Merge branch 'main' into lunny/fix_issue_comment_num

This commit is contained in:
silverwind 2024-04-23 21:35:03 +02:00 committed by GitHub
commit ee21b92588
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
224 changed files with 6448 additions and 5986 deletions

View File

@ -310,7 +310,7 @@ rules:
jquery/no-merge: [2]
jquery/no-param: [2]
jquery/no-parent: [0]
jquery/no-parents: [0]
jquery/no-parents: [2]
jquery/no-parse-html: [2]
jquery/no-prop: [2]
jquery/no-proxy: [2]
@ -319,8 +319,8 @@ rules:
jquery/no-show: [2]
jquery/no-size: [2]
jquery/no-sizzle: [2]
jquery/no-slide: [0]
jquery/no-submit: [0]
jquery/no-slide: [2]
jquery/no-submit: [2]
jquery/no-text: [0]
jquery/no-toggle: [2]
jquery/no-trigger: [0]
@ -458,7 +458,7 @@ rules:
no-jquery/no-other-utils: [2]
no-jquery/no-param: [2]
no-jquery/no-parent: [0]
no-jquery/no-parents: [0]
no-jquery/no-parents: [2]
no-jquery/no-parse-html-literal: [0]
no-jquery/no-parse-html: [2]
no-jquery/no-parse-json: [2]

View File

@ -38,6 +38,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json
- run: pip install poetry
- run: make deps-py
- run: make deps-frontend
@ -65,6 +67,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend
- run: make lint-swagger
@ -134,6 +138,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend
- run: make lint-frontend
- run: make checks-frontend
@ -181,6 +187,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend
- run: make lint-md
- run: make docs

View File

@ -24,6 +24,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend frontend deps-backend
- run: npx playwright install --with-deps
- run: make test-e2e-sqlite

View File

@ -25,6 +25,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend deps-backend
# xgo build
- run: make release

View File

@ -24,6 +24,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend deps-backend
# xgo build
- run: make release

View File

@ -26,6 +26,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend deps-backend
# xgo build
- run: make release

View File

@ -1,13 +1,14 @@
linters:
enable-all: false
disable-all: true
fast: false
enable:
- bidichk
# - deadcode # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- depguard
- dupl
- errcheck
- forbidigo
- gocritic
# - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- gofumpt
- gosimple
@ -17,20 +18,18 @@ linters:
- nolintlint
- revive
- staticcheck
# - structcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- stylecheck
- typecheck
- unconvert
- unused
# - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- wastedassign
enable-all: false
disable-all: true
fast: false
run:
timeout: 10m
output:
sort-results: true
linters-settings:
stylecheck:
checks: ["all", "-ST1005", "-ST1003"]
@ -47,27 +46,37 @@ linters-settings:
errorCode: 1
warningCode: 1
rules:
- name: atomic
- name: bare-return
- name: blank-imports
- name: constant-logical-expr
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: duplicated-imports
- name: empty-lines
- name: error-naming
- name: error-return
- name: error-strings
- name: error-naming
- name: errorf
- name: exported
- name: identical-branches
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: indent-error-flow
- name: modifies-value-receiver
- name: package-comments
- name: range
- name: receiver-naming
- name: redefines-builtin-id
- name: string-of-int
- name: superfluous-else
- name: time-naming
- name: unconditional-recursion
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: duplicated-imports
- name: modifies-value-receiver
- name: unreachable-code
- name: var-declaration
- name: var-naming
gofumpt:
extra-rules: true
depguard:
@ -93,8 +102,8 @@ issues:
max-issues-per-linter: 0
max-same-issues: 0
exclude-dirs: [node_modules, public, web_src]
exclude-case-sensitive: true
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gocyclo
@ -112,19 +121,19 @@ issues:
- path: cmd
linters:
- forbidigo
- linters:
- text: "webhook"
linters:
- dupl
text: "webhook"
- linters:
- text: "`ID' should not be capitalized"
linters:
- gocritic
text: "`ID' should not be capitalized"
- linters:
- text: "swagger"
linters:
- unused
- deadcode
text: "swagger"
- linters:
- text: "argument x is overwritten before first use"
linters:
- staticcheck
text: "argument x is overwritten before first use"
- text: "commentFormatting: put a space between `//` and comment text"
linters:
- gocritic

5223
CHANGELOG-archived.md Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -143,9 +143,9 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMAN
GO_DIRS := build cmd models modules routers services tests
WEB_DIRS := web_src/js web_src/css
ESLINT_FILES := web_src/js tools *.config.js tests/e2e
ESLINT_FILES := web_src/js tools *.js tests/e2e
STYLELINT_FILES := web_src/css web_src/js/components/*.vue
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.js *.md *.yml *.yaml *.toml))
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
GO_SOURCES := $(wildcard *.go)

File diff suppressed because one or more lines are too long

View File

@ -4,6 +4,7 @@
package cmd
import (
"errors"
"fmt"
"os"
"text/tabwriter"
@ -91,7 +92,7 @@ func runListAuth(c *cli.Context) error {
func runDeleteAuth(c *cli.Context) error {
if !c.IsSet("id") {
return fmt.Errorf("--id flag is missing")
return errors.New("--id flag is missing")
}
ctx, cancel := installSignals()

View File

@ -4,6 +4,7 @@
package cmd
import (
"errors"
"fmt"
"net/url"
@ -193,7 +194,7 @@ func runAddOauth(c *cli.Context) error {
func runUpdateOauth(c *cli.Context) error {
if !c.IsSet("id") {
return fmt.Errorf("--id flag is missing")
return errors.New("--id flag is missing")
}
ctx, cancel := installSignals()

View File

@ -5,7 +5,6 @@ package cmd
import (
"errors"
"fmt"
"strings"
auth_model "code.gitea.io/gitea/models/auth"
@ -166,7 +165,7 @@ func runAddSMTP(c *cli.Context) error {
func runUpdateSMTP(c *cli.Context) error {
if !c.IsSet("id") {
return fmt.Errorf("--id flag is missing")
return errors.New("--id flag is missing")
}
ctx, cancel := installSignals()

View File

@ -4,6 +4,7 @@
package cmd
import (
"errors"
"fmt"
"strings"
@ -42,7 +43,7 @@ var microcmdUserDelete = &cli.Command{
func runDeleteUser(c *cli.Context) error {
if !c.IsSet("id") && !c.IsSet("username") && !c.IsSet("email") {
return fmt.Errorf("You must provide the id, username or email of a user to delete")
return errors.New("You must provide the id, username or email of a user to delete")
}
ctx, cancel := installSignals()

View File

@ -4,6 +4,7 @@
package cmd
import (
"errors"
"fmt"
auth_model "code.gitea.io/gitea/models/auth"
@ -42,7 +43,7 @@ var microcmdUserGenerateAccessToken = &cli.Command{
func runGenerateAccessToken(c *cli.Context) error {
if !c.IsSet("username") {
return fmt.Errorf("You must provide a username to generate a token for")
return errors.New("You must provide a username to generate a token for")
}
ctx, cancel := installSignals()
@ -68,7 +69,7 @@ func runGenerateAccessToken(c *cli.Context) error {
return err
}
if exist {
return fmt.Errorf("access token name has been used already")
return errors.New("access token name has been used already")
}
// make sure the scopes are valid

View File

@ -87,6 +87,10 @@ var CmdDump = &cli.Command{
Name: "skip-index",
Usage: "Skip bleve index data",
},
&cli.BoolFlag{
Name: "skip-db",
Usage: "Skip database",
},
&cli.StringFlag{
Name: "type",
Usage: fmt.Sprintf(`Dump output format, default to "zip", supported types: %s`, strings.Join(dump.SupportedOutputTypes, ", ")),
@ -185,35 +189,41 @@ func runDump(ctx *cli.Context) error {
}
}
tmpDir := ctx.String("tempdir")
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
fatal("Path does not exist: %s", tmpDir)
}
dbDump, err := os.CreateTemp(tmpDir, "gitea-db.sql")
if err != nil {
fatal("Failed to create tmp file: %v", err)
}
defer func() {
_ = dbDump.Close()
if err := util.Remove(dbDump.Name()); err != nil {
log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err)
}
}()
targetDBType := ctx.String("database")
if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() {
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
if ctx.Bool("skip-db") {
// Ensure that we don't dump the database file that may reside in setting.AppDataPath or elsewhere.
dumper.GlobalExcludeAbsPath(setting.Database.Path)
log.Info("Skipping database")
} else {
log.Info("Dumping database...")
}
tmpDir := ctx.String("tempdir")
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
fatal("Path does not exist: %s", tmpDir)
}
if err := db.DumpDatabase(dbDump.Name(), targetDBType); err != nil {
fatal("Failed to dump database: %v", err)
}
dbDump, err := os.CreateTemp(tmpDir, "gitea-db.sql")
if err != nil {
fatal("Failed to create tmp file: %v", err)
}
defer func() {
_ = dbDump.Close()
if err := util.Remove(dbDump.Name()); err != nil {
log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err)
}
}()
if err = dumper.AddFile("gitea-db.sql", dbDump.Name()); err != nil {
fatal("Failed to include gitea-db.sql: %v", err)
targetDBType := ctx.String("database")
if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() {
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
} else {
log.Info("Dumping database...")
}
if err := db.DumpDatabase(dbDump.Name(), targetDBType); err != nil {
fatal("Failed to dump database: %v", err)
}
if err = dumper.AddFile("gitea-db.sql", dbDump.Name()); err != nil {
fatal("Failed to include gitea-db.sql: %v", err)
}
}
log.Info("Adding custom configuration file from %s", setting.CustomConf)

View File

@ -157,9 +157,9 @@ func runViewDo(c *cli.Context) error {
}
if len(matchedAssetFiles) == 0 {
return fmt.Errorf("no files matched the given pattern")
return errors.New("no files matched the given pattern")
} else if len(matchedAssetFiles) > 1 {
return fmt.Errorf("too many files matched the given pattern, try to be more specific")
return errors.New("too many files matched the given pattern, try to be more specific")
}
data, err := matchedAssetFiles[0].fs.ReadFile(matchedAssetFiles[0].name)
@ -180,7 +180,7 @@ func runExtractDo(c *cli.Context) error {
}
if c.NArg() == 0 {
return fmt.Errorf("a list of pattern of files to extract is mandatory (e.g. '**' for all)")
return errors.New("a list of pattern of files to extract is mandatory (e.g. '**' for all)")
}
destdir := "."

View File

@ -465,7 +465,7 @@ func hookPrintResult(output, isCreate bool, branch, url string) {
fmt.Fprintf(os.Stderr, " %s\n", url)
}
fmt.Fprintln(os.Stderr, "")
os.Stderr.Sync()
_ = os.Stderr.Sync()
}
func pushOptions() map[string]string {

View File

@ -4,6 +4,7 @@
package cmd
import (
"errors"
"fmt"
"os"
@ -249,7 +250,7 @@ func runAddFileLogger(c *cli.Context) error {
if c.IsSet("filename") {
vals["filename"] = c.String("filename")
} else {
return fmt.Errorf("filename must be set when creating a file logger")
return errors.New("filename must be set when creating a file logger")
}
if c.IsSet("rotate") {
vals["rotate"] = c.Bool("rotate")

View File

@ -1231,7 +1231,8 @@ LEVEL = Info
;DEFAULT_THEME = gitea-auto
;;
;; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`.
;THEMES = gitea-auto,gitea-light,gitea-dark
;; Leave it empty to allow users to select any theme from "{CustomPath}/public/assets/css/theme-*.css"
;THEMES =
;;
;; All available reactions users can choose on issues/prs and comments.
;; Values can be emoji alias (:smile:) or a unicode emoji.
@ -2377,22 +2378,6 @@ LEVEL = Info
;; Enable issue by repository metrics; default is false
;ENABLED_ISSUE_BY_REPOSITORY = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[task]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Task queue type, could be `channel` or `redis`.
;QUEUE_TYPE = channel
;;
;; Task queue length, available only when `QUEUE_TYPE` is `channel`.
;QUEUE_LENGTH = 1000
;;
;; Task queue connection string, available only when `QUEUE_TYPE` is `redis`.
;; If there is a password of redis, use `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for `redis-clsuter`.
;QUEUE_CONN_STR = "redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[migrations]

View File

@ -214,10 +214,9 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `SITEMAP_PAGING_NUM`: **20**: Number of items that are displayed in a single subsitemap.
- `GRAPH_MAX_COMMIT_NUM`: **100**: Number of maximum commits shown in the commit graph.
- `CODE_COMMENT_LINES`: **4**: Number of line of codes shown for a code comment.
- `DEFAULT_THEME`: **gitea-auto**: \[gitea-auto, gitea-light, gitea-dark\]: Set the default theme for the Gitea installation.
- `DEFAULT_THEME`: **gitea-auto**: Set the default theme for the Gitea installation, custom themes could be provided by "{CustomPath}/public/assets/css/theme-*.css".
- `SHOW_USER_EMAIL`: **true**: Whether the email of the user should be shown in the Explore Users page.
- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: All available themes. Allow users select personalized themes.
regardless of the value of `DEFAULT_THEME`.
- `THEMES`: **_empty_**: All available themes by "{CustomPath}/public/assets/css/theme-*.css". Allow users select personalized themes.
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB)
- `AMBIGUOUS_UNICODE_DETECTION`: **true**: Detect ambiguous unicode characters in file contents and show warnings on the UI
- `REACTIONS`: All available reactions users can choose on issues/prs and comments
@ -1198,14 +1197,6 @@ in this mapping or the filetype using heuristics.
- `DEFAULT_UI_LOCATION`: Default location of time on the UI, so that we can display correct user's time on UI. i.e. Asia/Shanghai
## Task (`task`)
Task queue configuration has been moved to `queue.task`. However, the below configuration values are kept for backwards compatibility:
- `QUEUE_TYPE`: **channel**: Task queue type, could be `channel` or `redis`.
- `QUEUE_LENGTH`: **1000**: Task queue length, available only when `QUEUE_TYPE` is `channel`.
- `QUEUE_CONN_STR`: **redis://127.0.0.1:6379/0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If redis needs a password, use `redis://123@127.0.0.1:6379/0` or `redis+cluster://123@127.0.0.1:6379/0`.
## Migrations (`migrations`)
- `MAX_ATTEMPTS`: **3**: Max attempts per http/https request on migrations.

View File

@ -212,10 +212,9 @@ menu:
- `SITEMAP_PAGING_NUM`: **20**: 在单个子SiteMap中显示的项数。
- `GRAPH_MAX_COMMIT_NUM`: **100**: 提交图中显示的最大commit数量。
- `CODE_COMMENT_LINES`: **4**: 在代码评论中能够显示的最大代码行数。
- `DEFAULT_THEME`: **gitea-auto**: \[gitea-auto, gitea-light, gitea-dark\]: 在Gitea安装时候设置的默认主题。
- `DEFAULT_THEME`: **gitea-auto**: 在Gitea安装时候设置的默认主题,自定义的主题可以通过 "{CustomPath}/public/assets/css/theme-*.css" 提供
- `SHOW_USER_EMAIL`: **true**: 用户的电子邮件是否应该显示在`Explore Users`页面中。
- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: 所有可用的主题。允许用户选择个性化的主题,
而不受DEFAULT_THEME 值的影响。
- `THEMES`: **_empty_**: 所有可用的主题(由 "{CustomPath}/public/assets/css/theme-*.css" 提供)。允许用户选择个性化的主题,
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: 能够显示文件的最大大小默认为8MiB
- `REACTIONS`: 用户可以在问题Issue、Pull RequestPR以及评论中选择的所有可选的反应。
这些值可以是表情符号别名(例如::smile:或Unicode表情符号。
@ -1128,15 +1127,6 @@ ALLOW_DATA_URI_IMAGES = true
- `DEFAULT_UI_LOCATION`:在 UI 上的默认时间位置,以便我们可以在 UI 上显示正确的用户时间。例如Asia/Shanghai
## 任务 (`task`)
任务队列配置已移动到 `queue.task`。然而,以下配置值仍保留以确保向后兼容:
- `QUEUE_TYPE`**channel**:任务队列类型,可以是 `channel``redis`
- `QUEUE_LENGTH`**1000**:任务队列长度,仅在 `QUEUE_TYPE``channel` 时可用。
- `QUEUE_CONN_STR`**redis://127.0.0.1:6379/0**:任务队列连接字符串,仅在 `QUEUE_TYPE``redis` 时可用。
如果 redis 需要密码,使用 `redis://123@127.0.0.1:6379/0``redis+cluster://123@127.0.0.1:6379/0`
## 迁移 (`migrations`)
- `MAX_ATTEMPTS`**3**:每次 http/https 请求的最大尝试次数(用于迁移)。

View File

@ -381,7 +381,7 @@ To make a custom theme available to all users:
1. Add a CSS file to `$GITEA_CUSTOM/public/assets/css/theme-<theme-name>.css`.
The value of `$GITEA_CUSTOM` of your instance can be queried by calling `gitea help` and looking up the value of "CustomPath".
2. Add `<theme-name>` to the comma-separated list of setting `THEMES` in `app.ini`
2. Add `<theme-name>` to the comma-separated list of setting `THEMES` in `app.ini`, or leave `THEMES` empty to allow all themes.
Community themes are listed in [gitea/awesome-gitea#themes](https://gitea.com/gitea/awesome-gitea#themes).

View File

@ -178,17 +178,6 @@ At some point, a customer or third party needs access to a specific repo and onl
Use [Fail2Ban](administration/fail2ban-setup.md) to monitor and stop automated login attempts or other malicious behavior based on log patterns
## How to add/use custom themes
Gitea supports three official themes right now, `gitea-light`, `gitea-dark`, and `gitea-auto` (automatically switches between the previous two depending on operating system settings).
To add your own theme, currently the only way is to provide a complete theme (not just color overrides)
As an example, let's say our theme is `arc-blue` (this is a real theme, and can be found [in this issue](https://github.com/go-gitea/gitea/issues/6011))
Name the `.css` file `theme-arc-blue.css` and add it to your custom folder in `custom/public/assets/css`
Allow users to use it by adding `arc-blue` to the list of `THEMES` in your `app.ini`
## SSHD vs built-in SSH
SSHD is the built-in SSH server on most Unix systems.

View File

@ -182,17 +182,6 @@ Gitea不提供内置的Pages服务器。您需要一个专用的域名来提供
使用 [Fail2Ban](administration/fail2ban-setup.md) 监视并阻止基于日志模式的自动登录尝试或其他恶意行为。
## 如何添加/使用自定义主题
Gitea 目前支持三个官方主题,分别是 `gitea-light`、`gitea-dark` 和 `gitea-auto`(根据操作系统设置自动切换前两个主题)。
要添加自己的主题,目前唯一的方法是提供一个完整的主题(不仅仅是颜色覆盖)。
假设我们的主题是 `arc-blue`(这是一个真实的主题,可以在[此问题](https://github.com/go-gitea/gitea/issues/6011)中找到)
将`.css`文件命名为`theme-arc-blue.css`并将其添加到`custom/public/assets/css`文件夹中
通过将`arc-blue`添加到`app.ini`中的`THEMES`列表中,允许用户使用该主题
## SSHD vs 内建SSH
SSHD是大多数Unix系统上内建的SSH服务器。

3
go.mod
View File

@ -16,7 +16,6 @@ require (
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
github.com/NYTimes/gziphandler v1.1.1
github.com/PuerkitoBio/goquery v1.9.1
github.com/alecthomas/chroma/v2 v2.13.0
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
@ -67,7 +66,7 @@ require (
github.com/json-iterator/go v1.1.12
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
github.com/klauspost/compress v1.17.7
github.com/klauspost/compress v1.17.8
github.com/klauspost/cpuid/v2 v2.2.7
github.com/lib/pq v1.10.9
github.com/markbates/goth v1.79.0

6
go.sum
View File

@ -70,8 +70,6 @@ github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBa
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI=
@ -500,8 +498,8 @@ github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=

View File

@ -98,13 +98,10 @@ func (run *ActionRun) LoadAttributes(ctx context.Context) error {
return nil
}
if run.Repo == nil {
repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID)
if err != nil {
return err
}
run.Repo = repo
if err := run.LoadRepo(ctx); err != nil {
return err
}
if err := run.Repo.LoadAttributes(ctx); err != nil {
return err
}
@ -120,6 +117,19 @@ func (run *ActionRun) LoadAttributes(ctx context.Context) error {
return nil
}
func (run *ActionRun) LoadRepo(ctx context.Context) error {
if run == nil || run.Repo != nil {
return nil
}
repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID)
if err != nil {
return err
}
run.Repo = repo
return nil
}
func (run *ActionRun) Duration() time.Duration {
return calculateDuration(run.Started, run.Stopped, run.Status) + run.PreviousDuration
}

View File

@ -270,7 +270,7 @@ func CountRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
// Only affect action runners were a owner ID is set, as actions runners
// could also be created on a repository.
return db.GetEngine(ctx).Table("action_runner").
Join("LEFT", "user", "`action_runner`.owner_id = `user`.id").
Join("LEFT", "`user`", "`action_runner`.owner_id = `user`.id").
Where("`action_runner`.owner_id != ?", 0).
And(builder.IsNull{"`user`.id"}).
Count(new(ActionRunner))
@ -279,7 +279,7 @@ func CountRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
func FixRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
subQuery := builder.Select("`action_runner`.id").
From("`action_runner`").
Join("LEFT", "user", "`action_runner`.owner_id = `user`.id").
Join("LEFT", "`user`", "`action_runner`.owner_id = `user`.id").
Where(builder.Neq{"`action_runner`.owner_id": 0}).
And(builder.IsNull{"`user`.id"})
b := builder.Delete(builder.In("id", subQuery)).From("`action_runner`")
@ -289,3 +289,25 @@ func FixRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
}
return res.RowsAffected()
}
func CountRunnersWithoutBelongingRepo(ctx context.Context) (int64, error) {
return db.GetEngine(ctx).Table("action_runner").
Join("LEFT", "`repository`", "`action_runner`.repo_id = `repository`.id").
Where("`action_runner`.repo_id != ?", 0).
And(builder.IsNull{"`repository`.id"}).
Count(new(ActionRunner))
}
func FixRunnersWithoutBelongingRepo(ctx context.Context) (int64, error) {
subQuery := builder.Select("`action_runner`.id").
From("`action_runner`").
Join("LEFT", "`repository`", "`action_runner`.repo_id = `repository`.id").
Where(builder.Neq{"`action_runner`.repo_id": 0}).
And(builder.IsNull{"`repository`.id"})
b := builder.Delete(builder.In("id", subQuery)).From("`action_runner`")
res, err := db.GetEngine(ctx).Exec(b)
if err != nil {
return 0, err
}
return res.RowsAffected()
}

View File

@ -92,6 +92,11 @@ func DeleteVariable(ctx context.Context, id int64) error {
func GetVariablesOfRun(ctx context.Context, run *ActionRun) (map[string]string, error) {
variables := map[string]string{}
if err := run.LoadRepo(ctx); err != nil {
log.Error("LoadRepo: %v", err)
return nil, err
}
// Global
globalVariables, err := db.Find[ActionVariable](ctx, FindVariablesOpts{})
if err != nil {

View File

@ -110,7 +110,6 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
Reason: "gpg.error.no_committer_account",
}
}
}
}

View File

@ -8,6 +8,7 @@ import (
"crypto/sha256"
"encoding/base32"
"encoding/base64"
"errors"
"fmt"
"net"
"net/url"
@ -294,7 +295,7 @@ func UpdateOAuth2Application(ctx context.Context, opts UpdateOAuth2ApplicationOp
return nil, err
}
if app.UID != opts.UserID {
return nil, fmt.Errorf("UID mismatch")
return nil, errors.New("UID mismatch")
}
builtinApps := BuiltinApplications()
if _, builtin := builtinApps[app.ClientID]; builtin {

View File

@ -13,8 +13,6 @@ import (
"github.com/stretchr/testify/assert"
)
//////////////////// Application
func TestOAuth2Application_GenerateClientSecret(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})

View File

@ -228,7 +228,6 @@ func NamesToBean(names ...string) ([]any, error) {
// Need to map provided names to beans...
beanMap := make(map[string]any)
for _, bean := range tables {
beanMap[strings.ToLower(reflect.Indirect(reflect.ValueOf(bean)).Type().Name())] = bean
beanMap[strings.ToLower(x.TableName(bean))] = bean
beanMap[strings.ToLower(x.TableName(bean, true))] = bean

View File

@ -5,7 +5,7 @@ package git
import (
"context"
"fmt"
"errors"
"strings"
"time"
@ -148,7 +148,7 @@ func DeleteLFSLockByID(ctx context.Context, id int64, repo *repo_model.Repositor
}
if !force && u.ID != lock.OwnerID {
return nil, fmt.Errorf("user doesn't own lock and force flag is not set")
return nil, errors.New("user doesn't own lock and force flag is not set")
}
if _, err := db.GetEngine(dbCtx).ID(id).Delete(new(LFSLock)); err != nil {

View File

@ -345,11 +345,9 @@ func CreateReview(ctx context.Context, opts CreateReviewOptions) (*Review, error
return nil, err
}
}
} else if opts.ReviewerTeam != nil {
review.Type = ReviewTypeRequest
review.ReviewerTeamID = opts.ReviewerTeam.ID
} else {
return nil, fmt.Errorf("provide either reviewer or reviewer team")
}

View File

@ -177,7 +177,6 @@ func RecreateTable(sess *xorm.Session, bean any) error {
log.Error("Unable to recreate uniques on table %s. Error: %v", tableName, err)
return err
}
case setting.Database.Type.IsMySQL():
// MySQL will drop all the constraints on the old table
if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
@ -228,7 +227,6 @@ func RecreateTable(sess *xorm.Session, bean any) error {
return err
}
sequenceMap[sequence] = sequenceData
}
// CASCADE causes postgres to drop all the constraints on the old table
@ -293,9 +291,7 @@ func RecreateTable(sess *xorm.Session, bean any) error {
return err
}
}
}
case setting.Database.Type.IsMSSQL():
// MSSQL will drop all the constraints on the old table
if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
@ -308,7 +304,6 @@ func RecreateTable(sess *xorm.Session, bean any) error {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
default:
log.Fatal("Unrecognized DB")
}

View File

@ -584,6 +584,8 @@ var migrations = []Migration{
NewMigration("Add missing field of commit status summary table", v1_23.AddCommitStatusSummary2),
// v297 -> v298
NewMigration("Add everyone_access_mode for repo_unit", v1_23.AddRepoUnitEveryoneAccessMode),
// v298 -> v299
NewMigration("Drop wrongly created table o_auth2_application", v1_23.DropWronglyCreatedTable),
}
// GetCurrentDBVersion returns the current db version

View File

@ -262,7 +262,6 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
for _, u := range units {
var found bool
for _, team := range teams {
var teamU []*TeamUnit
var unitEnabled bool
err = sess.Where("team_id = ?", team.ID).Find(&teamU)
@ -331,7 +330,6 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
}
if !protectedBranch.EnableApprovalsWhitelist {
perm, err := getUserRepoPermission(sess, baseRepo, reviewer)
if err != nil {
return false, err

View File

@ -9,9 +9,9 @@ import (
// AddConfidentialColumnToOAuth2ApplicationTable: add ConfidentialClient column, setting existing rows to true
func AddConfidentialClientColumnToOAuth2ApplicationTable(x *xorm.Engine) error {
type OAuth2Application struct {
type oauth2Application struct {
ID int64
ConfidentialClient bool `xorm:"NOT NULL DEFAULT TRUE"`
}
return x.Sync(new(OAuth2Application))
return x.Sync(new(oauth2Application))
}

View File

@ -13,12 +13,12 @@ import (
func Test_AddConfidentialClientColumnToOAuth2ApplicationTable(t *testing.T) {
// premigration
type OAuth2Application struct {
type oauth2Application struct {
ID int64
}
// Prepare and load the testing database
x, deferable := base.PrepareTestEnv(t, 0, new(OAuth2Application))
x, deferable := base.PrepareTestEnv(t, 0, new(oauth2Application))
defer deferable()
if x == nil || t.Failed() {
return
@ -36,7 +36,7 @@ func Test_AddConfidentialClientColumnToOAuth2ApplicationTable(t *testing.T) {
}
got := []ExpectedOAuth2Application{}
if err := x.Table("o_auth2_application").Select("id, confidential_client").Find(&got); !assert.NoError(t, err) {
if err := x.Table("oauth2_application").Select("id, confidential_client").Find(&got); !assert.NoError(t, err) {
return
}

View File

@ -104,7 +104,7 @@ func ChangeContainerMetadataMultiArch(x *xorm.Engine) error {
// Convert to new metadata format
new := &MetadataNew{
newMetadata := &MetadataNew{
Type: old.Type,
IsTagged: old.IsTagged,
Platform: old.Platform,
@ -119,7 +119,7 @@ func ChangeContainerMetadataMultiArch(x *xorm.Engine) error {
Manifests: manifests,
}
metadataJSON, err := json.Marshal(new)
metadataJSON, err := json.Marshal(newMetadata)
if err != nil {
return err
}

View File

@ -0,0 +1,10 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_23 //nolint
import "xorm.io/xorm"
func DropWronglyCreatedTable(x *xorm.Engine) error {
return x.DropTables("o_auth2_application")
}

View File

@ -61,7 +61,6 @@ func AddScratchHash(x *xorm.Engine) error {
if _, err := sess.ID(tfa.ID).Cols("scratch_salt, scratch_hash").Update(tfa); err != nil {
return fmt.Errorf("couldn't add in scratch_hash and scratch_salt: %w", err)
}
}
}

View File

@ -81,7 +81,6 @@ func HashAppToken(x *xorm.Engine) error {
if _, err := sess.ID(token.ID).Cols("token_hash, token_salt, token_last_eight, sha1").Update(token); err != nil {
return fmt.Errorf("couldn't add in sha1, token_hash, token_salt and token_last_eight: %w", err)
}
}
}

View File

@ -118,7 +118,7 @@ func removeAllRepositories(ctx context.Context, t *organization.Team) (err error
// Remove watches from all users and now unaccessible repos
for _, user := range t.Members {
has, err := access_model.HasAccess(ctx, user.ID, repo)
has, err := access_model.HasAnyUnitAccess(ctx, user.ID, repo)
if err != nil {
return err
} else if has {
@ -544,7 +544,7 @@ func ReconsiderRepoIssuesAssignee(ctx context.Context, repo *repo_model.Reposito
}
func ReconsiderWatches(ctx context.Context, repo *repo_model.Repository, user *user_model.User) error {
if has, err := access_model.HasAccess(ctx, user.ID, repo); err != nil || has {
if has, err := access_model.HasAnyUnitAccess(ctx, user.ID, repo); err != nil || has {
return err
}
if err := repo_model.WatchRepo(ctx, user, repo, false); err != nil {

View File

@ -226,9 +226,8 @@ func GetTeamIDsByNames(ctx context.Context, orgID int64, names []string, ignoreN
if err != nil {
if ignoreNonExistent {
continue
} else {
return nil, err
}
return nil, err
}
ids = append(ids, u.ID)
}

View File

@ -287,9 +287,10 @@ func (opts *PackageSearchOptions) configureOrderBy(e db.Engine) {
// SearchVersions gets all versions of packages matching the search options
func SearchVersions(ctx context.Context, opts *PackageSearchOptions) ([]*PackageVersion, int64, error) {
sess := db.GetEngine(ctx).
Where(opts.ToConds()).
Select("package_version.*").
Table("package_version").
Join("INNER", "package", "package.id = package_version.package_id")
Join("INNER", "package", "package.id = package_version.package_id").
Where(opts.ToConds())
opts.configureOrderBy(sess)
@ -304,19 +305,18 @@ func SearchVersions(ctx context.Context, opts *PackageSearchOptions) ([]*Package
// SearchLatestVersions gets the latest version of every package matching the search options
func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*PackageVersion, int64, error) {
cond := opts.ToConds().
And(builder.Expr("pv2.id IS NULL"))
joinCond := builder.Expr("package_version.package_id = pv2.package_id AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))")
if opts.IsInternal.Has() {
joinCond = joinCond.And(builder.Eq{"pv2.is_internal": opts.IsInternal.Value()})
}
in := builder.
Select("MAX(package_version.id)").
From("package_version").
InnerJoin("package", "package.id = package_version.package_id").
Where(opts.ToConds()).
GroupBy("package_version.package_id")
sess := db.GetEngine(ctx).
Select("package_version.*").
Table("package_version").
Join("LEFT", "package_version pv2", joinCond).
Join("INNER", "package", "package.id = package_version.package_id").
Where(cond)
Where(builder.In("package_version.id", in))
opts.configureOrderBy(sess)

View File

@ -79,17 +79,17 @@ func TestHasAccess(t *testing.T) {
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
assert.True(t, repo2.IsPrivate)
has, err := access_model.HasAccess(db.DefaultContext, user1.ID, repo1)
has, err := access_model.HasAnyUnitAccess(db.DefaultContext, user1.ID, repo1)
assert.NoError(t, err)
assert.True(t, has)
_, err = access_model.HasAccess(db.DefaultContext, user1.ID, repo2)
_, err = access_model.HasAnyUnitAccess(db.DefaultContext, user1.ID, repo2)
assert.NoError(t, err)
_, err = access_model.HasAccess(db.DefaultContext, user2.ID, repo1)
_, err = access_model.HasAnyUnitAccess(db.DefaultContext, user2.ID, repo1)
assert.NoError(t, err)
_, err = access_model.HasAccess(db.DefaultContext, user2.ID, repo2)
_, err = access_model.HasAnyUnitAccess(db.DefaultContext, user2.ID, repo2)
assert.NoError(t, err)
}

View File

@ -24,6 +24,8 @@ type Permission struct {
units []*repo_model.RepoUnit
unitsMode map[unit.Type]perm_model.AccessMode
everyoneAccessMode map[unit.Type]perm_model.AccessMode
}
// IsOwner returns true if current user is the owner of repository.
@ -36,9 +38,24 @@ func (p *Permission) IsAdmin() bool {
return p.AccessMode >= perm_model.AccessModeAdmin
}
// HasAccess returns true if the current user might have at least read access to any unit of this repository
func (p *Permission) HasAccess() bool {
return len(p.unitsMode) > 0 || p.AccessMode >= perm_model.AccessModeRead
// HasAnyUnitAccess returns true if the user might have at least one access mode to any unit of this repository.
// It doesn't count the "everyone access mode".
func (p *Permission) HasAnyUnitAccess() bool {
for _, v := range p.unitsMode {
if v >= perm_model.AccessModeRead {
return true
}
}
return p.AccessMode >= perm_model.AccessModeRead
}
func (p *Permission) HasAnyUnitAccessOrEveryoneAccess() bool {
for _, v := range p.everyoneAccessMode {
if v >= perm_model.AccessModeRead {
return true
}
}
return p.HasAnyUnitAccess()
}
// HasUnits returns true if the permission contains attached units
@ -56,16 +73,16 @@ func (p *Permission) GetFirstUnitRepoID() int64 {
}
// UnitAccessMode returns current user access mode to the specify unit of the repository
// It also considers "everyone access mode"
func (p *Permission) UnitAccessMode(unitType unit.Type) perm_model.AccessMode {
if p.unitsMode != nil {
// if the units map contains the access mode, use it, but admin/owner mode could override it
if m, ok := p.unitsMode[unitType]; ok {
return util.Iif(p.AccessMode >= perm_model.AccessModeAdmin, p.AccessMode, m)
}
// if the units map contains the access mode, use it, but admin/owner mode could override it
if m, ok := p.unitsMode[unitType]; ok {
return util.Iif(p.AccessMode >= perm_model.AccessModeAdmin, p.AccessMode, m)
}
// if the units map does not contain the access mode, return the default access mode if the unit exists
unitDefaultAccessMode := max(p.AccessMode, p.everyoneAccessMode[unitType])
hasUnit := slices.ContainsFunc(p.units, func(u *repo_model.RepoUnit) bool { return u.Type == unitType })
return util.Iif(hasUnit, p.AccessMode, perm_model.AccessModeNone)
return util.Iif(hasUnit, unitDefaultAccessMode, perm_model.AccessModeNone)
}
func (p *Permission) SetUnitsWithDefaultAccessMode(units []*repo_model.RepoUnit, mode perm_model.AccessMode) {
@ -159,14 +176,15 @@ func (p *Permission) LogString() string {
}
func applyEveryoneRepoPermission(user *user_model.User, perm *Permission) {
if user != nil && user.ID > 0 {
for _, u := range perm.units {
if perm.unitsMode == nil {
perm.unitsMode = make(map[unit.Type]perm_model.AccessMode)
}
if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.unitsMode[u.Type] {
perm.unitsMode[u.Type] = u.EveryoneAccessMode
if user == nil || user.ID <= 0 {
return
}
for _, u := range perm.units {
if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.everyoneAccessMode[u.Type] {
if perm.everyoneAccessMode == nil {
perm.everyoneAccessMode = make(map[unit.Type]perm_model.AccessMode)
}
perm.everyoneAccessMode[u.Type] = u.EveryoneAccessMode
}
}
}
@ -373,8 +391,8 @@ func CanBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model.
perm.CanAccessAny(perm_model.AccessModeRead, unit.TypePullRequests), nil
}
// HasAccess returns true if user has access to repo
func HasAccess(ctx context.Context, userID int64, repo *repo_model.Repository) (bool, error) {
// HasAnyUnitAccess see the comment of "perm.HasAnyUnitAccess"
func HasAnyUnitAccess(ctx context.Context, userID int64, repo *repo_model.Repository) (bool, error) {
var user *user_model.User
var err error
if userID > 0 {
@ -387,7 +405,7 @@ func HasAccess(ctx context.Context, userID int64, repo *repo_model.Repository) (
if err != nil {
return false, err
}
return perm.HasAccess(), nil
return perm.HasAnyUnitAccess(), nil
}
// getUsersWithAccessMode returns users that have at least given access mode to the repository.

View File

@ -14,16 +14,54 @@ import (
"github.com/stretchr/testify/assert"
)
func TestHasAnyUnitAccess(t *testing.T) {
perm := Permission{}
assert.False(t, perm.HasAnyUnitAccess())
perm = Permission{
units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}},
}
assert.False(t, perm.HasAnyUnitAccess())
assert.False(t, perm.HasAnyUnitAccessOrEveryoneAccess())
perm = Permission{
units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}},
everyoneAccessMode: map[unit.Type]perm_model.AccessMode{unit.TypeIssues: perm_model.AccessModeRead},
}
assert.False(t, perm.HasAnyUnitAccess())
assert.True(t, perm.HasAnyUnitAccessOrEveryoneAccess())
perm = Permission{
AccessMode: perm_model.AccessModeRead,
units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}},
}
assert.True(t, perm.HasAnyUnitAccess())
perm = Permission{
unitsMode: map[unit.Type]perm_model.AccessMode{unit.TypeWiki: perm_model.AccessModeRead},
}
assert.True(t, perm.HasAnyUnitAccess())
}
func TestApplyEveryoneRepoPermission(t *testing.T) {
perm := Permission{
AccessMode: perm_model.AccessModeNone,
units: []*repo_model.RepoUnit{
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeNone},
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
},
}
applyEveryoneRepoPermission(nil, &perm)
assert.False(t, perm.CanRead(unit.TypeWiki))
perm = Permission{
AccessMode: perm_model.AccessModeNone,
units: []*repo_model.RepoUnit{
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
},
}
applyEveryoneRepoPermission(&user_model.User{ID: 0}, &perm)
assert.False(t, perm.CanRead(unit.TypeWiki))
perm = Permission{
AccessMode: perm_model.AccessModeNone,
units: []*repo_model.RepoUnit{
@ -40,8 +78,8 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
},
}
applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm)
assert.True(t, perm.CanRead(unit.TypeWiki))
assert.False(t, perm.CanWrite(unit.TypeWiki)) // because there is no unit mode, so the everyone-mode is used as the unit's access mode
// it should work the same as "EveryoneAccessMode: none" because the default AccessMode should be applied to units
assert.True(t, perm.CanWrite(unit.TypeWiki))
perm = Permission{
units: []*repo_model.RepoUnit{

View File

@ -110,13 +110,11 @@ func createBoardsForProjectsType(ctx context.Context, project *Project) error {
var items []string
switch project.BoardType {
case BoardTypeBugTriage:
items = setting.Project.ProjectBoardBugTriageType
case BoardTypeBasicKanban:
items = setting.Project.ProjectBoardBasicKanbanType
case BoardTypeNone:
fallthrough
default:

View File

@ -170,7 +170,6 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64)
// the owner of a private repo needs to be explicitly added.
cond = cond.Or(builder.Eq{"`user`.id": repo.Owner.ID})
}
} else {
// This is a "public" repository:
// Any user that has read access, is a watcher or organization member can be requested to review

View File

@ -5,6 +5,7 @@ package models
import (
"context"
"errors"
"fmt"
"code.gitea.io/gitea/models/db"
@ -147,7 +148,7 @@ func DeleteRepositoryTransfer(ctx context.Context, repoID int64) error {
func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
switch status {
case repo_model.RepositoryBeingMigrated:
return fmt.Errorf("repo is not ready, currently migrating")
return errors.New("repo is not ready, currently migrating")
case repo_model.RepositoryPendingTransfer:
return ErrRepoTransferInProgress{}
}

View File

@ -988,9 +988,8 @@ func GetUserIDsByNames(ctx context.Context, names []string, ignoreNonExistent bo
if err != nil {
if ignoreNonExistent {
continue
} else {
return nil, err
}
return nil, err
}
ids = append(ids, u.ID)
}

View File

@ -63,16 +63,16 @@ func NewComplexity() {
func setupComplexity(values []string) {
if len(values) != 1 || values[0] != "off" {
for _, val := range values {
if complex, ok := charComplexities[val]; ok {
validChars += complex.ValidChars
requiredList = append(requiredList, complex)
if complexity, ok := charComplexities[val]; ok {
validChars += complexity.ValidChars
requiredList = append(requiredList, complexity)
}
}
if len(requiredList) == 0 {
// No valid character classes found; use all classes as default
for _, complex := range charComplexities {
validChars += complex.ValidChars
requiredList = append(requiredList, complex)
for _, complexity := range charComplexities {
validChars += complexity.ValidChars
requiredList = append(requiredList, complexity)
}
}
}

View File

@ -307,10 +307,10 @@ func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBu
// Deal with the binary hash
idx = 0
len := objectFormat.FullLength() / 2
for idx < len {
length := objectFormat.FullLength() / 2
for idx < length {
var read int
read, err = rd.Read(shaBuf[idx:len])
read, err = rd.Read(shaBuf[idx:length])
n += read
if err != nil {
return mode, fname, sha, n, err

View File

@ -468,7 +468,7 @@ func parseCommitFileStatus(fileStatus *CommitFileStatus, stdout io.Reader) {
_, _ = rd.Discard(1)
}
for {
modifier, err := rd.ReadSlice('\x00')
modifier, err := rd.ReadString('\x00')
if err != nil {
if err != io.EOF {
log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err)

View File

@ -49,9 +49,8 @@ readLoop:
if len(line) > 0 && line[0] == ' ' {
_, _ = signatureSB.Write(line[1:])
continue
} else {
pgpsig = false
}
pgpsig = false
}
if !message {

View File

@ -232,7 +232,6 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
errChan <- err
break
}
}
}()

View File

@ -251,18 +251,18 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
return nil, err
}
len := objectFormat.FullLength()
length := objectFormat.FullLength()
commits := []*Commit{}
shaline := make([]byte, len+1)
shaline := make([]byte, length+1)
for {
n, err := io.ReadFull(stdoutReader, shaline)
if err != nil || n < len {
if err != nil || n < length {
if err == io.EOF {
err = nil
}
return commits, err
}
objectID, err := NewIDFromString(string(shaline[0:len]))
objectID, err := NewIDFromString(string(shaline[0:length]))
if err != nil {
return nil, err
}

View File

@ -64,7 +64,6 @@ func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string {
// ex: git@try.gitea.io:go-gitea/gitea
match := scpSyntax.FindAllStringSubmatch(refURI, -1)
if len(match) > 0 {
m := match[0]
refHostname := m[2]
pth := m[3]

View File

@ -191,7 +191,6 @@ func (b *Indexer) addDelete(filename string, repo *repo_model.Repository, batch
func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *internal.RepoChanges) error {
batch := inner_bleve.NewFlushingBatch(b.inner.Indexer, maxBatchSize)
if len(changes.Updates) > 0 {
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil {
log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err)
@ -335,7 +334,6 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
if result, err = b.inner.Indexer.Search(facetRequest); err != nil {
return 0, nil, nil, err
}
}
languagesFacet := result.Facets["languages"]
for _, term := range languagesFacet.Terms.Terms() {

View File

@ -68,7 +68,7 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
searchOpt.Paginator = opts.Paginator
switch opts.SortType {
case "":
case "", "latest":
searchOpt.SortBy = SortByCreatedDesc
case "oldest":
searchOpt.SortBy = SortByCreatedAsc
@ -86,7 +86,7 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
searchOpt.SortBy = SortByDeadlineDesc
case "priority", "priorityrepo", "project-column-sorting":
// Unsupported sort type for search
searchOpt.SortBy = SortByUpdatedDesc
fallthrough
default:
searchOpt.SortBy = SortByUpdatedDesc
}

View File

@ -145,7 +145,6 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
query := elastic.NewBoolQuery()
if options.Keyword != "" {
searchType := esMultiMatchTypePhrasePrefix
if options.IsFuzzyKeyword {
searchType = esMultiMatchTypeBestFields

View File

@ -125,7 +125,6 @@ func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, ms
if mode.Colorize {
buf = append(buf, resetBytes...)
}
}
if flags&(Lshortfile|Llongfile) != 0 {
if mode.Colorize {

View File

@ -466,7 +466,6 @@ func TestColorPreview(t *testing.T) {
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase)
}
negativeTests := []string{
@ -549,7 +548,6 @@ func TestMathBlock(t *testing.T) {
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase)
}
}

View File

@ -147,35 +147,35 @@ func (e *MarshalEncoder) marshalIntInternal(i int64) error {
return e.w.WriteByte(byte(i - 5))
}
var len int
var length int
if 122 < i && i <= 0xff {
len = 1
length = 1
} else if 0xff < i && i <= 0xffff {
len = 2
length = 2
} else if 0xffff < i && i <= 0xffffff {
len = 3
length = 3
} else if 0xffffff < i && i <= 0x3fffffff {
len = 4
length = 4
} else if -0x100 <= i && i < -123 {
len = -1
length = -1
} else if -0x10000 <= i && i < -0x100 {
len = -2
length = -2
} else if -0x1000000 <= i && i < -0x100000 {
len = -3
length = -3
} else if -0x40000000 <= i && i < -0x1000000 {
len = -4
length = -4
} else {
return ErrInvalidIntRange
}
if err := e.w.WriteByte(byte(len)); err != nil {
if err := e.w.WriteByte(byte(length)); err != nil {
return err
}
if len < 0 {
len = -len
if length < 0 {
length = -length
}
for c := 0; c < len; c++ {
for c := 0; c < length; c++ {
if err := e.w.WriteByte(byte(i >> uint(8*c) & 0xff)); err != nil {
return err
}
@ -244,13 +244,13 @@ func (e *MarshalEncoder) marshalArray(arr reflect.Value) error {
return err
}
len := arr.Len()
length := arr.Len()
if err := e.marshalIntInternal(int64(len)); err != nil {
if err := e.marshalIntInternal(int64(length)); err != nil {
return err
}
for i := 0; i < len; i++ {
for i := 0; i < length; i++ {
if err := e.marshal(arr.Index(i).Interface()); err != nil {
return err
}

View File

@ -339,7 +339,6 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int
}
sort.Slice(processes, after(processes))
if !flat {
var sortChildren func(process *Process)
sortChildren = func(process *Process) {

View File

@ -8,7 +8,7 @@ import (
"time"
)
const (
var (
backoffBegin = 50 * time.Millisecond
backoffUpper = 2 * time.Second
)
@ -18,6 +18,14 @@ type (
backoffFuncErr func() (retry bool, err error)
)
func mockBackoffDuration(d time.Duration) func() {
oldBegin, oldUpper := backoffBegin, backoffUpper
backoffBegin, backoffUpper = d, d
return func() {
backoffBegin, backoffUpper = oldBegin, oldUpper
}
}
func backoffRetErr[T any](ctx context.Context, begin, upper time.Duration, end <-chan time.Time, fn backoffFuncRetErr[T]) (ret T, err error) {
d := begin
for {

View File

@ -63,6 +63,8 @@ func (q *WorkerPoolQueue[T]) doDispatchBatchToWorker(wg *workerGroup[T], flushCh
// TODO: the logic could be improved in the future, to avoid a data-race between "doStartNewWorker" and "workerNum"
// The root problem is that if we skip "doStartNewWorker" here, the "workerNum" might be decreased by other workers later
// So ideally, it should check whether there are enough workers by some approaches, and start new workers if necessary.
// This data-race is not serious, as long as a new worker will be started soon to make sure there are enough workers,
// so no need to hugely refactor at the moment.
q.workerNumMu.Lock()
noWorker := q.workerNum == 0
if full || noWorker {
@ -136,6 +138,14 @@ func (q *WorkerPoolQueue[T]) basePushForShutdown(items ...T) bool {
return true
}
func resetIdleTicker(t *time.Ticker, dur time.Duration) {
t.Reset(dur)
select {
case <-t.C:
default:
}
}
// doStartNewWorker starts a new worker for the queue, the worker reads from worker's channel and handles the items.
func (q *WorkerPoolQueue[T]) doStartNewWorker(wp *workerGroup[T]) {
wp.wg.Add(1)
@ -146,8 +156,6 @@ func (q *WorkerPoolQueue[T]) doStartNewWorker(wp *workerGroup[T]) {
log.Debug("Queue %q starts new worker", q.GetName())
defer log.Debug("Queue %q stops idle worker", q.GetName())
atomic.AddInt32(&q.workerStartedCounter, 1) // Only increase counter, used for debugging
t := time.NewTicker(workerIdleDuration)
defer t.Stop()
@ -169,11 +177,7 @@ func (q *WorkerPoolQueue[T]) doStartNewWorker(wp *workerGroup[T]) {
}
q.doWorkerHandle(batch)
// reset the idle ticker, and drain the tick after reset in case a tick is already triggered
t.Reset(workerIdleDuration)
select {
case <-t.C:
default:
}
resetIdleTicker(t, workerIdleDuration) // key code for TestWorkerPoolQueueWorkerIdleReset
case <-t.C:
q.workerNumMu.Lock()
keepWorking = q.workerNum <= 1 // keep the last worker running

View File

@ -40,8 +40,6 @@ type WorkerPoolQueue[T any] struct {
workerMaxNum int
workerActiveNum int
workerNumMu sync.Mutex
workerStartedCounter int32
}
type flushType chan struct{}

View File

@ -5,8 +5,10 @@ package queue
import (
"context"
"slices"
"strconv"
"sync"
"sync/atomic"
"testing"
"time"
@ -250,22 +252,34 @@ func TestWorkerPoolQueueShutdown(t *testing.T) {
func TestWorkerPoolQueueWorkerIdleReset(t *testing.T) {
defer test.MockVariableValue(&workerIdleDuration, 10*time.Millisecond)()
defer mockBackoffDuration(5 * time.Millisecond)()
var q *WorkerPoolQueue[int]
var handledCount atomic.Int32
var hasOnlyOneWorkerRunning atomic.Bool
handler := func(items ...int) (unhandled []int) {
time.Sleep(50 * time.Millisecond)
handledCount.Add(int32(len(items)))
// make each work have different duration, and check the active worker number periodically
var activeNums []int
for i := 0; i < 5-items[0]%2; i++ {
time.Sleep(workerIdleDuration * 2)
activeNums = append(activeNums, q.GetWorkerActiveNumber())
}
// When the queue never becomes empty, the existing workers should keep working
// It is not 100% true at the moment because the data-race in workergroup.go is not resolved, see that TODO */
// If the "active worker numbers" is like [2 2 ... 1 1], it means that an existing worker exited and the no new worker is started.
if slices.Equal([]int{1, 1}, activeNums[len(activeNums)-2:]) {
hasOnlyOneWorkerRunning.Store(true)
}
return nil
}
q, _ := newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 2, Length: 100}, handler, false)
q, _ = newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 2, Length: 100}, handler, false)
stop := runWorkerPoolQueue(q)
for i := 0; i < 20; i++ {
for i := 0; i < 100; i++ {
assert.NoError(t, q.Push(i))
}
time.Sleep(500 * time.Millisecond)
assert.EqualValues(t, 2, q.GetWorkerNumber())
assert.EqualValues(t, 2, q.GetWorkerActiveNumber())
// when the queue never becomes empty, the existing workers should keep working
assert.EqualValues(t, 2, q.workerStartedCounter)
assert.Greater(t, int(handledCount.Load()), 4) // make sure there are enough items handled during the test
assert.False(t, hasOnlyOneWorkerRunning.Load(), "a slow handler should not block other workers from starting")
stop()
}

View File

@ -32,7 +32,6 @@ func CreateTemporaryPath(prefix string) (string, error) {
if err != nil {
log.Error("Unable to create temporary directory: %s-*.git (%v)", prefix, err)
return "", fmt.Errorf("Failed to create dir %s-*.git: %w", prefix, err)
}
return basePath, nil
}

View File

@ -6,9 +6,6 @@ package session
import (
"net/http"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web/middleware"
"gitea.com/go-chi/session"
)
@ -21,10 +18,12 @@ type Store interface {
// RegenerateSession regenerates the underlying session and returns the new store
func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, error) {
// Ensure that a cookie with a trailing slash does not take precedence over
// the cookie written by the middleware.
middleware.DeleteLegacySiteCookie(resp, setting.SessionConfig.CookieName)
for _, f := range BeforeRegenerateSession {
f(resp, req)
}
s, err := session.RegenerateSession(resp, req)
return s, err
}
// BeforeRegenerateSession is a list of functions that are called before a session is regenerated.
var BeforeRegenerateSession []func(http.ResponseWriter, *http.Request)

View File

@ -318,7 +318,7 @@ func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting any) {
// StartupProblems contains the messages for various startup problems, including: setting option, file/folder, etc
var StartupProblems []string
func logStartupProblem(skip int, level log.Level, format string, args ...any) {
func LogStartupProblem(skip int, level log.Level, format string, args ...any) {
msg := fmt.Sprintf(format, args...)
log.Log(skip+1, level, "%s", msg)
StartupProblems = append(StartupProblems, msg)
@ -326,14 +326,14 @@ func logStartupProblem(skip int, level log.Level, format string, args ...any) {
func deprecatedSetting(rootCfg ConfigProvider, oldSection, oldKey, newSection, newKey, version string) {
if rootCfg.Section(oldSection).HasKey(oldKey) {
logStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents, please use `[%s].%s` instead because this fallback will be/has been removed in %s", oldSection, oldKey, newSection, newKey, version)
LogStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents, please use `[%s].%s` instead because this fallback will be/has been removed in %s", oldSection, oldKey, newSection, newKey, version)
}
}
// deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini
func deprecatedSettingDB(rootCfg ConfigProvider, oldSection, oldKey string) {
if rootCfg.Section(oldSection).HasKey(oldKey) {
logStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents but it won't take effect because it has been moved to admin panel -> config setting", oldSection, oldKey)
LogStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents but it won't take effect because it has been moved to admin panel -> config setting", oldSection, oldKey)
}
}

View File

@ -174,7 +174,7 @@ func GetGeneralTokenSigningSecret() []byte {
}
if generalSigningSecret.CompareAndSwap(old, &jwtSecret) {
// FIXME: in main branch, the signing token should be refactored (eg: one unique for LFS/OAuth2/etc ...)
logStartupProblem(1, log.WARN, "OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes")
LogStartupProblem(1, log.WARN, "OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes")
return jwtSecret
}
return *generalSigningSecret.Load()

View File

@ -235,7 +235,7 @@ var configuredPaths = make(map[string]string)
func checkOverlappedPath(name, path string) {
// TODO: some paths shouldn't overlap (storage.xxx.path), while some could (data path is the base path for storage path)
if targetName, ok := configuredPaths[path]; ok && targetName != name {
logStartupProblem(1, log.ERROR, "Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name)
LogStartupProblem(1, log.ERROR, "Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name)
}
configuredPaths[path] = name
}

View File

@ -19,9 +19,8 @@ func loadTimeFrom(rootCfg ConfigProvider) {
DefaultUILocation, err = time.LoadLocation(zone)
if err != nil {
log.Fatal("Load time zone failed: %v", err)
} else {
log.Info("Default UI Location is %v", zone)
}
log.Info("Default UI Location is %v", zone)
}
if DefaultUILocation == nil {
DefaultUILocation = time.Local

View File

@ -82,7 +82,6 @@ var UI = struct {
ReactionMaxUserNum: 10,
MaxDisplayFileSize: 8388608,
DefaultTheme: `gitea-auto`,
Themes: []string{`gitea-auto`, `gitea-light`, `gitea-dark`},
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},

View File

@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/gitdiff"
"code.gitea.io/gitea/services/webtheme"
)
// NewFuncMap returns functions for injecting to templates
@ -137,12 +138,7 @@ func NewFuncMap() template.FuncMap {
"DisableImportLocal": func() bool {
return !setting.ImportLocalPaths
},
"ThemeName": func(user *user_model.User) string {
if user == nil || user.Theme == "" {
return setting.UI.DefaultTheme
}
return user.Theme
},
"UserThemeName": UserThemeName,
"NotificationSettings": func() map[string]any {
return map[string]any{
"MinTimeout": int(setting.UI.Notification.MinTimeout / time.Millisecond),
@ -261,3 +257,13 @@ func Eval(tokens ...any) (any, error) {
n, err := eval.Expr(tokens...)
return n.Value, err
}
func UserThemeName(user *user_model.User) string {
if user == nil || user.Theme == "" {
return setting.UI.DefaultTheme
}
if webtheme.IsThemeAvailable(user.Theme) {
return user.Theme
}
return setting.UI.DefaultTheme
}

View File

@ -138,10 +138,9 @@ func wrapTmplErrMsg(msg string) {
if setting.IsProd {
// in prod mode, Gitea must have correct templates to run
log.Fatal("Gitea can't run with template errors: %s", msg)
} else {
// in dev mode, do not need to really exit, because the template errors could be fixed by developer soon and the templates get reloaded
log.Error("There are template errors but Gitea continues to run in dev mode: %s", msg)
}
// in dev mode, do not need to really exit, because the template errors could be fixed by developer soon and the templates get reloaded
log.Error("There are template errors but Gitea continues to run in dev mode: %s", msg)
}
type templateErrorPrettier struct {

View File

@ -84,9 +84,8 @@ func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) {
if err = buildSubjectBodyTemplate(subjectTemplates, bodyTemplates, tmplName, content); err != nil {
if firstRun {
log.Fatal("Failed to parse mail template, err: %v", err)
} else {
log.Error("Failed to parse mail template, err: %v", err)
}
log.Error("Failed to parse mail template, err: %v", err)
}
}
}

View File

@ -121,9 +121,9 @@ func Test_NormalizeEOL(t *testing.T) {
}
func Test_RandomInt(t *testing.T) {
int, err := CryptoRandomInt(255)
assert.True(t, int >= 0)
assert.True(t, int <= 255)
randInt, err := CryptoRandomInt(255)
assert.True(t, randInt >= 0)
assert.True(t, randInt <= 255)
assert.NoError(t, err)
}

View File

@ -128,6 +128,16 @@ func hasResponseBeenWritten(argsIn []reflect.Value) bool {
return false
}
func wrapHandlerProvider[T http.Handler](hp func(next http.Handler) T, funcInfo *routing.FuncInfo) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
h := hp(next) // this handle could be dynamically generated, so we can't use it for debug info
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
routing.UpdateFuncInfo(req.Context(), funcInfo)
h.ServeHTTP(resp, req)
})
}
}
// toHandlerProvider converts a handler to a handler provider
// A handler provider is a function that takes a "next" http.Handler, it can be used as a middleware
func toHandlerProvider(handler any) func(next http.Handler) http.Handler {
@ -138,13 +148,9 @@ func toHandlerProvider(handler any) func(next http.Handler) http.Handler {
}
if hp, ok := handler.(func(next http.Handler) http.Handler); ok {
return func(next http.Handler) http.Handler {
h := hp(next) // this handle could be dynamically generated, so we can't use it for debug info
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
routing.UpdateFuncInfo(req.Context(), funcInfo)
h.ServeHTTP(resp, req)
})
}
return wrapHandlerProvider(hp, funcInfo)
} else if hp, ok := handler.(func(http.Handler) http.HandlerFunc); ok {
return wrapHandlerProvider(hp, funcInfo)
}
provider := func(next http.Handler) http.Handler {

View File

@ -9,6 +9,7 @@ import (
"net/url"
"strings"
"code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting"
)
@ -48,12 +49,12 @@ func SetSiteCookie(resp http.ResponseWriter, name, value string, maxAge int) {
// Previous versions would use a cookie path with a trailing /.
// These are more specific than cookies without a trailing /, so
// we need to delete these if they exist.
DeleteLegacySiteCookie(resp, name)
deleteLegacySiteCookie(resp, name)
}
// DeleteLegacySiteCookie deletes the cookie with the given name at the cookie
// deleteLegacySiteCookie deletes the cookie with the given name at the cookie
// path with a trailing /, which would unintentionally override the cookie.
func DeleteLegacySiteCookie(resp http.ResponseWriter, name string) {
func deleteLegacySiteCookie(resp http.ResponseWriter, name string) {
if setting.SessionConfig.CookiePath == "" || strings.HasSuffix(setting.SessionConfig.CookiePath, "/") {
// If the cookie path ends with /, no legacy cookies will take
// precedence, so do nothing. The exception is that cookies with no
@ -74,3 +75,11 @@ func DeleteLegacySiteCookie(resp http.ResponseWriter, name string) {
}
resp.Header().Add("Set-Cookie", cookie.String())
}
func init() {
session.BeforeRegenerateSession = append(session.BeforeRegenerateSession, func(resp http.ResponseWriter, _ *http.Request) {
// Ensure that a cookie with a trailing slash does not take precedence over
// the cookie written by the middleware.
deleteLegacySiteCookie(resp, setting.SessionConfig.CookieName)
})
}

View File

@ -0,0 +1,10 @@
Copyright (C) 1985, 1990 Regents of the University of California.
Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies. The University of California
makes no representations about the suitability of this
software for any purpose. It is provided "as is" without
express or implied warranty. Export of this software outside
of the United States of America may require an export license.

32
options/license/NCL Normal file
View File

@ -0,0 +1,32 @@
Copyright (c) 2004 the University Corporation for Atmospheric
Research ("UCAR"). All rights reserved. Developed by NCAR's
Computational and Information Systems Laboratory, UCAR,
www.cisl.ucar.edu.
Redistribution and use of the Software in source and binary forms,
with or without modification, is permitted provided that the
following conditions are met:
- Neither the names of NCAR's Computational and Information Systems
Laboratory, the University Corporation for Atmospheric Research,
nor the names of its sponsors or contributors may be used to
endorse or promote products derived from this Software without
specific prior written permission.
- Redistributions of source code must retain the above copyright
notices, this list of conditions, and the disclaimer below.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the disclaimer below in the
documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.

View File

@ -1186,7 +1186,6 @@ action.blocked_user=Nelze provést akci, protože jste zablokování vlastníkem
download_archive=Stáhnout repozitář
more_operations=Další operace
no_desc=Bez popisu
quick_guide=Krátká příručka
clone_this_repo=Naklonovat tento repozitář
cite_this_repo=Citovat tento repozitář

View File

@ -1187,7 +1187,6 @@ action.blocked_user=Die Aktion kann nicht ausgeführt werden, da du vom Reposito
download_archive=Repository herunterladen
more_operations=Weitere Operationen
no_desc=Keine Beschreibung
quick_guide=Kurzanleitung
clone_this_repo=Dieses Repository klonen
cite_this_repo=Dieses Repository zitieren

View File

@ -1118,7 +1118,6 @@ fork=Fork
download_archive=Λήψη Αποθετηρίου
more_operations=Περισσότερες Λειτουργίες
no_desc=Χωρίς Περιγραφή
quick_guide=Γρήγορος Οδηγός
clone_this_repo=Κλωνοποίηση αυτού του αποθετηρίου
cite_this_repo=Αναφορά σε αυτό το αποθετήριο

View File

@ -763,6 +763,8 @@ manage_themes = Select default theme
manage_openid = Manage OpenID Addresses
email_desc = Your primary email address will be used for notifications, password recovery and, provided that it is not hidden, web-based Git operations.
theme_desc = This will be your default theme across the site.
theme_colorblindness_help = Colorblindness Theme Support
theme_colorblindness_prompt = Gitea just gets some themes with basic colorblindness support, which only have a few colors defined. The work is still in progress. More improvements could be done by defining more colors in the theme CSS files.
primary = Primary
activated = Activated
requires_activation = Requires activation
@ -1193,7 +1195,6 @@ action.blocked_user = Cannot perform action because you are blocked by the repos
download_archive = Download Repository
more_operations = More Operations
no_desc = No Description
quick_guide = Quick Guide
clone_this_repo = Clone this repository
cite_this_repo = Cite this repository

View File

@ -1111,7 +1111,6 @@ fork=Fork
download_archive=Descargar repositorio
more_operations=Más operaciones
no_desc=Sin descripción
quick_guide=Guía rápida
clone_this_repo=Clonar este repositorio
cite_this_repo=Citar este repositorio

View File

@ -874,7 +874,6 @@ star=ستاره دار کن
fork=انشعاب
download_archive=دانلود مخزن
no_desc=بدون توضیح
quick_guide=راهنمای سریع
clone_this_repo=همسان‌سازی این مخزن
create_new_repo_command=ایجاد یک مخزن جدید در خط فرمان

View File

@ -718,7 +718,6 @@ unstar=Poista tähti
star=Tähti
download_archive=Lataa repo
no_desc=Ei kuvausta
quick_guide=Pikaopas
clone_this_repo=Kloonaa tämä repo

View File

@ -150,6 +150,10 @@ filter.private=Privé
[search]
exact=Exact
exact_tooltip=Inclure uniquement les résultats qui correspondent exactement au terme de recherche
issue_kind=Recherche de tickets…
pull_kind=Recherche de demandes dajouts…
[aria]
navbar=Barre de navigation
@ -824,6 +828,7 @@ repo_and_org_access=Accès aux Organisations et Dépôts
permissions_public_only=Publique uniquement
permissions_access_all=Tout (public, privé et limité)
select_permissions=Sélectionner les autorisations
permission_not_set=Non défini
permission_no_access=Aucun accès
permission_read=Lecture
permission_write=Lecture et écriture
@ -1125,7 +1130,6 @@ fork=Bifurcation
download_archive=Télécharger ce dépôt
more_operations=Plus d'opérations
no_desc=Aucune description
quick_guide=Introduction rapide
clone_this_repo=Cloner ce dépôt
cite_this_repo=Citer ce dépôt
@ -2016,6 +2020,7 @@ settings.branches.add_new_rule=Ajouter une nouvelle règle
settings.advanced_settings=Paramètres avancés
settings.wiki_desc=Activer le wiki du dépôt
settings.use_internal_wiki=Utiliser le wiki interne
settings.default_wiki_everyone_access=Autorisation daccès par défaut pour les utilisateurs connectés :
settings.use_external_wiki=Utiliser un wiki externe
settings.external_wiki_url=URL Wiki externe
settings.external_wiki_url_error=LURL du wiki externe nest pas une URL valide.

View File

@ -656,7 +656,6 @@ star=Csillagozás
fork=Tükrözés
download_archive=Tároló letöltése
no_desc=Nincs leírás
quick_guide=Gyors útmutató
clone_this_repo=Tároló klónozása
create_new_repo_command=Egy új tároló létrehozása a parancssorból

View File

@ -570,7 +570,6 @@ star=Bintang
fork=Garpu
download_archive=Unduh Repositori
no_desc=Tidak ada Deskripsi
quick_guide=Panduan Cepat
clone_this_repo=Klon repositori ini
create_new_repo_command=Membuat repositori baru pada baris perintah

Some files were not shown because too many files have changed in this diff Show More