diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 104f1cfeeda..95d673cd309 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -7,7 +7,7 @@
"version": "lts"
},
"ghcr.io/devcontainers/features/git-lfs:1.2.2": {},
- "ghcr.io/devcontainers-extra/features/poetry:2": {},
+ "ghcr.io/jsburckhardt/devcontainer-features/uv:1": {},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.12"
},
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 57c6b19600b..cf3ff53b30d 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -326,6 +326,7 @@ module.exports = {
'@typescript-eslint/no-unnecessary-type-arguments': [0],
'@typescript-eslint/no-unnecessary-type-assertion': [2],
'@typescript-eslint/no-unnecessary-type-constraint': [2],
+ '@typescript-eslint/no-unnecessary-type-conversion': [2],
'@typescript-eslint/no-unsafe-argument': [0],
'@typescript-eslint/no-unsafe-assignment': [0],
'@typescript-eslint/no-unsafe-call': [0],
@@ -645,7 +646,7 @@ module.exports = {
'no-multi-str': [2],
'no-negated-condition': [0],
'no-nested-ternary': [0],
- 'no-new-func': [2],
+ 'no-new-func': [0], // handled by @typescript-eslint/no-implied-eval
'no-new-native-nonconstructor': [2],
'no-new-object': [2],
'no-new-symbol': [2],
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 0af43cd0299..a82bf0c2b21 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -61,7 +61,7 @@ modifies/dependencies:
- "package.json"
- "package-lock.json"
- "pyproject.toml"
- - "poetry.lock"
+ - "uv.lock"
- "go.mod"
- "go.sum"
@@ -81,3 +81,13 @@ docs-update-needed:
- changed-files:
- any-glob-to-any-file:
- "custom/conf/app.example.ini"
+
+topic/code-linting:
+ - changed-files:
+ - any-glob-to-any-file:
+ - ".eslintrc.cjs"
+ - ".golangci.yml"
+ - ".markdownlint.yaml"
+ - ".spectral.yaml"
+ - ".yamllint.yaml"
+ - "stylelint.config.js"
diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml
index be275379243..21d3ea73939 100644
--- a/.github/workflows/files-changed.yml
+++ b/.github/workflows/files-changed.yml
@@ -77,7 +77,7 @@ jobs:
- "tools/lint-templates-*.js"
- "templates/**/*.tmpl"
- "pyproject.toml"
- - "poetry.lock"
+ - "uv.lock"
docker:
- "Dockerfile"
@@ -98,4 +98,3 @@ jobs:
- "**/*.yaml"
- ".yamllint.yaml"
- "pyproject.toml"
- - "poetry.lock"
diff --git a/.github/workflows/pull-compliance.yml b/.github/workflows/pull-compliance.yml
index f6720bf2f6d..56685ffb460 100644
--- a/.github/workflows/pull-compliance.yml
+++ b/.github/workflows/pull-compliance.yml
@@ -32,15 +32,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - uses: actions/setup-python@v5
- with:
- python-version: "3.12"
+ - uses: astral-sh/setup-uv@v6
+ - run: uv python install 3.12
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
cache-dependency-path: package-lock.json
- - run: pip install poetry
- run: make deps-py
- run: make deps-frontend
- run: make lint-templates
@@ -51,10 +49,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - uses: actions/setup-python@v5
- with:
- python-version: "3.12"
- - run: pip install poetry
+ - uses: astral-sh/setup-uv@v6
+ - run: uv python install 3.12
- run: make deps-py
- run: make lint-yaml
diff --git a/.gitignore b/.gitignore
index 0791a17c710..fc2d74a33ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -109,3 +109,15 @@ prime/
# Manpage
/man
+
+# Ignore AI/LLM instruction files
+/.claude/
+/.cursorrules
+/.cursor/
+/.goosehints
+/.windsurfrules
+/.github/copilot-instructions.md
+/AGENT.md
+/CLAUDE.md
+/llms.txt
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 11c99d1e3a9..96e05c578fc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -591,7 +591,7 @@ be reviewed by two maintainers and must pass the automatic tests.
## Releasing Gitea
- Let $vmaj, $vmin and $vpat be Major, Minor and Patch version numbers, $vpat should be rc1, rc2, 0, 1, ...... $vmaj.$vmin will be kept the same as milestones on github or gitea in future.
-- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody against in about serval hours.
+- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours.
- If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
- Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
- When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
diff --git a/Dockerfile b/Dockerfile
index c9e6a2d3db8..f852cf42355 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -39,7 +39,6 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
/tmp/local/etc/s6/.s6-svscan/* \
/go/src/code.gitea.io/gitea/gitea \
/go/src/code.gitea.io/gitea/environment-to-ini
-RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM docker.io/library/alpine:3.22
LABEL maintainer="maintainers@gitea.io"
@@ -83,4 +82,3 @@ CMD ["/usr/bin/s6-svscan", "/etc/s6"]
COPY --from=build-env /tmp/local /
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
-COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
diff --git a/Dockerfile.rootless b/Dockerfile.rootless
index 558e6cf73bc..f955edc6678 100644
--- a/Dockerfile.rootless
+++ b/Dockerfile.rootless
@@ -37,7 +37,6 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
/tmp/local/usr/local/bin/gitea \
/go/src/code.gitea.io/gitea/gitea \
/go/src/code.gitea.io/gitea/environment-to-ini
-RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM docker.io/library/alpine:3.22
LABEL maintainer="maintainers@gitea.io"
@@ -72,7 +71,6 @@ RUN chown git:git /var/lib/gitea /etc/gitea
COPY --from=build-env /tmp/local /
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
-COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
# git:git
USER 1000:1000
diff --git a/Makefile b/Makefile
index 6a3fa60e495..08ff938972d 100644
--- a/Makefile
+++ b/Makefile
@@ -393,11 +393,11 @@ lint-actions: ## lint action workflow files
.PHONY: lint-templates
lint-templates: .venv node_modules ## lint template files
@node tools/lint-templates-svg.js
- @poetry run djlint $(shell find templates -type f -iname '*.tmpl')
+ @uv run --frozen djlint $(shell find templates -type f -iname '*.tmpl')
.PHONY: lint-yaml
lint-yaml: .venv ## lint yaml files
- @poetry run yamllint -s .
+ @uv run --frozen yamllint -s .
.PHONY: watch
watch: ## watch everything and continuously rebuild
@@ -829,8 +829,8 @@ node_modules: package-lock.json
npm install --no-save
@touch node_modules
-.venv: poetry.lock
- poetry install
+.venv: uv.lock
+ uv sync
@touch .venv
.PHONY: update
@@ -848,8 +848,8 @@ update-js: node-check | node_modules ## update js dependencies
.PHONY: update-py
update-py: node-check | node_modules ## update py dependencies
npx updates -u -f pyproject.toml
- rm -rf .venv poetry.lock
- poetry install
+ rm -rf .venv uv.lock
+ uv sync
@touch .venv
.PHONY: webpack
diff --git a/cmd/admin_auth_oauth.go b/cmd/admin_auth_oauth.go
index d1aa753500a..8848c94fc51 100644
--- a/cmd/admin_auth_oauth.go
+++ b/cmd/admin_auth_oauth.go
@@ -87,6 +87,14 @@ func oauthCLIFlags() []cli.Flag {
Value: nil,
Usage: "Scopes to request when to authenticate against this OAuth2 source",
},
+ &cli.StringFlag{
+ Name: "ssh-public-key-claim-name",
+ Usage: "Claim name that provides SSH public keys",
+ },
+ &cli.StringFlag{
+ Name: "full-name-claim-name",
+ Usage: "Claim name that provides user's full name",
+ },
&cli.StringFlag{
Name: "required-claim-name",
Value: "",
@@ -177,6 +185,8 @@ func parseOAuth2Config(c *cli.Command) *oauth2.Source {
RestrictedGroup: c.String("restricted-group"),
GroupTeamMap: c.String("group-team-map"),
GroupTeamMapRemoval: c.Bool("group-team-map-removal"),
+ SSHPublicKeyClaimName: c.String("ssh-public-key-claim-name"),
+ FullNameClaimName: c.String("full-name-claim-name"),
}
}
@@ -268,6 +278,12 @@ func (a *authService) runUpdateOauth(ctx context.Context, c *cli.Command) error
if c.IsSet("group-team-map-removal") {
oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal")
}
+ if c.IsSet("ssh-public-key-claim-name") {
+ oAuth2Config.SSHPublicKeyClaimName = c.String("ssh-public-key-claim-name")
+ }
+ if c.IsSet("full-name-claim-name") {
+ oAuth2Config.FullNameClaimName = c.String("full-name-claim-name")
+ }
// update custom URL mapping
customURLMapping := &oauth2.CustomURLMapping{}
diff --git a/cmd/admin_auth_oauth_test.go b/cmd/admin_auth_oauth_test.go
index df1bd9c1a6d..bb9da667fd1 100644
--- a/cmd/admin_auth_oauth_test.go
+++ b/cmd/admin_auth_oauth_test.go
@@ -88,6 +88,8 @@ func TestAddOauth(t *testing.T) {
"--restricted-group", "restricted",
"--group-team-map", `{"group1": [1,2]}`,
"--group-team-map-removal=true",
+ "--ssh-public-key-claim-name", "attr_ssh_pub_key",
+ "--full-name-claim-name", "attr_full_name",
},
source: &auth_model.Source{
Type: auth_model.OAuth2,
@@ -104,15 +106,17 @@ func TestAddOauth(t *testing.T) {
EmailURL: "https://example.com/email",
Tenant: "some_tenant",
},
- IconURL: "https://example.com/icon",
- Scopes: []string{"scope1", "scope2"},
- RequiredClaimName: "claim_name",
- RequiredClaimValue: "claim_value",
- GroupClaimName: "group_name",
- AdminGroup: "admin",
- RestrictedGroup: "restricted",
- GroupTeamMap: `{"group1": [1,2]}`,
- GroupTeamMapRemoval: true,
+ IconURL: "https://example.com/icon",
+ Scopes: []string{"scope1", "scope2"},
+ RequiredClaimName: "claim_name",
+ RequiredClaimValue: "claim_value",
+ GroupClaimName: "group_name",
+ AdminGroup: "admin",
+ RestrictedGroup: "restricted",
+ GroupTeamMap: `{"group1": [1,2]}`,
+ GroupTeamMapRemoval: true,
+ SSHPublicKeyClaimName: "attr_ssh_pub_key",
+ FullNameClaimName: "attr_full_name",
},
TwoFactorPolicy: "skip",
},
@@ -223,15 +227,17 @@ func TestUpdateOauth(t *testing.T) {
EmailURL: "https://old.example.com/email",
Tenant: "old_tenant",
},
- IconURL: "https://old.example.com/icon",
- Scopes: []string{"old_scope1", "old_scope2"},
- RequiredClaimName: "old_claim_name",
- RequiredClaimValue: "old_claim_value",
- GroupClaimName: "old_group_name",
- AdminGroup: "old_admin",
- RestrictedGroup: "old_restricted",
- GroupTeamMap: `{"old_group1": [1,2]}`,
- GroupTeamMapRemoval: true,
+ IconURL: "https://old.example.com/icon",
+ Scopes: []string{"old_scope1", "old_scope2"},
+ RequiredClaimName: "old_claim_name",
+ RequiredClaimValue: "old_claim_value",
+ GroupClaimName: "old_group_name",
+ AdminGroup: "old_admin",
+ RestrictedGroup: "old_restricted",
+ GroupTeamMap: `{"old_group1": [1,2]}`,
+ GroupTeamMapRemoval: true,
+ SSHPublicKeyClaimName: "old_ssh_pub_key",
+ FullNameClaimName: "old_full_name",
},
TwoFactorPolicy: "",
},
@@ -257,6 +263,8 @@ func TestUpdateOauth(t *testing.T) {
"--restricted-group", "restricted",
"--group-team-map", `{"group1": [1,2]}`,
"--group-team-map-removal=false",
+ "--ssh-public-key-claim-name", "new_ssh_pub_key",
+ "--full-name-claim-name", "new_full_name",
},
authSource: &auth_model.Source{
ID: 1,
@@ -274,15 +282,17 @@ func TestUpdateOauth(t *testing.T) {
EmailURL: "https://example.com/email",
Tenant: "new_tenant",
},
- IconURL: "https://example.com/icon",
- Scopes: []string{"scope1", "scope2"},
- RequiredClaimName: "claim_name",
- RequiredClaimValue: "claim_value",
- GroupClaimName: "group_name",
- AdminGroup: "admin",
- RestrictedGroup: "restricted",
- GroupTeamMap: `{"group1": [1,2]}`,
- GroupTeamMapRemoval: false,
+ IconURL: "https://example.com/icon",
+ Scopes: []string{"scope1", "scope2"},
+ RequiredClaimName: "claim_name",
+ RequiredClaimValue: "claim_value",
+ GroupClaimName: "group_name",
+ AdminGroup: "admin",
+ RestrictedGroup: "restricted",
+ GroupTeamMap: `{"group1": [1,2]}`,
+ GroupTeamMapRemoval: false,
+ SSHPublicKeyClaimName: "new_ssh_pub_key",
+ FullNameClaimName: "new_full_name",
},
TwoFactorPolicy: "skip",
},
diff --git a/cmd/hook.go b/cmd/hook.go
index 2ce272b411e..b741127ca3c 100644
--- a/cmd/hook.go
+++ b/cmd/hook.go
@@ -32,6 +32,7 @@ var (
CmdHook = &cli.Command{
Name: "hook",
Usage: "(internal) Should only be called by Git",
+ Hidden: true, // internal commands shouldn't be visible
Description: "Delegate commands to corresponding Git hooks",
Before: PrepareConsoleLoggerLevel(log.FATAL),
Commands: []*cli.Command{
diff --git a/cmd/keys.go b/cmd/keys.go
index 8710756a813..5ca3b91e15e 100644
--- a/cmd/keys.go
+++ b/cmd/keys.go
@@ -19,6 +19,7 @@ import (
var CmdKeys = &cli.Command{
Name: "keys",
Usage: "(internal) Should only be called by SSH server",
+ Hidden: true, // internal commands shouldn't not be visible
Description: "Queries the Gitea database to get the authorized command for a given ssh key fingerprint",
Before: PrepareConsoleLoggerLevel(log.FATAL),
Action: runKeys,
diff --git a/cmd/main.go b/cmd/main.go
index 3b8a8a93116..3fdaf48ed96 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -6,6 +6,7 @@ package cmd
import (
"context"
"fmt"
+ "io"
"os"
"strings"
@@ -15,26 +16,28 @@ import (
"github.com/urfave/cli/v3"
)
-// cmdHelp is our own help subcommand with more information
-// Keep in mind that the "./gitea help"(subcommand) is different from "./gitea --help"(flag), the flag doesn't parse the config or output "DEFAULT CONFIGURATION:" information
-func cmdHelp() *cli.Command {
- c := &cli.Command{
- Name: "help",
- Aliases: []string{"h"},
- Usage: "Shows a list of commands or help for one command",
- ArgsUsage: "[command]",
- Action: func(ctx context.Context, c *cli.Command) (err error) {
- lineage := c.Lineage() // The order is from child to parent: help, doctor, Gitea
- targetCmdIdx := 0
- if c.Name == "help" {
- targetCmdIdx = 1
- }
- if lineage[targetCmdIdx] != lineage[targetCmdIdx].Root() {
- err = cli.ShowCommandHelp(ctx, lineage[targetCmdIdx+1] /* parent cmd */, lineage[targetCmdIdx].Name /* sub cmd */)
- } else {
- err = cli.ShowAppHelp(c)
- }
- _, _ = fmt.Fprintf(c.Root().Writer, `
+var cliHelpPrinterOld = cli.HelpPrinter
+
+func init() {
+ cli.HelpPrinter = cliHelpPrinterNew
+}
+
+// cliHelpPrinterNew helps to print "DEFAULT CONFIGURATION" for the following cases ( "-c" can apper in any position):
+// * ./gitea -c /dev/null -h
+// * ./gitea -c help /dev/null help
+// * ./gitea help -c /dev/null
+// * ./gitea help -c /dev/null web
+// * ./gitea help web -c /dev/null
+// * ./gitea web help -c /dev/null
+// * ./gitea web -h -c /dev/null
+func cliHelpPrinterNew(out io.Writer, templ string, data any) {
+ cmd, _ := data.(*cli.Command)
+ if cmd != nil {
+ prepareWorkPathAndCustomConf(cmd)
+ }
+ cliHelpPrinterOld(out, templ, data)
+ if setting.CustomConf != "" {
+ _, _ = fmt.Fprintf(out, `
DEFAULT CONFIGURATION:
AppPath: %s
WorkPath: %s
@@ -42,77 +45,36 @@ DEFAULT CONFIGURATION:
ConfigFile: %s
`, setting.AppPath, setting.AppWorkPath, setting.CustomPath, setting.CustomConf)
- return err
- },
- }
- return c
-}
-
-func appGlobalFlags() []cli.Flag {
- return []cli.Flag{
- // make the builtin flags at the top
- cli.HelpFlag,
-
- // shared configuration flags, they are for global and for each sub-command at the same time
- // eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed
- // keep in mind that the short flags like "-C", "-c" and "-w" are globally polluted, they can't be used for sub-commands anymore.
- &cli.StringFlag{
- Name: "custom-path",
- Aliases: []string{"C"},
- Usage: "Set custom path (defaults to '{WorkPath}/custom')",
- },
- &cli.StringFlag{
- Name: "config",
- Aliases: []string{"c"},
- Value: setting.CustomConf,
- Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')",
- },
- &cli.StringFlag{
- Name: "work-path",
- Aliases: []string{"w"},
- Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)",
- },
}
}
-func prepareSubcommandWithGlobalFlags(command *cli.Command) {
- command.Flags = append(append([]cli.Flag{}, appGlobalFlags()...), command.Flags...)
- command.Action = prepareWorkPathAndCustomConf(command.Action)
- command.HideHelp = true
- if command.Name != "help" {
- command.Commands = append(command.Commands, cmdHelp())
- }
- for i := range command.Commands {
- prepareSubcommandWithGlobalFlags(command.Commands[i])
- }
-}
-
-// prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config
-// It can't use "Before", because each level's sub-command's Before will be called one by one, so the "init" would be done multiple times
-func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(context.Context, *cli.Command) error {
- return func(ctx context.Context, cmd *cli.Command) error {
- var args setting.ArgWorkPathAndCustomConf
- // from children to parent, check the global flags
- for _, curCtx := range cmd.Lineage() {
- if curCtx.IsSet("work-path") && args.WorkPath == "" {
- args.WorkPath = curCtx.String("work-path")
- }
- if curCtx.IsSet("custom-path") && args.CustomPath == "" {
- args.CustomPath = curCtx.String("custom-path")
- }
- if curCtx.IsSet("config") && args.CustomConf == "" {
- args.CustomConf = curCtx.String("config")
- }
+func prepareSubcommandWithGlobalFlags(originCmd *cli.Command) {
+ originBefore := originCmd.Before
+ originCmd.Before = func(ctx context.Context, cmd *cli.Command) (context.Context, error) {
+ prepareWorkPathAndCustomConf(cmd)
+ if originBefore != nil {
+ return originBefore(ctx, cmd)
}
- setting.InitWorkPathAndCommonConfig(os.Getenv, args)
- if cmd.Bool("help") || action == nil {
- // the default behavior of "urfave/cli": "nil action" means "show help"
- return cmdHelp().Action(ctx, cmd)
- }
- return action(ctx, cmd)
+ return ctx, nil
}
}
+// prepareWorkPathAndCustomConf tries to prepare the work path, custom path and custom config from various inputs:
+// command line flags, environment variables, config file
+func prepareWorkPathAndCustomConf(cmd *cli.Command) {
+ var args setting.ArgWorkPathAndCustomConf
+ if cmd.IsSet("work-path") {
+ args.WorkPath = cmd.String("work-path")
+ }
+ if cmd.IsSet("custom-path") {
+ args.CustomPath = cmd.String("custom-path")
+ }
+ if cmd.IsSet("config") {
+ args.CustomConf = cmd.String("config")
+ }
+ setting.InitWorkPathAndCommonConfig(os.Getenv, args)
+}
+
type AppVersion struct {
Version string
Extra string
@@ -125,10 +87,29 @@ func NewMainApp(appVer AppVersion) *cli.Command {
app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.`
app.Version = appVer.Version + appVer.Extra
app.EnableShellCompletion = true
-
- // these sub-commands need to use config file
+ app.Flags = []cli.Flag{
+ &cli.StringFlag{
+ Name: "work-path",
+ Aliases: []string{"w"},
+ TakesFile: true,
+ Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)",
+ },
+ &cli.StringFlag{
+ Name: "config",
+ Aliases: []string{"c"},
+ TakesFile: true,
+ Value: setting.CustomConf,
+ Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')",
+ },
+ &cli.StringFlag{
+ Name: "custom-path",
+ Aliases: []string{"C"},
+ TakesFile: true,
+ Usage: "Set custom path (defaults to '{WorkPath}/custom')",
+ },
+ }
+ // these sub-commands need to use a config file
subCmdWithConfig := []*cli.Command{
- cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
CmdWeb,
CmdServ,
CmdHook,
@@ -156,9 +137,6 @@ func NewMainApp(appVer AppVersion) *cli.Command {
// but not sure whether it would break Windows users who used to double-click the EXE to run.
app.DefaultCommand = CmdWeb.Name
- app.Flags = append(app.Flags, cli.VersionFlag)
- app.Flags = append(app.Flags, appGlobalFlags()...)
- app.HideHelp = true // use our own help action to show helps (with more information like default config)
app.Before = PrepareConsoleLoggerLevel(log.INFO)
for i := range subCmdWithConfig {
prepareSubcommandWithGlobalFlags(subCmdWithConfig[i])
diff --git a/cmd/main_test.go b/cmd/main_test.go
index 7dfa87a0ef0..d49ebfd4df4 100644
--- a/cmd/main_test.go
+++ b/cmd/main_test.go
@@ -74,12 +74,56 @@ func TestCliCmd(t *testing.T) {
cmd string
exp string
}{
- // main command help
+ // help commands
+ {
+ cmd: "./gitea -h",
+ exp: "DEFAULT CONFIGURATION:",
+ },
{
cmd: "./gitea help",
exp: "DEFAULT CONFIGURATION:",
},
+ {
+ cmd: "./gitea -c /dev/null -h",
+ exp: "ConfigFile: /dev/null",
+ },
+
+ {
+ cmd: "./gitea -c /dev/null help",
+ exp: "ConfigFile: /dev/null",
+ },
+ {
+ cmd: "./gitea help -c /dev/null",
+ exp: "ConfigFile: /dev/null",
+ },
+
+ {
+ cmd: "./gitea -c /dev/null test-cmd -h",
+ exp: "ConfigFile: /dev/null",
+ },
+ {
+ cmd: "./gitea test-cmd -c /dev/null -h",
+ exp: "ConfigFile: /dev/null",
+ },
+ {
+ cmd: "./gitea test-cmd -h -c /dev/null",
+ exp: "ConfigFile: /dev/null",
+ },
+
+ {
+ cmd: "./gitea -c /dev/null test-cmd help",
+ exp: "ConfigFile: /dev/null",
+ },
+ {
+ cmd: "./gitea test-cmd -c /dev/null help",
+ exp: "ConfigFile: /dev/null",
+ },
+ {
+ cmd: "./gitea test-cmd help -c /dev/null",
+ exp: "ConfigFile: /dev/null",
+ },
+
// parse paths
{
cmd: "./gitea test-cmd",
diff --git a/cmd/serv.go b/cmd/serv.go
index 8c6001e7274..38c79f68cd2 100644
--- a/cmd/serv.go
+++ b/cmd/serv.go
@@ -41,6 +41,7 @@ var CmdServ = &cli.Command{
Name: "serv",
Usage: "(internal) Should only be called by SSH shell",
Description: "Serv provides access auth for repositories",
+ Hidden: true, // Internal commands shouldn't be visible in help
Before: PrepareConsoleLoggerLevel(log.FATAL),
Action: runServ,
Flags: []cli.Flag{
diff --git a/contrib/autocompletion/README b/contrib/autocompletion/README
deleted file mode 100644
index 1defd219d8a..00000000000
--- a/contrib/autocompletion/README
+++ /dev/null
@@ -1,17 +0,0 @@
-Bash and Zsh completion
-=======================
-
-From within the gitea root run:
-
-```bash
-source contrib/autocompletion/bash_autocomplete
-```
-
-or for zsh run:
-
-```bash
-source contrib/autocompletion/zsh_autocomplete
-```
-
-These scripts will check if gitea is on the path and if so add autocompletion for `gitea`. Or if not autocompletion will work for `./gitea`.
-If gitea has been installed as a different program pass in the `PROG` environment variable to set the correct program name.
diff --git a/contrib/autocompletion/bash_autocomplete b/contrib/autocompletion/bash_autocomplete
deleted file mode 100755
index 5cb62f26a71..00000000000
--- a/contrib/autocompletion/bash_autocomplete
+++ /dev/null
@@ -1,30 +0,0 @@
-#! /bin/bash
-# Heavily inspired by https://github.com/urfave/cli
-
-_cli_bash_autocomplete() {
- if [[ "${COMP_WORDS[0]}" != "source" ]]; then
- local cur opts base
- COMPREPLY=()
- cur="${COMP_WORDS[COMP_CWORD]}"
- if [[ "$cur" == "-"* ]]; then
- opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
- else
- opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
- fi
- COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
- return 0
- fi
-}
-
-if [ -z "$PROG" ] && [ ! "$(command -v gitea &> /dev/null)" ] ; then
- complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete gitea
-elif [ -z "$PROG" ]; then
- complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete ./gitea
- complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete "$PWD/gitea"
-else
- complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete "$PROG"
- unset PROG
-fi
-
-
-
diff --git a/contrib/autocompletion/zsh_autocomplete b/contrib/autocompletion/zsh_autocomplete
deleted file mode 100644
index b3b40df503f..00000000000
--- a/contrib/autocompletion/zsh_autocomplete
+++ /dev/null
@@ -1,30 +0,0 @@
-#compdef ${PROG:=gitea}
-
-
-# Heavily inspired by https://github.com/urfave/cli
-
-_cli_zsh_autocomplete() {
-
- local -a opts
- local cur
- cur=${words[-1]}
- if [[ "$cur" == "-"* ]]; then
- opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
- else
- opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
- fi
-
- if [[ "${opts[1]}" != "" ]]; then
- _describe 'values' opts
- else
- _files
- fi
-
- return
-}
-
-if [ -z $PROG ] ; then
- compdef _cli_zsh_autocomplete gitea
-else
- compdef _cli_zsh_autocomplete $(basename $PROG)
-fi
diff --git a/flake.lock b/flake.lock
index da3f19bbd26..67f87dfaf62 100644
--- a/flake.lock
+++ b/flake.lock
@@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1747179050,
- "narHash": "sha256-qhFMmDkeJX9KJwr5H32f1r7Prs7XbQWtO0h3V0a0rFY=",
+ "lastModified": 1752480373,
+ "narHash": "sha256-JHQbm+OcGp32wAsXTE/FLYGNpb+4GLi5oTvCxwSoBOA=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "adaa24fbf46737f3f1b5497bf64bae750f82942e",
+ "rev": "62e0f05ede1da0d54515d4ea8ce9c733f12d9f08",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index 1b930649d08..e3375b82b35 100644
--- a/flake.nix
+++ b/flake.nix
@@ -26,7 +26,7 @@
# linting
python312
- poetry
+ uv
# backend
go_1_24
diff --git a/go.mod b/go.mod
index afe7c990e40..8b8d61dc657 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module code.gitea.io/gitea
-go 1.24.4
+go 1.24.5
// 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:
diff --git a/models/actions/run_job.go b/models/actions/run_job.go
index bad895036d1..e7fa21270c1 100644
--- a/models/actions/run_job.go
+++ b/models/actions/run_job.go
@@ -187,10 +187,10 @@ func AggregateJobStatus(jobs []*ActionRunJob) Status {
return StatusCancelled
case hasRunning:
return StatusRunning
- case hasFailure:
- return StatusFailure
case hasWaiting:
return StatusWaiting
+ case hasFailure:
+ return StatusFailure
case hasBlocked:
return StatusBlocked
default:
diff --git a/models/actions/run_job_status_test.go b/models/actions/run_job_status_test.go
index 2a5eb00a6f8..b9ae9f34bfd 100644
--- a/models/actions/run_job_status_test.go
+++ b/models/actions/run_job_status_test.go
@@ -64,7 +64,7 @@ func TestAggregateJobStatus(t *testing.T) {
{[]Status{StatusFailure, StatusSuccess}, StatusFailure},
{[]Status{StatusFailure, StatusSkipped}, StatusFailure},
{[]Status{StatusFailure, StatusCancelled}, StatusCancelled},
- {[]Status{StatusFailure, StatusWaiting}, StatusFailure},
+ {[]Status{StatusFailure, StatusWaiting}, StatusWaiting},
{[]Status{StatusFailure, StatusRunning}, StatusRunning},
{[]Status{StatusFailure, StatusBlocked}, StatusFailure},
diff --git a/models/asymkey/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go
index 39ec8936063..b85374e0735 100644
--- a/models/asymkey/gpg_key_commit_verification.go
+++ b/models/asymkey/gpg_key_commit_verification.go
@@ -15,25 +15,6 @@ import (
"github.com/ProtonMail/go-crypto/openpgp/packet"
)
-// __________________ ________ ____ __.
-// / _____/\______ \/ _____/ | |/ _|____ ___.__.
-// / \ ___ | ___/ \ ___ | <_/ __ < | |
-// \ \_\ \| | \ \_\ \ | | \ ___/\___ |
-// \______ /|____| \______ / |____|__ \___ > ____|
-// \/ \/ \/ \/\/
-// _________ .__ __
-// \_ ___ \ ____ _____ _____ |__|/ |_
-// / \ \/ / _ \ / \ / \| \ __\
-// \ \___( <_> ) Y Y \ Y Y \ || |
-// \______ /\____/|__|_| /__|_| /__||__|
-// \/ \/ \/
-// ____ ____ .__ _____.__ __ .__
-// \ \ / /___________|__|/ ____\__| ____ _____ _/ |_|__| ____ ____
-// \ Y // __ \_ __ \ \ __\| |/ ___\\__ \\ __\ |/ _ \ / \
-// \ /\ ___/| | \/ || | | \ \___ / __ \| | | ( <_> ) | \
-// \___/ \___ >__| |__||__| |__|\___ >____ /__| |__|\____/|___| /
-// \/ \/ \/ \/
-
// This file provides functions relating commit verification
// CommitVerification represents a commit validation of signature
@@ -41,8 +22,8 @@ type CommitVerification struct {
Verified bool
Warning bool
Reason string
- SigningUser *user_model.User
- CommittingUser *user_model.User
+ SigningUser *user_model.User // if Verified, then SigningUser is non-nil
+ CommittingUser *user_model.User // if Verified, then CommittingUser is non-nil
SigningEmail string
SigningKey *GPGKey
SigningSSHKey *PublicKey
diff --git a/models/asymkey/ssh_key.go b/models/asymkey/ssh_key.go
index 7a18732c327..dd94070fb9d 100644
--- a/models/asymkey/ssh_key.go
+++ b/models/asymkey/ssh_key.go
@@ -355,13 +355,13 @@ func AddPublicKeysBySource(ctx context.Context, usr *user_model.User, s *auth.So
return sshKeysNeedUpdate
}
-// SynchronizePublicKeys updates a users public keys. Returns true if there are changes.
+// SynchronizePublicKeys updates a user's public keys. Returns true if there are changes.
func SynchronizePublicKeys(ctx context.Context, usr *user_model.User, s *auth.Source, sshPublicKeys []string) bool {
var sshKeysNeedUpdate bool
log.Trace("synchronizePublicKeys[%s]: Handling Public SSH Key synchronization for user %s", s.Name, usr.Name)
- // Get Public Keys from DB with current LDAP source
+ // Get Public Keys from DB with the current auth source
var giteaKeys []string
keys, err := db.Find[PublicKey](ctx, FindPublicKeyOptions{
OwnerID: usr.ID,
diff --git a/models/asymkey/ssh_key_fingerprint.go b/models/asymkey/ssh_key_fingerprint.go
index 4dcfe1f2792..b666469ae87 100644
--- a/models/asymkey/ssh_key_fingerprint.go
+++ b/models/asymkey/ssh_key_fingerprint.go
@@ -13,9 +13,9 @@ import (
"xorm.io/builder"
)
-// The database is used in checkKeyFingerprint however most of these functions probably belong in a module
+// The database is used in checkKeyFingerprint. However, most of these functions probably belong in a module
-// checkKeyFingerprint only checks if key fingerprint has been used as public key,
+// checkKeyFingerprint only checks if key fingerprint has been used as a public key,
// it is OK to use same key as deploy key for multiple repositories/users.
func checkKeyFingerprint(ctx context.Context, fingerprint string) error {
has, err := db.Exist[PublicKey](ctx, builder.Eq{"fingerprint": fingerprint})
diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go
index c2b66901164..55af4e9036e 100644
--- a/models/auth/oauth2.go
+++ b/models/auth/oauth2.go
@@ -612,8 +612,8 @@ func (err ErrOAuthApplicationNotFound) Unwrap() error {
return util.ErrNotExist
}
-// GetActiveOAuth2SourceByName returns a OAuth2 AuthSource based on the given name
-func GetActiveOAuth2SourceByName(ctx context.Context, name string) (*Source, error) {
+// GetActiveOAuth2SourceByAuthName returns a OAuth2 AuthSource based on the given name
+func GetActiveOAuth2SourceByAuthName(ctx context.Context, name string) (*Source, error) {
authSource := new(Source)
has, err := db.GetEngine(ctx).Where("name = ? and type = ? and is_active = ?", name, OAuth2, true).Get(authSource)
if err != nil {
diff --git a/models/auth/source.go b/models/auth/source.go
index 7d7bc0f03c2..08cfc9615b0 100644
--- a/models/auth/source.go
+++ b/models/auth/source.go
@@ -334,7 +334,7 @@ func UpdateSource(ctx context.Context, source *Source) error {
err = registerableSource.RegisterSource()
if err != nil {
- // restore original values since we cannot update the provider it self
+ // restore original values since we cannot update the provider itself
if _, err := db.GetEngine(ctx).ID(source.ID).AllCols().Update(originalSource); err != nil {
log.Error("UpdateSource: Error while wrapOpenIDConnectInitializeError: %v", err)
}
diff --git a/models/fixtures/public_key.yml b/models/fixtures/public_key.yml
index ae620ee2d19..856b0e3fb29 100644
--- a/models/fixtures/public_key.yml
+++ b/models/fixtures/public_key.yml
@@ -9,3 +9,4 @@
created_unix: 1559593109
updated_unix: 1565224552
login_source_id: 0
+ verified: false
diff --git a/models/git/branch.go b/models/git/branch.go
index 07c94a8ba5b..6021e1101f6 100644
--- a/models/git/branch.go
+++ b/models/git/branch.go
@@ -472,7 +472,7 @@ type RecentlyPushedNewBranch struct {
// if opts.CommitAfterUnix is 0, we will find the branches that were committed to in the last 2 hours
// if opts.ListOptions is not set, we will only display top 2 latest branches.
// Protected branches will be skipped since they are unlikely to be used to create new PRs.
-func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, opts *FindRecentlyPushedNewBranchesOptions) ([]*RecentlyPushedNewBranch, error) {
+func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, opts FindRecentlyPushedNewBranchesOptions) ([]*RecentlyPushedNewBranch, error) {
if doer == nil {
return []*RecentlyPushedNewBranch{}, nil
}
diff --git a/models/issues/issue_xref.go b/models/issues/issue_xref.go
index e2e35859df1..f8495929cf9 100644
--- a/models/issues/issue_xref.go
+++ b/models/issues/issue_xref.go
@@ -235,7 +235,7 @@ func (issue *Issue) verifyReferencedIssue(stdCtx context.Context, ctx *crossRefe
// AddCrossReferences add cross references
func (c *Comment) AddCrossReferences(stdCtx context.Context, doer *user_model.User, removeOld bool) error {
- if c.Type != CommentTypeCode && c.Type != CommentTypeComment {
+ if !c.Type.HasContentSupport() {
return nil
}
if err := c.LoadIssue(stdCtx); err != nil {
diff --git a/models/issues/pull.go b/models/issues/pull.go
index 0ff32e24733..4c25b6f0c84 100644
--- a/models/issues/pull.go
+++ b/models/issues/pull.go
@@ -413,8 +413,8 @@ func (pr *PullRequest) getReviewedByLines(ctx context.Context, writer io.Writer)
return committer.Commit()
}
-// GetGitRefName returns git ref for hidden pull request branch
-func (pr *PullRequest) GetGitRefName() string {
+// GetGitHeadRefName returns git ref for hidden pull request branch
+func (pr *PullRequest) GetGitHeadRefName() string {
return fmt.Sprintf("%s%d/head", git.PullPrefix, pr.Index)
}
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 34d1bf55f65..2403b3b40ba 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -652,7 +652,13 @@ func (repo *Repository) AllowsPulls(ctx context.Context) bool {
}
// CanEnableEditor returns true if repository meets the requirements of web editor.
+// FIXME: most CanEnableEditor calls should be replaced with CanContentChange
+// And all other like CanCreateBranch / CanEnablePulls should also be updated
func (repo *Repository) CanEnableEditor() bool {
+ return repo.CanContentChange()
+}
+
+func (repo *Repository) CanContentChange() bool {
return !repo.IsMirror && !repo.IsArchived
}
diff --git a/models/user/setting_keys.go b/models/user/setting_options.go
similarity index 76%
rename from models/user/setting_keys.go
rename to models/user/setting_options.go
index 2c2ed078bea..7be50393296 100644
--- a/models/user/setting_keys.go
+++ b/models/user/setting_options.go
@@ -21,4 +21,9 @@ const (
SignupUserAgent = "signup.user_agent"
SettingsKeyCodeViewShowFileTree = "code_view.show_file_tree"
+
+ SettingsKeyEmailNotificationGiteaActions = "email_notification.gitea_actions"
+ SettingEmailNotificationGiteaActionsAll = "all"
+ SettingEmailNotificationGiteaActionsFailureOnly = "failure-only" // Default for actions email preference
+ SettingEmailNotificationGiteaActionsDisabled = "disabled"
)
diff --git a/models/user/user.go b/models/user/user.go
index 449163ab0f8..9cad1cc7c9d 100644
--- a/models/user/user.go
+++ b/models/user/user.go
@@ -1176,12 +1176,6 @@ func ValidateCommitsWithEmails(ctx context.Context, oldCommits []*git.Commit) ([
for _, c := range oldCommits {
user := emailUserMap.GetByEmail(c.Author.Email) // FIXME: why ValidateCommitsWithEmails uses "Author", but ParseCommitsWithSignature uses "Committer"?
- if user == nil {
- user = &User{
- Name: c.Author.Name,
- Email: c.Author.Email,
- }
- }
newCommits = append(newCommits, &UserCommit{
User: user,
Commit: c,
@@ -1205,12 +1199,14 @@ func GetUsersByEmails(ctx context.Context, emails []string) (*EmailUserMap, erro
needCheckEmails := make(container.Set[string])
needCheckUserNames := make(container.Set[string])
+ noReplyAddressSuffix := "@" + strings.ToLower(setting.Service.NoReplyAddress)
for _, email := range emails {
- if strings.HasSuffix(email, "@"+setting.Service.NoReplyAddress) {
- username := strings.TrimSuffix(email, "@"+setting.Service.NoReplyAddress)
- needCheckUserNames.Add(strings.ToLower(username))
+ emailLower := strings.ToLower(email)
+ if noReplyUserNameLower, ok := strings.CutSuffix(emailLower, noReplyAddressSuffix); ok {
+ needCheckUserNames.Add(noReplyUserNameLower)
+ needCheckEmails.Add(emailLower)
} else {
- needCheckEmails.Add(strings.ToLower(email))
+ needCheckEmails.Add(emailLower)
}
}
diff --git a/models/user/user_test.go b/models/user/user_test.go
index a2597ba3f5e..7944fc4b734 100644
--- a/models/user/user_test.go
+++ b/models/user/user_test.go
@@ -85,6 +85,11 @@ func TestUserEmails(t *testing.T) {
testGetUserByEmail(t, c.Email, c.UID)
})
}
+
+ t.Run("NoReplyConflict", func(t *testing.T) {
+ setting.Service.NoReplyAddress = "example.com"
+ testGetUserByEmail(t, "user1-2@example.COM", 1)
+ })
})
}
diff --git a/modules/actions/artifacts.go b/modules/actions/artifacts.go
index 4d074435efc..d28726e8993 100644
--- a/modules/actions/artifacts.go
+++ b/modules/actions/artifacts.go
@@ -20,7 +20,7 @@ func IsArtifactV4(art *actions_model.ActionArtifact) bool {
func DownloadArtifactV4ServeDirectOnly(ctx *context.Base, art *actions_model.ActionArtifact) (bool, error) {
if setting.Actions.ArtifactStorage.ServeDirect() {
- u, err := storage.ActionsArtifacts.URL(art.StoragePath, art.ArtifactPath, nil)
+ u, err := storage.ActionsArtifacts.URL(art.StoragePath, art.ArtifactPath, ctx.Req.Method, nil)
if u != nil && err == nil {
ctx.Redirect(u.String(), http.StatusFound)
return true, nil
diff --git a/modules/git/attribute/attribute.go b/modules/git/attribute/attribute.go
index adf323ef41c..9c01cb339e0 100644
--- a/modules/git/attribute/attribute.go
+++ b/modules/git/attribute/attribute.go
@@ -20,6 +20,7 @@ const (
GitlabLanguage = "gitlab-language"
Lockable = "lockable"
Filter = "filter"
+ Diff = "diff"
)
var LinguistAttributes = []string{
diff --git a/modules/git/commit.go b/modules/git/commit.go
index ed4876e7b3e..aae40c575bc 100644
--- a/modules/git/commit.go
+++ b/modules/git/commit.go
@@ -22,9 +22,9 @@ import (
type Commit struct {
Tree // FIXME: bad design, this field can be nil if the commit is from "last commit cache"
- ID ObjectID // The ID of this commit object
- Author *Signature
- Committer *Signature
+ ID ObjectID
+ Author *Signature // never nil
+ Committer *Signature // never nil
CommitMessage string
Signature *CommitSignature
diff --git a/modules/git/commit_info.go b/modules/git/commit_info.go
index c046acbb508..b44e9fa51da 100644
--- a/modules/git/commit_info.go
+++ b/modules/git/commit_info.go
@@ -3,9 +3,24 @@
package git
+import "path"
+
// CommitInfo describes the first commit with the provided entry
type CommitInfo struct {
Entry *TreeEntry
Commit *Commit
SubmoduleFile *CommitSubmoduleFile
}
+
+func getCommitInfoSubmoduleFile(repoLink string, entry *TreeEntry, commit *Commit, treePathDir string) (*CommitSubmoduleFile, error) {
+ fullPath := path.Join(treePathDir, entry.Name())
+ submodule, err := commit.GetSubModule(fullPath)
+ if err != nil {
+ return nil, err
+ }
+ if submodule == nil {
+ // unable to find submodule from ".gitmodules" file
+ return NewCommitSubmoduleFile(repoLink, fullPath, "", entry.ID.String()), nil
+ }
+ return NewCommitSubmoduleFile(repoLink, fullPath, submodule.URL, entry.ID.String()), nil
+}
diff --git a/modules/git/commit_info_gogit.go b/modules/git/commit_info_gogit.go
index 314c2df7284..7e03e634a03 100644
--- a/modules/git/commit_info_gogit.go
+++ b/modules/git/commit_info_gogit.go
@@ -16,7 +16,7 @@ import (
)
// GetCommitsInfo gets information of all commits that are corresponding to these entries
-func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
+func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
entryPaths := make([]string, len(tes)+1)
// Get the commit for the treePath itself
entryPaths[0] = ""
@@ -71,22 +71,12 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
commitsInfo[i].Commit = entryCommit
}
- // If the entry is a submodule add a submodule file for this
+ // If the entry is a submodule, add a submodule file for this
if entry.IsSubModule() {
- subModuleURL := ""
- var fullPath string
- if len(treePath) > 0 {
- fullPath = treePath + "/" + entry.Name()
- } else {
- fullPath = entry.Name()
- }
- if subModule, err := commit.GetSubModule(fullPath); err != nil {
+ commitsInfo[i].SubmoduleFile, err = getCommitInfoSubmoduleFile(repoLink, entry, commit, treePath)
+ if err != nil {
return nil, nil, err
- } else if subModule != nil {
- subModuleURL = subModule.URL
}
- subModuleFile := NewCommitSubmoduleFile(subModuleURL, entry.ID.String())
- commitsInfo[i].SubmoduleFile = subModuleFile
}
}
diff --git a/modules/git/commit_info_nogogit.go b/modules/git/commit_info_nogogit.go
index 1b45fc8a6c3..161edb7e966 100644
--- a/modules/git/commit_info_nogogit.go
+++ b/modules/git/commit_info_nogogit.go
@@ -15,7 +15,7 @@ import (
)
// GetCommitsInfo gets information of all commits that are corresponding to these entries
-func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
+func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
entryPaths := make([]string, len(tes)+1)
// Get the commit for the treePath itself
entryPaths[0] = ""
@@ -62,22 +62,12 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
log.Debug("missing commit for %s", entry.Name())
}
- // If the entry is a submodule add a submodule file for this
+ // If the entry is a submodule, add a submodule file for this
if entry.IsSubModule() {
- subModuleURL := ""
- var fullPath string
- if len(treePath) > 0 {
- fullPath = treePath + "/" + entry.Name()
- } else {
- fullPath = entry.Name()
- }
- if subModule, err := commit.GetSubModule(fullPath); err != nil {
+ commitsInfo[i].SubmoduleFile, err = getCommitInfoSubmoduleFile(repoLink, entry, commit, treePath)
+ if err != nil {
return nil, nil, err
- } else if subModule != nil {
- subModuleURL = subModule.URL
}
- subModuleFile := NewCommitSubmoduleFile(subModuleURL, entry.ID.String())
- commitsInfo[i].SubmoduleFile = subModuleFile
}
}
diff --git a/modules/git/commit_info_test.go b/modules/git/commit_info_test.go
index ba518ab2455..5f2eb5e1292 100644
--- a/modules/git/commit_info_test.go
+++ b/modules/git/commit_info_test.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
const (
@@ -82,7 +83,7 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
}
// FIXME: Context.TODO() - if graceful has started we should use its Shutdown context otherwise use install signals in TestMain.
- commitsInfo, treeCommit, err := entries.GetCommitsInfo(t.Context(), commit, testCase.Path)
+ commitsInfo, treeCommit, err := entries.GetCommitsInfo(t.Context(), "/any/repo-link", commit, testCase.Path)
assert.NoError(t, err, "Unable to get commit information for entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err)
if err != nil {
t.FailNow()
@@ -120,6 +121,23 @@ func TestEntries_GetCommitsInfo(t *testing.T) {
defer clonedRepo1.Close()
testGetCommitsInfo(t, clonedRepo1)
+
+ t.Run("NonExistingSubmoduleAsNil", func(t *testing.T) {
+ commit, err := bareRepo1.GetCommit("HEAD")
+ require.NoError(t, err)
+ tree, err := commit.GetTreeEntryByPath("file1.txt")
+ require.NoError(t, err)
+ cisf, err := getCommitInfoSubmoduleFile("/any/repo-link", tree, commit, "")
+ require.NoError(t, err)
+ assert.Equal(t, &CommitSubmoduleFile{
+ repoLink: "/any/repo-link",
+ fullPath: "file1.txt",
+ refURL: "",
+ refID: "e2129701f1a4d54dc44f03c93bca0a2aec7c5449",
+ }, cisf)
+ // since there is no refURL, it means that the submodule info doesn't exist, so it won't have a web link
+ assert.Nil(t, cisf.SubmoduleWebLinkTree(t.Context()))
+ })
}
func BenchmarkEntries_GetCommitsInfo(b *testing.B) {
@@ -159,7 +177,7 @@ func BenchmarkEntries_GetCommitsInfo(b *testing.B) {
b.ResetTimer()
b.Run(benchmark.name, func(b *testing.B) {
for b.Loop() {
- _, _, err := entries.GetCommitsInfo(b.Context(), commit, "")
+ _, _, err := entries.GetCommitsInfo(b.Context(), "/any/repo-link", commit, "")
if err != nil {
b.Fatal(err)
}
diff --git a/modules/git/commit_submodule.go b/modules/git/commit_submodule.go
index 031fd4e5d02..ff253b7ecab 100644
--- a/modules/git/commit_submodule.go
+++ b/modules/git/commit_submodule.go
@@ -35,7 +35,8 @@ func (c *Commit) GetSubModules() (*ObjectCache[*SubModule], error) {
return c.submoduleCache, nil
}
-// GetSubModule get the submodule according entry name
+// GetSubModule gets the submodule by the entry name.
+// It returns "nil, nil" if the submodule does not exist, caller should always remember to check the "nil"
func (c *Commit) GetSubModule(entryName string) (*SubModule, error) {
modules, err := c.GetSubModules()
if err != nil {
diff --git a/modules/git/commit_submodule_file.go b/modules/git/commit_submodule_file.go
index 729401f7521..a3f63710de2 100644
--- a/modules/git/commit_submodule_file.go
+++ b/modules/git/commit_submodule_file.go
@@ -6,49 +6,64 @@ package git
import (
"context"
+ "path"
+ "strings"
giturl "code.gitea.io/gitea/modules/git/url"
+ "code.gitea.io/gitea/modules/util"
)
// CommitSubmoduleFile represents a file with submodule type.
type CommitSubmoduleFile struct {
- refURL string
- parsedURL *giturl.RepositoryURL
- parsed bool
- refID string
- repoLink string
+ repoLink string
+ fullPath string
+ refURL string
+ refID string
+
+ parsed bool
+ parsedTargetLink string
}
// NewCommitSubmoduleFile create a new submodule file
-func NewCommitSubmoduleFile(refURL, refID string) *CommitSubmoduleFile {
- return &CommitSubmoduleFile{refURL: refURL, refID: refID}
+func NewCommitSubmoduleFile(repoLink, fullPath, refURL, refID string) *CommitSubmoduleFile {
+ return &CommitSubmoduleFile{repoLink: repoLink, fullPath: fullPath, refURL: refURL, refID: refID}
}
+// RefID returns the commit ID of the submodule, it returns empty string for nil receiver
func (sf *CommitSubmoduleFile) RefID() string {
- return sf.refID // this function is only used in templates
+ if sf == nil {
+ return ""
+ }
+ return sf.refID
}
-// SubmoduleWebLink tries to make some web links for a submodule, it also works on "nil" receiver
-func (sf *CommitSubmoduleFile) SubmoduleWebLink(ctx context.Context, optCommitID ...string) *SubmoduleWebLink {
- if sf == nil {
+func (sf *CommitSubmoduleFile) getWebLinkInTargetRepo(ctx context.Context, moreLinkPath string) *SubmoduleWebLink {
+ if sf == nil || sf.refURL == "" {
return nil
}
+ if strings.HasPrefix(sf.refURL, "../") {
+ targetLink := path.Join(sf.repoLink, path.Dir(sf.fullPath), sf.refURL)
+ return &SubmoduleWebLink{RepoWebLink: targetLink, CommitWebLink: targetLink + moreLinkPath}
+ }
if !sf.parsed {
sf.parsed = true
parsedURL, err := giturl.ParseRepositoryURL(ctx, sf.refURL)
if err != nil {
return nil
}
- sf.parsedURL = parsedURL
- sf.repoLink = giturl.MakeRepositoryWebLink(sf.parsedURL)
+ sf.parsedTargetLink = giturl.MakeRepositoryWebLink(parsedURL)
}
- var commitLink string
- if len(optCommitID) == 2 {
- commitLink = sf.repoLink + "/compare/" + optCommitID[0] + "..." + optCommitID[1]
- } else if len(optCommitID) == 1 {
- commitLink = sf.repoLink + "/tree/" + optCommitID[0]
- } else {
- commitLink = sf.repoLink + "/tree/" + sf.refID
- }
- return &SubmoduleWebLink{RepoWebLink: sf.repoLink, CommitWebLink: commitLink}
+ return &SubmoduleWebLink{RepoWebLink: sf.parsedTargetLink, CommitWebLink: sf.parsedTargetLink + moreLinkPath}
+}
+
+// SubmoduleWebLinkTree tries to make the submodule's tree link in its own repo, it also works on "nil" receiver
+// It returns nil if the submodule does not have a valid URL or is nil
+func (sf *CommitSubmoduleFile) SubmoduleWebLinkTree(ctx context.Context, optCommitID ...string) *SubmoduleWebLink {
+ return sf.getWebLinkInTargetRepo(ctx, "/tree/"+util.OptionalArg(optCommitID, sf.RefID()))
+}
+
+// SubmoduleWebLinkCompare tries to make the submodule's compare link in its own repo, it also works on "nil" receiver
+// It returns nil if the submodule does not have a valid URL or is nil
+func (sf *CommitSubmoduleFile) SubmoduleWebLinkCompare(ctx context.Context, commitID1, commitID2 string) *SubmoduleWebLink {
+ return sf.getWebLinkInTargetRepo(ctx, "/compare/"+commitID1+"..."+commitID2)
}
diff --git a/modules/git/commit_submodule_file_test.go b/modules/git/commit_submodule_file_test.go
index 6581fa87127..203939fb1b5 100644
--- a/modules/git/commit_submodule_file_test.go
+++ b/modules/git/commit_submodule_file_test.go
@@ -10,20 +10,31 @@ import (
)
func TestCommitSubmoduleLink(t *testing.T) {
- sf := NewCommitSubmoduleFile("git@github.com:user/repo.git", "aaaa")
+ assert.Nil(t, (*CommitSubmoduleFile)(nil).SubmoduleWebLinkTree(t.Context()))
+ assert.Nil(t, (*CommitSubmoduleFile)(nil).SubmoduleWebLinkCompare(t.Context(), "", ""))
+ assert.Nil(t, (&CommitSubmoduleFile{}).SubmoduleWebLinkTree(t.Context()))
+ assert.Nil(t, (&CommitSubmoduleFile{}).SubmoduleWebLinkCompare(t.Context(), "", ""))
- wl := sf.SubmoduleWebLink(t.Context())
- assert.Equal(t, "https://github.com/user/repo", wl.RepoWebLink)
- assert.Equal(t, "https://github.com/user/repo/tree/aaaa", wl.CommitWebLink)
+ t.Run("GitHubRepo", func(t *testing.T) {
+ sf := NewCommitSubmoduleFile("/any/repo-link", "full-path", "git@github.com:user/repo.git", "aaaa")
+ wl := sf.SubmoduleWebLinkTree(t.Context())
+ assert.Equal(t, "https://github.com/user/repo", wl.RepoWebLink)
+ assert.Equal(t, "https://github.com/user/repo/tree/aaaa", wl.CommitWebLink)
- wl = sf.SubmoduleWebLink(t.Context(), "1111")
- assert.Equal(t, "https://github.com/user/repo", wl.RepoWebLink)
- assert.Equal(t, "https://github.com/user/repo/tree/1111", wl.CommitWebLink)
+ wl = sf.SubmoduleWebLinkCompare(t.Context(), "1111", "2222")
+ assert.Equal(t, "https://github.com/user/repo", wl.RepoWebLink)
+ assert.Equal(t, "https://github.com/user/repo/compare/1111...2222", wl.CommitWebLink)
+ })
- wl = sf.SubmoduleWebLink(t.Context(), "1111", "2222")
- assert.Equal(t, "https://github.com/user/repo", wl.RepoWebLink)
- assert.Equal(t, "https://github.com/user/repo/compare/1111...2222", wl.CommitWebLink)
+ t.Run("RelativePath", func(t *testing.T) {
+ sf := NewCommitSubmoduleFile("/subpath/any/repo-home-link", "full-path", "../../user/repo", "aaaa")
+ wl := sf.SubmoduleWebLinkTree(t.Context())
+ assert.Equal(t, "/subpath/user/repo", wl.RepoWebLink)
+ assert.Equal(t, "/subpath/user/repo/tree/aaaa", wl.CommitWebLink)
- wl = (*CommitSubmoduleFile)(nil).SubmoduleWebLink(t.Context())
- assert.Nil(t, wl)
+ sf = NewCommitSubmoduleFile("/subpath/any/repo-home-link", "dir/submodule", "../../../user/repo", "aaaa")
+ wl = sf.SubmoduleWebLinkCompare(t.Context(), "1111", "2222")
+ assert.Equal(t, "/subpath/user/repo", wl.RepoWebLink)
+ assert.Equal(t, "/subpath/user/repo/compare/1111...2222", wl.CommitWebLink)
+ })
}
diff --git a/modules/git/diff.go b/modules/git/diff.go
index c4df6b80633..35d115be0e5 100644
--- a/modules/git/diff.go
+++ b/modules/git/diff.go
@@ -99,9 +99,9 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
return nil
}
-// ParseDiffHunkString parse the diffhunk content and return
-func ParseDiffHunkString(diffhunk string) (leftLine, leftHunk, rightLine, righHunk int) {
- ss := strings.Split(diffhunk, "@@")
+// ParseDiffHunkString parse the diff hunk content and return
+func ParseDiffHunkString(diffHunk string) (leftLine, leftHunk, rightLine, rightHunk int) {
+ ss := strings.Split(diffHunk, "@@")
ranges := strings.Split(ss[1][1:], " ")
leftRange := strings.Split(ranges[0], ",")
leftLine, _ = strconv.Atoi(leftRange[0][1:])
@@ -112,14 +112,19 @@ func ParseDiffHunkString(diffhunk string) (leftLine, leftHunk, rightLine, righHu
rightRange := strings.Split(ranges[1], ",")
rightLine, _ = strconv.Atoi(rightRange[0])
if len(rightRange) > 1 {
- righHunk, _ = strconv.Atoi(rightRange[1])
+ rightHunk, _ = strconv.Atoi(rightRange[1])
}
} else {
- log.Debug("Parse line number failed: %v", diffhunk)
+ log.Debug("Parse line number failed: %v", diffHunk)
rightLine = leftLine
- righHunk = leftHunk
+ rightHunk = leftHunk
}
- return leftLine, leftHunk, rightLine, righHunk
+ if rightLine == 0 {
+ // FIXME: GIT-DIFF-CUT-BUG search this tag to see details
+ // this is only a hacky patch, the rightLine&rightHunk might still be incorrect in some cases.
+ rightLine++
+ }
+ return leftLine, leftHunk, rightLine, rightHunk
}
// Example: @@ -1,8 +1,9 @@ => [..., 1, 8, 1, 9]
@@ -270,6 +275,12 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi
oldNumOfLines++
}
}
+
+ // "git diff" outputs "@@ -1 +1,3 @@" for "OLD" => "A\nB\nC"
+ // FIXME: GIT-DIFF-CUT-BUG But there is a bug in CutDiffAroundLine, then the "Patch" stored in the comment model becomes "@@ -1,1 +0,4 @@"
+ // It may generate incorrect results for difference cases, for example: delete 2 line add 1 line, delete 2 line add 2 line etc, need to double check.
+ // For example: "L1\nL2" => "A\nB", then the patch shows "L2" as line 1 on the left (deleted part)
+
// construct the new hunk header
newHunk[headerLines] = fmt.Sprintf("@@ -%d,%d +%d,%d @@",
oldBegin, oldNumOfLines, newBegin, newNumOfLines)
diff --git a/modules/migration/pullrequest.go b/modules/migration/pullrequest.go
index fbfdff0315e..cccab3fd7e5 100644
--- a/modules/migration/pullrequest.go
+++ b/modules/migration/pullrequest.go
@@ -49,8 +49,8 @@ func (p *PullRequest) IsForkPullRequest() bool {
return p.Head.RepoFullName() != p.Base.RepoFullName()
}
-// GetGitRefName returns pull request relative path to head
-func (p PullRequest) GetGitRefName() string {
+// GetGitHeadRefName returns pull request relative path to head
+func (p PullRequest) GetGitHeadRefName() string {
return fmt.Sprintf("%s%d/head", git.PullPrefix, p.Number)
}
diff --git a/modules/optional/option.go b/modules/optional/option.go
index 6075c6347e0..cbecf869873 100644
--- a/modules/optional/option.go
+++ b/modules/optional/option.go
@@ -28,6 +28,13 @@ func FromPtr[T any](v *T) Option[T] {
return Some(*v)
}
+func FromMapLookup[K comparable, V any](m map[K]V, k K) Option[V] {
+ if v, ok := m[k]; ok {
+ return Some(v)
+ }
+ return None[V]()
+}
+
func FromNonDefault[T comparable](v T) Option[T] {
var zero T
if v == zero {
diff --git a/modules/optional/option_test.go b/modules/optional/option_test.go
index f600ff5a2c7..ea80a2e3cb4 100644
--- a/modules/optional/option_test.go
+++ b/modules/optional/option_test.go
@@ -56,6 +56,12 @@ func TestOption(t *testing.T) {
opt3 := optional.FromNonDefault(1)
assert.True(t, opt3.Has())
assert.Equal(t, int(1), opt3.Value())
+
+ opt4 := optional.FromMapLookup(map[string]int{"a": 1}, "a")
+ assert.True(t, opt4.Has())
+ assert.Equal(t, 1, opt4.Value())
+ opt4 = optional.FromMapLookup(map[string]int{"a": 1}, "b")
+ assert.False(t, opt4.Has())
}
func Test_ParseBool(t *testing.T) {
diff --git a/modules/packages/content_store.go b/modules/packages/content_store.go
index dadb7eaefcb..57974515e2c 100644
--- a/modules/packages/content_store.go
+++ b/modules/packages/content_store.go
@@ -36,8 +36,8 @@ func (s *ContentStore) ShouldServeDirect() bool {
return setting.Packages.Storage.ServeDirect()
}
-func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename string, reqParams url.Values) (*url.URL, error) {
- return s.store.URL(KeyToRelativePath(key), filename, reqParams)
+func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename, method string, reqParams url.Values) (*url.URL, error) {
+ return s.store.URL(KeyToRelativePath(key), filename, method, reqParams)
}
// FIXME: Workaround to be removed in v1.20
diff --git a/modules/session/mem.go b/modules/session/mem.go
new file mode 100644
index 00000000000..bb807bc91a1
--- /dev/null
+++ b/modules/session/mem.go
@@ -0,0 +1,68 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package session
+
+import (
+ "bytes"
+ "encoding/gob"
+ "net/http"
+
+ "gitea.com/go-chi/session"
+)
+
+type mockMemRawStore struct {
+ s *session.MemStore
+}
+
+var _ session.RawStore = (*mockMemRawStore)(nil)
+
+func (m *mockMemRawStore) Set(k, v any) error {
+ // We need to use gob to encode the value, to make it have the same behavior as other stores and catch abuses.
+ // Because gob needs to "Register" the type before it can encode it, and it's unable to decode a struct to "any" so use a map to help to decode the value.
+ var buf bytes.Buffer
+ if err := gob.NewEncoder(&buf).Encode(map[string]any{"v": v}); err != nil {
+ return err
+ }
+ return m.s.Set(k, buf.Bytes())
+}
+
+func (m *mockMemRawStore) Get(k any) (ret any) {
+ v, ok := m.s.Get(k).([]byte)
+ if !ok {
+ return nil
+ }
+ var w map[string]any
+ _ = gob.NewDecoder(bytes.NewBuffer(v)).Decode(&w)
+ return w["v"]
+}
+
+func (m *mockMemRawStore) Delete(k any) error {
+ return m.s.Delete(k)
+}
+
+func (m *mockMemRawStore) ID() string {
+ return m.s.ID()
+}
+
+func (m *mockMemRawStore) Release() error {
+ return m.s.Release()
+}
+
+func (m *mockMemRawStore) Flush() error {
+ return m.s.Flush()
+}
+
+type mockMemStore struct {
+ *mockMemRawStore
+}
+
+var _ Store = (*mockMemStore)(nil)
+
+func (m mockMemStore) Destroy(writer http.ResponseWriter, request *http.Request) error {
+ return nil
+}
+
+func NewMockMemStore(sid string) Store {
+ return &mockMemStore{&mockMemRawStore{session.NewMemStore(sid)}}
+}
diff --git a/modules/session/mock.go b/modules/session/mock.go
deleted file mode 100644
index 95231a3655f..00000000000
--- a/modules/session/mock.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2024 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package session
-
-import (
- "net/http"
-
- "gitea.com/go-chi/session"
-)
-
-type MockStore struct {
- *session.MemStore
-}
-
-func (m *MockStore) Destroy(writer http.ResponseWriter, request *http.Request) error {
- return nil
-}
-
-type mockStoreContextKeyStruct struct{}
-
-var MockStoreContextKey = mockStoreContextKeyStruct{}
-
-func NewMockStore(sid string) *MockStore {
- return &MockStore{session.NewMemStore(sid)}
-}
diff --git a/modules/session/store.go b/modules/session/store.go
index 09d1ef44dd7..0217ed97aca 100644
--- a/modules/session/store.go
+++ b/modules/session/store.go
@@ -11,25 +11,25 @@ import (
"gitea.com/go-chi/session"
)
-// Store represents a session store
+type RawStore = session.RawStore
+
type Store interface {
- Get(any) any
- Set(any, any) error
- Delete(any) error
- ID() string
- Release() error
- Flush() error
+ RawStore
Destroy(http.ResponseWriter, *http.Request) error
}
+type mockStoreContextKeyStruct struct{}
+
+var MockStoreContextKey = mockStoreContextKeyStruct{}
+
// RegenerateSession regenerates the underlying session and returns the new store
func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, error) {
for _, f := range BeforeRegenerateSession {
f(resp, req)
}
if setting.IsInTesting {
- if store, ok := req.Context().Value(MockStoreContextKey).(*MockStore); ok {
- return store, nil
+ if store := req.Context().Value(MockStoreContextKey); store != nil {
+ return store.(Store), nil
}
}
return session.RegenerateSession(resp, req)
@@ -37,8 +37,8 @@ func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, erro
func GetContextSession(req *http.Request) Store {
if setting.IsInTesting {
- if store, ok := req.Context().Value(MockStoreContextKey).(*MockStore); ok {
- return store
+ if store := req.Context().Value(MockStoreContextKey); store != nil {
+ return store.(Store)
}
}
return session.GetSession(req)
diff --git a/modules/session/virtual.go b/modules/session/virtual.go
index 80352b6e721..2e29b5fc6f6 100644
--- a/modules/session/virtual.go
+++ b/modules/session/virtual.go
@@ -22,8 +22,8 @@ type VirtualSessionProvider struct {
provider session.Provider
}
-// Init initializes the cookie session provider with given root path.
-func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error {
+// Init initializes the cookie session provider with the given config.
+func (o *VirtualSessionProvider) Init(gcLifetime int64, config string) error {
var opts session.Options
if err := json.Unmarshal([]byte(config), &opts); err != nil {
return err
@@ -52,7 +52,7 @@ func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error {
default:
return fmt.Errorf("VirtualSessionProvider: Unknown Provider: %s", opts.Provider)
}
- return o.provider.Init(gclifetime, opts.ProviderConfig)
+ return o.provider.Init(gcLifetime, opts.ProviderConfig)
}
// Read returns raw session store by session ID.
diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go
index 0d3e63e0b4a..1a88f3cb082 100644
--- a/modules/setting/oauth2.go
+++ b/modules/setting/oauth2.go
@@ -12,7 +12,7 @@ import (
"code.gitea.io/gitea/modules/log"
)
-// OAuth2UsernameType is enum describing the way gitea 'name' should be generated from oauth2 data
+// OAuth2UsernameType is enum describing the way gitea generates its 'username' from oauth2 data
type OAuth2UsernameType string
const (
diff --git a/modules/setting/server.go b/modules/setting/server.go
index 8a22f6a8448..38e166e02ad 100644
--- a/modules/setting/server.go
+++ b/modules/setting/server.go
@@ -275,7 +275,7 @@ func loadServerFrom(rootCfg ConfigProvider) {
HTTPAddr = filepath.Join(AppWorkPath, HTTPAddr)
}
default:
- log.Fatal("Invalid PROTOCOL %q", Protocol)
+ log.Fatal("Invalid PROTOCOL %q", protocolCfg)
}
UseProxyProtocol = sec.Key("USE_PROXY_PROTOCOL").MustBool(false)
ProxyProtocolTLSBridging = sec.Key("PROXY_PROTOCOL_TLS_BRIDGING").MustBool(false)
diff --git a/modules/storage/azureblob.go b/modules/storage/azureblob.go
index 837afd0ba62..6860d81131b 100644
--- a/modules/storage/azureblob.go
+++ b/modules/storage/azureblob.go
@@ -247,7 +247,7 @@ func (a *AzureBlobStorage) Delete(path string) error {
}
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
-func (a *AzureBlobStorage) URL(path, name string, reqParams url.Values) (*url.URL, error) {
+func (a *AzureBlobStorage) URL(path, name, _ string, reqParams url.Values) (*url.URL, error) {
blobClient := a.getBlobClient(path)
startTime := time.Now()
diff --git a/modules/storage/helper.go b/modules/storage/helper.go
index 9e6cceb537d..f6c3d5eebbc 100644
--- a/modules/storage/helper.go
+++ b/modules/storage/helper.go
@@ -30,7 +30,7 @@ func (s discardStorage) Delete(_ string) error {
return fmt.Errorf("%s", s)
}
-func (s discardStorage) URL(_, _ string, _ url.Values) (*url.URL, error) {
+func (s discardStorage) URL(_, _, _ string, _ url.Values) (*url.URL, error) {
return nil, fmt.Errorf("%s", s)
}
diff --git a/modules/storage/helper_test.go b/modules/storage/helper_test.go
index 62ebd8753c8..3cba1e13c01 100644
--- a/modules/storage/helper_test.go
+++ b/modules/storage/helper_test.go
@@ -37,7 +37,7 @@ func Test_discardStorage(t *testing.T) {
assert.Error(t, err, string(tt))
}
{
- got, err := tt.URL("path", "name", nil)
+ got, err := tt.URL("path", "name", "GET", nil)
assert.Nil(t, got)
assert.Errorf(t, err, string(tt))
}
diff --git a/modules/storage/local.go b/modules/storage/local.go
index 00c7f668aa2..8a1776f606d 100644
--- a/modules/storage/local.go
+++ b/modules/storage/local.go
@@ -114,7 +114,7 @@ func (l *LocalStorage) Delete(path string) error {
}
// URL gets the redirect URL to a file
-func (l *LocalStorage) URL(path, name string, reqParams url.Values) (*url.URL, error) {
+func (l *LocalStorage) URL(path, name, _ string, reqParams url.Values) (*url.URL, error) {
return nil, ErrURLNotSupported
}
diff --git a/modules/storage/minio.go b/modules/storage/minio.go
index 1c5d25b2d4f..01f2c162679 100644
--- a/modules/storage/minio.go
+++ b/modules/storage/minio.go
@@ -279,7 +279,7 @@ func (m *MinioStorage) Delete(path string) error {
}
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
-func (m *MinioStorage) URL(path, name string, serveDirectReqParams url.Values) (*url.URL, error) {
+func (m *MinioStorage) URL(path, name, method string, serveDirectReqParams url.Values) (*url.URL, error) {
// copy serveDirectReqParams
reqParams, err := url.ParseQuery(serveDirectReqParams.Encode())
if err != nil {
@@ -287,7 +287,12 @@ func (m *MinioStorage) URL(path, name string, serveDirectReqParams url.Values) (
}
// TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we?
reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"")
- u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), 5*time.Minute, reqParams)
+ expires := 5 * time.Minute
+ if method == http.MethodHead {
+ u, err := m.client.PresignedHeadObject(m.ctx, m.bucket, m.buildMinioPath(path), expires, reqParams)
+ return u, convertMinioErr(err)
+ }
+ u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), expires, reqParams)
return u, convertMinioErr(err)
}
diff --git a/modules/storage/storage.go b/modules/storage/storage.go
index b0529941e7d..1868817c057 100644
--- a/modules/storage/storage.go
+++ b/modules/storage/storage.go
@@ -59,11 +59,15 @@ type Object interface {
// ObjectStorage represents an object storage to handle a bucket and files
type ObjectStorage interface {
Open(path string) (Object, error)
- // Save store a object, if size is unknown set -1
+
+ // Save store an object, if size is unknown set -1
+ // NOTICE: Some storage SDK will close the Reader after saving if it is also a Closer,
+ // DO NOT use the reader anymore after Save, or wrap it to a non-Closer reader.
Save(path string, r io.Reader, size int64) (int64, error)
+
Stat(path string) (os.FileInfo, error)
Delete(path string) error
- URL(path, name string, reqParams url.Values) (*url.URL, error)
+ URL(path, name, method string, reqParams url.Values) (*url.URL, error)
IterateObjects(path string, iterator func(path string, obj Object) error) error
}
diff --git a/modules/structs/repo.go b/modules/structs/repo.go
index abc80763878..aca5d9c3f43 100644
--- a/modules/structs/repo.go
+++ b/modules/structs/repo.go
@@ -57,7 +57,7 @@ type Repository struct {
Private bool `json:"private"`
Fork bool `json:"fork"`
Template bool `json:"template"`
- Parent *Repository `json:"parent"`
+ Parent *Repository `json:"parent,omitempty"`
Mirror bool `json:"mirror"`
Size int `json:"size"`
Language string `json:"language"`
@@ -114,7 +114,7 @@ type Repository struct {
ObjectFormatName string `json:"object_format_name"`
// swagger:strfmt date-time
MirrorUpdated time.Time `json:"mirror_updated"`
- RepoTransfer *RepoTransfer `json:"repo_transfer"`
+ RepoTransfer *RepoTransfer `json:"repo_transfer,omitempty"`
Topics []string `json:"topics"`
Licenses []string `json:"licenses"`
}
diff --git a/modules/templates/mailer.go b/modules/templates/mailer.go
index 310d6453287..c43b7607779 100644
--- a/modules/templates/mailer.go
+++ b/modules/templates/mailer.go
@@ -9,6 +9,7 @@ import (
"html/template"
"regexp"
"strings"
+ "sync/atomic"
texttmpl "text/template"
"code.gitea.io/gitea/modules/log"
@@ -16,6 +17,12 @@ import (
"code.gitea.io/gitea/modules/util"
)
+type MailTemplates struct {
+ TemplateNames []string
+ BodyTemplates *template.Template
+ SubjectTemplates *texttmpl.Template
+}
+
var mailSubjectSplit = regexp.MustCompile(`(?m)^-{3,}\s*$`)
// mailSubjectTextFuncMap returns functions for injecting to text templates, it's only used for mail subject
@@ -52,16 +59,17 @@ func buildSubjectBodyTemplate(stpl *texttmpl.Template, btpl *template.Template,
return nil
}
-// Mailer provides the templates required for sending notification mails.
-func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) {
- subjectTemplates := texttmpl.New("")
- bodyTemplates := template.New("")
-
- subjectTemplates.Funcs(mailSubjectTextFuncMap())
- bodyTemplates.Funcs(NewFuncMap())
-
+// LoadMailTemplates provides the templates required for sending notification mails.
+func LoadMailTemplates(ctx context.Context, loadedTemplates *atomic.Pointer[MailTemplates]) {
assetFS := AssetFS()
refreshTemplates := func(firstRun bool) {
+ var templateNames []string
+ subjectTemplates := texttmpl.New("")
+ bodyTemplates := template.New("")
+
+ subjectTemplates.Funcs(mailSubjectTextFuncMap())
+ bodyTemplates.Funcs(NewFuncMap())
+
if !firstRun {
log.Trace("Reloading mail templates")
}
@@ -81,6 +89,7 @@ func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) {
if firstRun {
log.Trace("Adding mail template %s: %s by %s", tmplName, assetPath, layerName)
}
+ templateNames = append(templateNames, tmplName)
if err = buildSubjectBodyTemplate(subjectTemplates, bodyTemplates, tmplName, content); err != nil {
if firstRun {
log.Fatal("Failed to parse mail template, err: %v", err)
@@ -88,6 +97,12 @@ func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) {
log.Error("Failed to parse mail template, err: %v", err)
}
}
+ loaded := &MailTemplates{
+ TemplateNames: templateNames,
+ BodyTemplates: bodyTemplates,
+ SubjectTemplates: subjectTemplates,
+ }
+ loadedTemplates.Store(loaded)
}
refreshTemplates(true)
@@ -99,6 +114,4 @@ func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) {
refreshTemplates(false)
})
}
-
- return subjectTemplates, bodyTemplates
}
diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini
index 17ee12af799..da01c67f952 100644
--- a/options/locale/locale_cs-CZ.ini
+++ b/options/locale/locale_cs-CZ.ini
@@ -128,7 +128,6 @@ pin=Připnout
unpin=Odepnout
artifacts=Artefakty
-confirm_delete_artifact=Jste si jisti, že chcete odstranit artefakt „%s“?
archived=Archivováno
@@ -168,7 +167,6 @@ internal_error_skipped=Došlo k vnitřní chybě, ale je přeskočena: %s
search=Hledat...
type_tooltip=Druh vyhledávání
fuzzy=Fuzzy
-fuzzy_tooltip=Zahrnout výsledky, které také úzce odpovídají hledanému výrazu
exact=Přesně
exact_tooltip=Zahrnout pouze výsledky, které přesně odpovídají hledanému výrazu
repo_kind=Hledat repozitáře...
@@ -351,7 +349,6 @@ no_reply_address=Skrytá e-mailová doména
no_reply_address_helper=Název domény pro uživatele se skrytou e-mailovou adresou. Příklad: Pokud je název skryté e-mailové domény nastaven na „noreply.example.org“, uživatelské jméno „joe“ bude zaznamenáno v Gitu jako „joe@noreply.example.org“.
password_algorithm=Hash algoritmus hesla
invalid_password_algorithm=Neplatný algoritmus hash hesla
-password_algorithm_helper=Nastavte algoritmus hashování hesla. Algoritmy mají odlišné požadavky a sílu. Algoritmus argon2 je poměrně bezpečný, ale používá spoustu paměti a může být nevhodný pro malé systémy.
enable_update_checker=Povolit kontrolu aktualizací
enable_update_checker_helper=Kontroluje vydání nových verzí pravidelně připojením ke gitea.io.
env_config_keys=Konfigurace prostředí
@@ -448,7 +445,6 @@ oauth_signin_title=Přihlaste se pro ověření propojeného účtu
oauth_signin_submit=Propojit účet
oauth.signin.error.access_denied=Žádost o autorizaci byla zamítnuta.
oauth.signin.error.temporarily_unavailable=Autorizace se nezdařila, protože ověřovací server je dočasně nedostupný. Opakujte akci později.
-oauth_callback_unable_auto_reg=Automatická registrace je povolena, ale OAuth2 poskytovatel %[1]s vrátil chybějící pole: %[2]s, nelze vytvořit účet automaticky, vytvořte účet nebo se připojte k účtu, nebo kontaktujte správce webu.
openid_connect_submit=Připojit
openid_connect_title=Připojení k existujícímu účtu
openid_connect_desc=Zvolené OpenID URI není známé. Přidružte nový účet zde.
@@ -461,7 +457,6 @@ email_domain_blacklisted=Nemůžete se registrovat s vaší e-mailovou adresou.
authorize_application=Autorizovat aplikaci
authorize_redirect_notice=Budete přesměrováni na %s, pokud autorizujete tuto aplikaci.
authorize_application_created_by=Tuto aplikaci vytvořil %s.
-authorize_application_description=Pokud povolíte přístup, bude moci přistupovat a zapisovat do všech vašich informací o účtu včetně soukromých repozitářů a organizací.
authorize_application_with_scopes=S rozsahy působnosti: %s
authorize_title=Autorizovat „%s“ pro přístup k vašemu účtu?
authorization_failed=Autorizace selhala
@@ -490,8 +485,6 @@ activate_email.text=Pro aktivaci vašeho účtu do %s klikněte na násle
register_notify=Vítejte v %s
register_notify.title=%[1]s vítejte v %[2]s
-register_notify.text_1=toto je váš potvrzovací e-mail pro %s!
-register_notify.text_2=Nyní se můžete přihlásit přes uživatelské jméno: %s.
register_notify.text_3=Pokud pro vás byl vytvořen tento účet, nejprve nastavte své heslo.
reset_password=Obnovit váš účet
@@ -673,7 +666,6 @@ form.name_chars_not_allowed=Uživatelské jméno „%s“ obsahuje neplatné zna
block.block=Blokovat
block.block.user=Zablokovat Uživatele
-block.block.org=Blokovat uživatele pro organizaci
block.block.failure=Nepodařilo se zablokovat uživatele: %s
block.unblock=Odblokovat
block.unblock.failure=Nepodařilo se odblokovat uživatele: %s
@@ -717,7 +709,6 @@ webauthn=Dvoufaktorové ověření (Bezpečnostní klíče)
public_profile=Veřejný profil
biography_placeholder=Řekněte nám něco o sobě! (Můžete použít Markdown)
location_placeholder=Sdílejte svou přibližnou polohu s ostatními
-profile_desc=Nastavte, jak bude váš profil zobrazen ostatním uživatelům. Vaše hlavní e-mailová adresa bude použita pro oznámení, obnovení hesla a operace Git.
full_name=Celé jméno
website=Web
location=Místo
@@ -794,7 +785,6 @@ activations_pending=Čekající aktivace
can_not_add_email_activations_pending=Existuje čekající aktivace, zkuste to znovu za pár minut, pokud chcete přidat nový e-mail.
delete_email=Smazat
email_deletion=Odstranit e-mailovou adresu
-email_deletion_desc=E-mailová adresa a přidružené informace budou z vašeho účtu odstraněny. Commity Gitu s touto e-mailovou adresou zůstanou nezměněny. Pokračovat?
email_deletion_success=E-mailová adresa byla odstraněna.
theme_update_success=Váš motiv vzhledu byl aktualizován.
theme_update_error=Vybraný motiv vzhledu neexistuje.
@@ -977,7 +967,6 @@ webauthn_alternative_tip=Možná budete chtít nakonfigurovat další metodu ov
manage_account_links=Správa propojených účtů
manage_account_links_desc=Tyto externí účty jsou propojeny s vaším Gitea účtem.
-account_links_not_available=K vašemu Gitea účtu nejsou aktuálně připojené žádné externí účty.
link_account=Propojit účet
remove_account_link=Odstranit propojený účet
remove_account_link_desc=Odstraněním propojeného účtu zrušíte jeho přístup k vašemu Gitea účtu. Pokračovat?
@@ -1014,8 +1003,6 @@ new_repo_helper=Repozitář obsahuje všechny projektové soubory, včetně hist
owner=Vlastník
owner_helper=Některé organizace se nemusejí v seznamu zobrazit kvůli maximálnímu dosaženému počtu repozitářů.
repo_name=Název repozitáře
-repo_name_profile_public_hint=.profile je speciální repozitář, který můžete použít k přidání souboru README.md do svého veřejného profilu organizace, který je viditelný pro každého. Ujistěte se, že je veřejný, a pro začátek jej inicializujte pomocí README v adresáři profilu.
-repo_name_profile_private_hint=.profile-private je speciální repozitář, který můžete použít k přidání souboru README.md do profilu člena organizace, který je viditelný pouze pro členy organizace. Ujistěte se, že je soukromý, a pro začátek jej inicializujte pomocí README v adresáři profilu.
repo_name_helper=Dobrá jména repozitářů používají krátká, zapamatovatelná a unikátní klíčová slova. Repozitář s názvem „.profile“ nebo „.profile-private“ lze použít k přidání README.md pro uživatelský/organizační profil.
repo_size=Velikost repozitáře
template=Šablona
@@ -1037,7 +1024,6 @@ fork_branch=Větev, která má být klonována pro fork
all_branches=Všechny větve
view_all_branches=Zobrazit všechny větve
view_all_tags=Zobrazit všechny značky
-fork_no_valid_owners=Tento repozitář nemůže být rozštěpen, protože neexistují žádní platní vlastníci.
fork.blocked_user=Nelze rozštěpit repozitář, protože jste blokováni majitelem repozitáře.
use_template=Použít tuto šablonu
open_with_editor=Otevřít pomocí %s
@@ -1081,7 +1067,6 @@ mirror_sync=synchronizováno
mirror_sync_on_commit=Synchronizovat při nahrávání revizí
mirror_address=Klonovat z URL
mirror_address_desc=Zadejte požadované přístupové údaje do sekce Ověření.
-mirror_address_url_invalid=Poskytnutá URL je neplatná. Všechny části musíte správně nahradit escape sekvencí.
mirror_address_protocol_invalid=Zadaná URL je neplatná. Mohou být zrcadleny pouze umístění http(s):// nebo git://.
mirror_lfs=Úložiště velkých souborů (LFS)
mirror_lfs_desc=Aktivovat zrcadlení dat LFS.
@@ -1140,8 +1125,6 @@ template.issue_labels=Štítky úkolů
template.one_item=Musíte vybrat alespoň jednu položku šablony
template.invalid=Musíte vybrat repositář šablony
-archive.title=Tento repozitář je archivovaný. Můžete prohlížet soubory, klonovat, ale nemůžete nahrávat a vytvářet nové úkoly nebo pull requesty.
-archive.title_date=Tento repositář byl archivován %s. Můžete zobrazit soubory a klonovat je, ale nemůžete nahrávat ani otevírat úkoly nebo pull requesty.
archive.issue.nocomment=Tento repozitář je archivovaný. Nemůžete komentovat úkoly.
archive.pull.nocomment=Tento repozitář je archivovaný. Nemůžete komentovat pull requesty.
@@ -1170,7 +1153,6 @@ migrate_items_releases=Vydání
migrate_repo=Migrovat repozitář
migrate.clone_address=Migrovat / klonovat z URL
migrate.clone_address_desc=HTTP(S) nebo URL pro klonování existujícího repozitáře
-migrate.github_token_desc=Můžete sem vložit jeden nebo více tokenů oddělených čárkou, abyste urychlili migraci kvůli omezení rychlosti rozhraní GitHub API. VAROVÁNÍ: Zneužití této funkce může vést k porušení zásad poskytovatele služeb a zablokování účtu.
migrate.clone_local_path=nebo místní cesta serveru
migrate.permission_denied=Není dovoleno importovat místní repozitáře.
migrate.permission_denied_blocked=Nelze importovat z nepovolených hostitelů, prosím požádejte správce, aby zkontroloval nastavení ALLOWED_DOMAINS/ALLOW_LOCALETWORKS/BLOCKED_DOMAINS.
@@ -1231,7 +1213,6 @@ create_new_repo_command=Vytvořit nový repozitář na příkazové řádce
push_exist_repo=Nahrání existujícího repozitáře z příkazové řádky
empty_message=Tento repozitář nemá žádný obsah.
broken_message=Data gitu, která jsou základem tohoto repozitáře, nelze číst. Kontaktujte správce této instance nebo smažte tento repositář.
-no_branch=Tento repozitář nemá žádné větve.
code=Zdrojový kód
code.desc=Přístup ke zdrojovým kódům, souborům, commitům a větvím.
@@ -1654,7 +1635,6 @@ issues.lock_no_reason=uzamkl/a a omezil/a konverzaci na spolupracovníky %s
issues.unlock_comment=odemkl/a tuto konverzaci %s
issues.lock_confirm=Uzamknout
issues.unlock_confirm=Odemknout
-issues.lock.notice_1=- Další uživatelé nemohou komentovat tento úkol.
issues.lock.notice_2=- Vy a ostatní spolupracovníci s přístupem k tomuto repozitáři můžete stále přidávat komentáře, které ostatní uvidí.
issues.lock.notice_3=- V budoucnu budete moci vždy znovu tento úkol odemknout.
issues.unlock.notice_1=- Všichni budou moci znovu komentovat tento úkol.
@@ -1705,7 +1685,6 @@ issues.due_date_form=rrrr-mm-dd
issues.due_date_form_add=Přidat termín dokončení
issues.due_date_form_edit=Upravit
issues.due_date_form_remove=Odstranit
-issues.due_date_not_writer=Potřebujete přístup k zápisu do tohoto repozitáře, abyste mohli aktualizovat datum dokončení úkolu.
issues.due_date_not_set=Žádný termín dokončení.
issues.due_date_added=přidal/a termín dokončení %s %s
issues.due_date_modified=upravil/a termín termínu z %[2]s na %[1]s %[3]s
@@ -1819,7 +1798,6 @@ pulls.select_commit_hold_shift_for_range=Vyberte commit. Podržte klávesu shift
pulls.review_only_possible_for_full_diff=Posouzení je možné pouze při zobrazení plného rozlišení
pulls.filter_changes_by_commit=Filtrovat podle commitu
pulls.nothing_to_compare=Tyto větve jsou stejné. Není potřeba vytvářet pull request.
-pulls.nothing_to_compare_have_tag=Vybraná větev/značka je stejná.
pulls.nothing_to_compare_and_allow_empty_pr=Tyto větve jsou stejné. Tento pull request bude prázdný.
pulls.has_pull_request=`Pull request mezi těmito větvemi již existuje: %[2]s#%[3]d`
pulls.create=Vytvořit pull request
@@ -1979,7 +1957,6 @@ milestones.filter_sort.most_issues=Nejvíce úkolů
milestones.filter_sort.least_issues=Nejméně úkolů
signing.will_sign=Tento commit bude podepsána klíčem „%s“.
-signing.wont_sign.error=Došlo k chybě při kontrole, zda může být commit podepsán.
signing.wont_sign.nokey=K podpisu tohoto commitu není k dispozici žádný klíč.
signing.wont_sign.never=Commity nejsou nikdy podepsány.
signing.wont_sign.always=Commity jsou vždy podepsány.
@@ -2070,7 +2047,6 @@ activity.title.releases_1=%d Vydání
activity.title.releases_n=%d Vydání
activity.title.releases_published_by=%s publikoval %s
activity.published_release_label=Publikováno
-activity.no_git_activity=V tomto období nebyla žádná aktivita při odevzdání.
activity.git_stats_exclude_merges=Při vyloučení slučování,
activity.git_stats_author_1=%d autor
activity.git_stats_author_n=%d autoři
@@ -2469,7 +2445,6 @@ settings.block_on_official_review_requests_desc=Slučování nebude možné, pok
settings.block_outdated_branch=Blokovat sloučení, pokud je pull request zastaralý
settings.block_outdated_branch_desc=Slučování nebude možné, pokud je hlavní větev za základní větví.
settings.block_admin_merge_override=Pravidla pro ochranu větví se vztahují i na administrátory
-settings.block_admin_merge_override_desc=Pravidla pro ochranu větví se vztahují i na administrátory a nesmějí je obcházet.
settings.default_branch_desc=Vybrat výchozí větev repozitáře pro pull requesty a revize kódu:
settings.merge_style_desc=Sloučit styly
settings.default_merge_style_desc=Výchozí styl sloučení
@@ -2496,10 +2471,7 @@ settings.matrix.homeserver_url=URL adresa Homeserveru
settings.matrix.room_id=ID místnosti
settings.matrix.message_type=Typ zprávy
settings.visibility.private.button=Nastavit jako soukromé
-settings.visibility.private.text=Změna viditelnosti na soukromou nejen zviditelní repozitář pouze pro povolené členy, ale může odstranit vztah mezi ním a rozštěpením, sledujícími a oblíbeností.
settings.visibility.private.bullet_title=Změna viditelnosti na soukromou způsobí:
-settings.visibility.private.bullet_one=Zviditelnit repozitář pouze pro povolené členy.
-settings.visibility.private.bullet_two=Může odstranit vztah mezi ním a rozštěpeními, sledujícímia oblíbeností.
settings.visibility.public.button=Nastavit jako veřejné
settings.visibility.public.text=Změna viditelnosti na veřejné učiní repozitář viditelným pro kohokoliv.
settings.visibility.public.bullet_title=Změna viditelnosti na veřejnou způsobí:
@@ -2918,9 +2890,6 @@ dashboard.resync_all_sshprincipals=Aktualizovat soubor '.ssh/authorized_principa
dashboard.resync_all_hooks=Znovu synchronizovat háčky před přijetím, aktualizace a po přijetí všech repozitářů.
dashboard.reinit_missing_repos=Znovu inicializovat všechny chybějící repozitáře, pro které existují záznamy
dashboard.sync_external_users=Synchronizovat externí uživatelská data
-dashboard.cleanup_hook_task_table=Vyčistit tabulku hook_task
-dashboard.cleanup_packages=Vyčistit prošlé balíčky
-dashboard.cleanup_actions=Vyčištění prostředků akcí, jejichž platnost vypršela
dashboard.server_uptime=Doba provozu serveru
dashboard.current_goroutine=Aktuální Goroutines
dashboard.current_memory_usage=Aktuální využití paměti
@@ -3355,7 +3324,6 @@ monitor.start=Čas zahájení
monitor.execute_time=Doba provádění
monitor.last_execution_result=Výsledek
monitor.process.cancel=Zrušit proces
-monitor.process.cancel_desc=Zrušení procesu může způsobit ztrátu dat
monitor.process.children=Potomek
monitor.queues=Fronty
@@ -3627,7 +3595,6 @@ owner.settings.cargo.initialize.success=Index Cargo byl úspěšně vytvořen.
owner.settings.cargo.rebuild=Znovu vytvořit Index
owner.settings.cargo.rebuild.description=Obnova může být užitečná, pokud index není synchronizován s uloženými balíčky Cargo.
owner.settings.cargo.rebuild.error=Obnovení Cargo indexu se nezdařilo: %v
-owner.settings.cargo.rebuild.success=Cargo Index byl úspěšně obnoven.
owner.settings.cleanuprules.title=Spravovat pravidla pro čištění
owner.settings.cleanuprules.add=Přidat pravidlo pro čištění
owner.settings.cleanuprules.edit=Upravit pravidlo pro čištění
@@ -3710,7 +3677,6 @@ runners.delete_runner=Odstranit tento runner
runners.delete_runner_success=Runner byl úspěšně odstraněn
runners.delete_runner_failed=Odstranění runneru selhalo
runners.delete_runner_header=Potvrdit odstranění tohoto runneru
-runners.delete_runner_notice=Pokud na tomto runneru běží úloha, bude ukončena a označena jako neúspěšná. Může dojít k přerušení vytváření pracovního postupu.
runners.none=Žádné runnery nejsou k dispozici
runners.status.unspecified=Neznámý
runners.status.idle=Nečinný
diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini
index b989fc54732..7bf2df968a3 100644
--- a/options/locale/locale_de-DE.ini
+++ b/options/locale/locale_de-DE.ini
@@ -117,7 +117,6 @@ files=Dateien
error=Fehler
error404=Die Seite, die Du versuchst aufzurufen, existiert nicht oder Du bist nicht berechtigt, diese anzusehen.
-error503=Der Server konnte deine Anfrage nicht abschließen. Bitte versuche es später erneut.
go_back=Zurück
invalid_data=Ungültige Daten: %v
@@ -131,7 +130,6 @@ unpin=Loslösen
artifacts=Artefakte
expired=Abgelaufen
-confirm_delete_artifact=Bist du sicher, dass du das Artefakt '%s' löschen möchtest?
archived=Archiviert
@@ -171,7 +169,6 @@ internal_error_skipped=Ein interner Fehler ist aufgetreten, wurde aber überspru
search=Suche ...
type_tooltip=Suchmodus
fuzzy=Ähnlich
-fuzzy_tooltip=Ergebnisse einbeziehen, die dem Suchbegriff ähnlich sind
words=Wörter
words_tooltip=Nur Suchbegriffe einbeziehen, die den Suchbegriffen exakt entsprechen
regexp=Regexp
@@ -358,7 +355,6 @@ no_reply_address=Versteckte E-Mail-Domain
no_reply_address_helper=Domain-Name für Benutzer mit einer versteckten Emailadresse. Zum Beispiel wird der Benutzername „Joe“ in Git als „joe@noreply.example.org“ protokolliert, wenn die versteckte E-Mail-Domain „noreply.example.org“ festgelegt ist.
password_algorithm=Passwort Hashing Algorithmus
invalid_password_algorithm=Ungültiger Passwort-Hash-Algorithmus
-password_algorithm_helper=Lege einen Passwort-Hashing-Algorithmus fest. Algorithmen haben unterschiedliche Anforderungen und Stärken. Der argon2-Algorithmus ist ziemlich sicher, aber er verbraucht viel Speicher und kann für kleine Systeme ungeeignet sein.
enable_update_checker=Aktualisierungsprüfung aktivieren
enable_update_checker_helper=Stellt regelmäßig eine Verbindung zu gitea.io her, um nach neuen Versionen zu prüfen.
env_config_keys=Umgebungskonfiguration
@@ -451,7 +447,6 @@ use_scratch_code=Einmalpasswort verwenden
twofa_scratch_used=Du hast dein Einmalpasswort verwendet. Du wurdest zu den Einstellung der Zwei-Faktor-Authentifizierung umgeleitet, dort kannst du dein Gerät abmelden oder ein neues Einmalpasswort erzeugen.
twofa_passcode_incorrect=Ungültige PIN. Wenn du dein Gerät verloren hast, verwende dein Einmalpasswort.
twofa_scratch_token_incorrect=Das Einmalpasswort ist falsch.
-twofa_required=Du musst die Zwei-Faktor-Authentifizierung einrichten, um Zugriff auf die Repositories zu erhalten, oder versuche dich erneut anzumelden.
login_userpass=Anmelden
login_openid=OpenID
oauth_signup_tab=Neues Konto registrieren
@@ -463,7 +458,6 @@ oauth_signin_submit=Konto verbinden
oauth.signin.error.general=Beim Verarbeiten der Autorisierungsanfrage ist ein Fehler aufgetreten: %s. Wenn dieser Fehler weiterhin besteht, wende dich bitte an den Administrator.
oauth.signin.error.access_denied=Die Autorisierungsanfrage wurde abgelehnt.
oauth.signin.error.temporarily_unavailable=Autorisierung fehlgeschlagen, da der Authentifizierungsserver vorübergehend nicht verfügbar ist. Bitte versuch es später erneut.
-oauth_callback_unable_auto_reg=Automatische Registrierung ist aktiviert, aber der OAuth2-Provider %[1]s hat fehlende Felder zurückgegeben: %[2]s, kann den Account nicht automatisch erstellen. Bitte erstelle oder verbinde einen Account oder kontaktieren den Administrator.
openid_connect_submit=Verbinden
openid_connect_title=Mit bestehendem Konto verbinden
openid_connect_desc=Die gewählte OpenID-URI ist unbekannt. Ordne sie hier einem neuen Account zu.
@@ -476,7 +470,6 @@ email_domain_blacklisted=Du kannst dich nicht mit deiner E-Mail-Adresse registri
authorize_application=Anwendung autorisieren
authorize_redirect_notice=Du wirst zu %s weitergeleitet, wenn du diese Anwendung autorisierst.
authorize_application_created_by=Diese Anwendung wurde von %s erstellt.
-authorize_application_description=Wenn du diese Anwendung autorisierst, wird sie die Berechtigung erhalten, alle Informationen zu deinem Account zu bearbeiten oder zu lesen. Dies beinhaltet auch private Repositories und Organisationen.
authorize_application_with_scopes=Mit Bereichen: %s
authorize_title=`"%s" den Zugriff auf deinen Account gestatten?`
authorization_failed=Autorisierung fehlgeschlagen
@@ -505,8 +498,6 @@ activate_email.text=Bitte klicke innerhalb von %s auf folgenden Link, um
register_notify=Willkommen bei %s
register_notify.title=%[1]s, willkommen bei %[2]s
-register_notify.text_1=dies ist deine Bestätigungs-E-Mail für %s!
-register_notify.text_2=Du kannst dich jetzt mit dem Benutzernamen "%s" anmelden.
register_notify.text_3=Wenn dieser Account von dir erstellt wurde, musst du zuerst dein Passwort setzen.
reset_password=Stelle dein Konto wieder her
@@ -688,7 +679,6 @@ form.name_chars_not_allowed=Benutzername "%s" enthält ungültige Zeichen.
block.block=Sperren
block.block.user=Benutzer sperren
-block.block.org=Benutzer für Organisation sperren
block.block.failure=Fehler beim Sperren des Benutzers: %s
block.unblock=Entsperren
block.unblock.failure=Fehler beim Entsperren des Benutzers: %s
@@ -732,7 +722,6 @@ webauthn=Zwei-Faktor-Authentifizierung (Hardware-Sicherheitsschlüssel)
public_profile=Öffentliches Profil
biography_placeholder=Erzähle uns ein wenig über Dich selbst! (Du kannst Markdown verwenden)
location_placeholder=Teile Deinen ungefähren Standort mit anderen
-profile_desc=Lege fest, wie dein Profil anderen Benutzern angezeigt wird. Deine primäre E-Mail-Adresse wird für Benachrichtigungen, Passwort-Wiederherstellung und webbasierte Git-Operationen verwendet.
password_username_disabled=Du bist nicht berechtigt, den Benutzernamen zu ändern. Bitte kontaktiere Deinen Seitenadministrator für weitere Details.
password_full_name_disabled=Du bist nicht berechtigt, den vollständigen Namen zu ändern. Bitte kontaktiere Deinen Seitenadministrator für weitere Details.
full_name=Vollständiger Name
@@ -811,7 +800,6 @@ activations_pending=Aktivierung ausstehend
can_not_add_email_activations_pending=Es gibt eine ausstehende Aktivierung, versuche es in ein paar Minuten erneut, wenn du eine neue E-Mail hinzufügen möchtest.
delete_email=Löschen
email_deletion=E-Mail-Adresse löschen
-email_deletion_desc=Die E-Mail-Adresse und die damit verbundenen Informationen werden von deinem Konto entfernt. Git-Commits von dieser E-Mail-Addresse bleiben unverändert. Fortfahren?
email_deletion_success=Die E-Mail-Adresse wurde entfernt.
theme_update_success=Deine Theme-Auswahl wurde gespeichert.
theme_update_error=Das ausgewählte Theme existiert nicht.
@@ -997,7 +985,6 @@ webauthn_alternative_tip=Möglicherweise möchtest du eine zusätzliche Authenti
manage_account_links=Verknüpfte Accounts verwalten
manage_account_links_desc=Diese externen Accounts sind mit deinem Gitea-Account verknüpft.
-account_links_not_available=Es sind keine externen Accounts mit diesem Gitea-Account verknüpft.
link_account=Account verbinden
remove_account_link=Verknüpften Account entfernen
remove_account_link_desc=Wenn du den verknüpften Account entfernst, wirst du darüber nicht mehr auf deinen Gitea-Account zugreifen können. Fortfahren?
@@ -1034,8 +1021,6 @@ new_repo_helper=Ein Repository enthält alle Projektdateien, einschließlich des
owner=Besitzer
owner_helper=Einige Organisationen könnten in der Dropdown-Liste nicht angezeigt werden, da die Anzahl an Repositories begrenzt ist.
repo_name=Repository-Name
-repo_name_profile_public_hint=.profile ist ein spezielles Repository, mit dem du die README.md zu deinem öffentlichen Organisationsprofil hinzufügen kannst, das für jeden sichtbar ist. Stelle sicher, dass es öffentlich ist und initialisiere es mit einer README im Profilverzeichnis, um loszulegen.
-repo_name_profile_private_hint=.profile ist ein spezielles Repository, mit dem du die README.md zu deinem privaten Organisationsprofil hinzufügen kannst, das nur für Organisationsmitglieder sichtbar ist. Stelle sicher, dass es privat ist und initialisiere es mit einer README im Profilverzeichnis, um loszulegen.
repo_name_helper=Ein guter Repository-Name besteht normalerweise aus kurzen, unvergesslichen und einzigartigen Schlagwörtern. Ein Repository namens ".profile" or ".profile-private" kann verwendet werden, um die README.md auf dem Benutzer- oder Organisationsprofil anzuzeigen.
repo_size=Repository-Größe
template=Template
@@ -1057,7 +1042,6 @@ fork_branch=Branch, der zum Fork geklont werden soll
all_branches=Alle Branches
view_all_branches=Alle Branches anzeigen
view_all_tags=Alle Tags anzeigen
-fork_no_valid_owners=Dieses Repository kann nicht geforkt werden, da keine gültigen Besitzer vorhanden sind.
fork.blocked_user=Das Repository kann nicht geforkt werden, da du vom Repository-Eigentümer blockiert wurdest.
use_template=Dieses Template verwenden
open_with_editor=Mit %s öffnen
@@ -1101,7 +1085,6 @@ mirror_sync=synchronisiert
mirror_sync_on_commit=Synchronisieren, wenn Commits gepusht wurden
mirror_address=Klonen via URL
mirror_address_desc=Gib alle erforderlichen Anmeldedaten im Abschnitt "Authentifizierung" ein.
-mirror_address_url_invalid=Die angegebene URL ist ungültig. Achte darauf, alle URL-Komponenten korrekt zu maskieren.
mirror_address_protocol_invalid=Die angegebene URL ist ungültig. Nur URLs beginnend mit http(s):// oder git:// sind möglich.
mirror_lfs=Großdatei-Speicher (LFS)
mirror_lfs_desc=Mirroring von LFS-Dateien aktivieren.
@@ -1161,8 +1144,6 @@ template.issue_labels=Issue Label
template.one_item=Es muss mindestens ein Template ausgewählt werden
template.invalid=Es muss ein Template-Repository ausgewählt werden
-archive.title=Dieses Repository ist archiviert. Du kannst Dateien ansehen und es klonen, kannst aber nicht pushen oder Issues/Pull-Requests öffnen.
-archive.title_date=Dieses Repository wurde am %s archiviert. Du kannst Dateien ansehen und es klonen, aber nicht pushen oder Issues/Pull-Requests öffnen.
archive.issue.nocomment=Dieses Repo ist archiviert. Du kannst Issues nicht kommentieren.
archive.pull.nocomment=Dieses Repo ist archiviert. Du kannst Pull-Requests nicht kommentieren.
@@ -1191,7 +1172,6 @@ migrate_items_releases=Releases
migrate_repo=Repository migrieren
migrate.clone_address=Migrations- / Klon-URL
migrate.clone_address_desc=Die HTTP(S)- oder „git clone“-URL eines bereits existierenden Repositories
-migrate.github_token_desc=Du kannst hier ein oder mehrere Token durch Komma getrennt eintippen, um die Migration aufgrund der Github API Ratenlimitierung zu beschleunigen. WARNUNG: Der Missbrauch dieser Funktion kann gegen die Richtlinien des Diensteanbieters verstoßen und zur Kontosperrung führen.
migrate.clone_local_path=oder ein lokaler Serverpfad
migrate.permission_denied=Du hast keine Berechtigung zum Importieren lokaler Repositories.
migrate.permission_denied_blocked=Du kannst von keinen nicht erlaubten Hosts importieren. Bitte fragen deinen Administrator, die Einstellungen ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS zu überprüfen.
@@ -1252,7 +1232,6 @@ create_new_repo_command=Erstelle ein neues Repository von der Kommandozeile aus
push_exist_repo=Bestehendes Repository via Kommandozeile pushen
empty_message=Dieses Repository hat keinen Inhalt.
broken_message=Die Git-Daten, die diesem Repository zugrunde liegen, können nicht gelesen werden. Kontaktiere den Administrator deiner Instanz oder lösche dieses Repository.
-no_branch=Dieses Repository hat keine Branches.
code=Code
code.desc=Zugriff auf Quellcode, Dateien, Commits und Branches.
@@ -1686,7 +1665,6 @@ issues.lock_no_reason=gesperrt und Diskussion auf Mitarbeiter beschränkt %s
issues.unlock_comment=hat diese Diskussion %s entsperrt
issues.lock_confirm=Sperren
issues.unlock_confirm=Entsperren
-issues.lock.notice_1=- Andere Nutzer können keine neuen Kommentare beisteuern.
issues.lock.notice_2=- Du und andere Mitarbeiter mit Zugriff auf dieses Repository können weiterhin für andere sichtbare Kommentare hinterlassen.
issues.lock.notice_3=- Du kannst die Diskussion jederzeit wieder entsperren.
issues.unlock.notice_1=- Jeder wird wieder in der Lage sein, zu diesem Issue zu kommentieren.
@@ -1739,7 +1717,6 @@ issues.due_date_form=JJJJ-MM-TT
issues.due_date_form_add=Fälligkeitsdatum hinzufügen
issues.due_date_form_edit=Bearbeiten
issues.due_date_form_remove=Entfernen
-issues.due_date_not_writer=Du musst Schreibrechte für dieses Repository haben, um das Fälligkeitsdatum zu ändern.
issues.due_date_not_set=Kein Fälligkeitsdatum gesetzt.
issues.due_date_added=hat %[2]s das Fälligkeitsdatum %[1]s hinzugefügt
issues.due_date_modified=ändert das Abgabedatum von %[2]s auf %[1]s %[3]s s
@@ -1853,7 +1830,6 @@ pulls.select_commit_hold_shift_for_range=Commit auswählen. Halte Shift + klicke
pulls.review_only_possible_for_full_diff=Ein Review ist nur möglich, wenn das vollständige Diff angezeigt wird
pulls.filter_changes_by_commit=Nach Commit filtern
pulls.nothing_to_compare=Diese Branches sind identisch. Es muss kein Pull-Request erstellt werden.
-pulls.nothing_to_compare_have_tag=Der ausgewählte Branch und Tag sind gleich.
pulls.nothing_to_compare_and_allow_empty_pr=Diese Branches sind gleich. Der Pull-Request wird leer sein.
pulls.has_pull_request=`Es existiert bereits ein Pull-Request zwischen diesen beiden Branches: %[2]s#%[3]d`
pulls.create=Pull-Request erstellen
@@ -2015,7 +1991,6 @@ milestones.filter_sort.most_issues=Meiste Issues
milestones.filter_sort.least_issues=Wenigste Issues
signing.will_sign=Dieser Commit wird mit dem Key "%s" signiert werden.
-signing.wont_sign.error=Es gab einen Fehler bei der Prüfung, ob der Commit signiert werden kann.
signing.wont_sign.nokey=Es ist kein Schlüssel zum Signieren dieses Commits verfügbar.
signing.wont_sign.never=Commits werden nie signiert.
signing.wont_sign.always=Commits werden immer signiert.
@@ -2106,7 +2081,6 @@ activity.title.releases_1=%d Release
activity.title.releases_n=%d Releases
activity.title.releases_published_by=%s von %s veröffentlicht
activity.published_release_label=Veröffentlicht
-activity.no_git_activity=In diesem Zeitraum sind keine Commit-Aktivität vorhanden.
activity.git_stats_exclude_merges=Merges ausgenommen,
activity.git_stats_author_1=%d Autor
activity.git_stats_author_n=%d Autoren
@@ -2516,7 +2490,6 @@ settings.block_on_official_review_requests_desc=Mergen ist nicht möglich wenn o
settings.block_outdated_branch=Merge blockieren, wenn der Pull-Request veraltet ist
settings.block_outdated_branch_desc=Mergen ist nicht möglich, wenn der Head-Branch hinter dem Basis-Branch ist.
settings.block_admin_merge_override=Administratoren müssen die Schutzregeln für Branches befolgen
-settings.block_admin_merge_override_desc=Administratoren müssen die Schutzregeln für Branches befolgen und können sie nicht umgehen.
settings.default_branch_desc=Wähle einen Standardbranch für Pull-Requests und Code-Commits:
settings.merge_style_desc=Merge-Styles
settings.default_merge_style_desc=Standard-Mergeverhalten für Pull-Requests
@@ -2543,10 +2516,7 @@ settings.matrix.homeserver_url=Homeserver-URL
settings.matrix.room_id=Raum-ID
settings.matrix.message_type=Nachrichtentyp
settings.visibility.private.button=Auf privat setzen
-settings.visibility.private.text=Das Ändern der Sichtbarkeit auf privat wird das Repository nicht nur für erlaubte Mitglieder sichtbar machen, sondern kann auch die Beziehung zwischen ihm und Forks, Beobachtern und Sternen entfernen.
settings.visibility.private.bullet_title=Das Ändern der Sichtbarkeit auf privat wird:
-settings.visibility.private.bullet_one=Das Repository nur für zugelassene Mitglieder sichtbar machen.
-settings.visibility.private.bullet_two=Kann die Beziehung zwischen ihm und Forks, Beobachternund Sternen entfernen.
settings.visibility.public.button=Auf öffentlich setzen
settings.visibility.public.text=Das Ändern der Sichtbarkeit auf öffentlich macht das Repository für jeden sichtbar.
settings.visibility.public.bullet_title=Das Ändern der Sichtbarkeit auf öffentlich wird:
@@ -2974,9 +2944,6 @@ dashboard.resync_all_sshprincipals=Aktualisiere die Datei '.ssh/authorized_princ
dashboard.resync_all_hooks=Die „pre-receive“-, „update“- und „post-receive“-Hooks für alle Repositories erneut synchronisieren.
dashboard.reinit_missing_repos=Alle Git-Repositories neu einlesen, für die Einträge existieren
dashboard.sync_external_users=Externe Benutzerdaten synchronisieren
-dashboard.cleanup_hook_task_table=Hook-Task-Tabelle bereinigen
-dashboard.cleanup_packages=Veraltete Pakete löschen
-dashboard.cleanup_actions=Abgelaufene Ressourcen von Actions bereinigen
dashboard.server_uptime=Server-Uptime
dashboard.current_goroutine=Aktuelle Goroutinen
dashboard.current_memory_usage=Aktuelle Speichernutzung
@@ -3411,7 +3378,6 @@ monitor.start=Startzeit
monitor.execute_time=Ausführungszeit
monitor.last_execution_result=Ergebnis
monitor.process.cancel=Prozess abbrechen
-monitor.process.cancel_desc=Abbrechen eines Prozesses kann Datenverlust verursachen
monitor.process.children=Subprozesse
monitor.queues=Warteschlangen
@@ -3683,7 +3649,6 @@ owner.settings.cargo.initialize.success=Der Cargo-Index wurde erfolgreich erstel
owner.settings.cargo.rebuild=Index neu erstellen
owner.settings.cargo.rebuild.description=Neubauen kann hilfreich sein, wenn der Index nicht mit den gespeicherten Cargo-Paketen synchronisiert ist.
owner.settings.cargo.rebuild.error=Cargo-Index konnte nicht neu erstellt werden: %v
-owner.settings.cargo.rebuild.success=Der Cargo-Index wurde erfolgreich neu erstellt.
owner.settings.cleanuprules.title=Bereinigungsregeln verwalten
owner.settings.cleanuprules.add=Bereinigungsregel hinzufügen
owner.settings.cleanuprules.edit=Bereinigungsregel bearbeiten
@@ -3771,7 +3736,6 @@ runners.delete_runner=Diesen Runner löschen
runners.delete_runner_success=Runner erfolgreich gelöscht
runners.delete_runner_failed=Der Runner konnte nicht gelöscht werden
runners.delete_runner_header=Bestätigen, um diesen Runner zu löschen
-runners.delete_runner_notice=Wenn eine Aufgabe auf diesem Runner ausgeführt wird, wird sie beendet und als fehlgeschlagen markiert. Dies könnte Workflows zerstören.
runners.none=Keine Runner verfügbar
runners.status.unspecified=Unbekannt
runners.status.idle=Leerlauf
diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini
index 0411686084a..4bdaf95df54 100644
--- a/options/locale/locale_el-GR.ini
+++ b/options/locale/locale_el-GR.ini
@@ -303,7 +303,6 @@ no_reply_address=Κρυφό Όνομα Τομέα Email
no_reply_address_helper=Όνομα τομέα για χρήστες με μια κρυφή διεύθυνση email. Για παράδειγμα, το όνομα χρήστη 'nikos' θα συνδεθεί στο Git ως 'nikos@noreply.example.org' αν ο κρυφός τομέας email έχει οριστεί ως 'noreply.example.org'.
password_algorithm=Αλγόριθμος Hash Κωδικού Πρόσβασης
invalid_password_algorithm=Μη έγκυρος αλγόριθμος κωδικού πρόσβασης
-password_algorithm_helper=Ορίστε τον αλγόριθμο κατακερματισμού για το κωδικό πρόσβασης. Οι αλγόριθμοι διαφέρουν σε απαιτήσεις και αντοχή. Ο αλγόριθμος argon2 είναι αρκετά ασφαλής, αλλά χρησιμοποιεί πολλή μνήμη και μπορεί να είναι ακατάλληλος για μικρά συστήματα.
enable_update_checker=Ενεργοποίηση Ελεγκτή Ενημερώσεων
enable_update_checker_helper=Ελέγχει περιοδικά για νέες εκδόσεις κάνοντας σύνδεση στο gitea.io.
env_config_keys=Ρυθμίσεις Περιβάλλοντος
@@ -404,7 +403,6 @@ email_domain_blacklisted=Δεν μπορείτε να εγγραφείτε με
authorize_application=Εξουσιοδότηση Εφαρμογής
authorize_redirect_notice=Θα μεταφερθείτε στο %s εάν εξουσιοδοτήσετε αυτήν την εφαρμογή.
authorize_application_created_by=Αυτή η εφαρμογή δημιουργήθηκε από %s.
-authorize_application_description=Εάν παραχωρήσετε την πρόσβαση, θα μπορεί να έχει πρόσβαση και να γράφει σε όλες τις πληροφορίες του λογαριασμού σας, συμπεριλαμβανομένων των ιδιωτικών αποθετηρίων και οργανισμών.
authorize_title=Εξουσιοδότηση του "%s" για έχει πρόσβαση στο λογαριασμό σας;
authorization_failed=Αποτυχία εξουσιοδότησης
authorization_failed_desc=Η εξουσιοδότηση απέτυχε επειδή εντοπίστηκε μια μη έγκυρη αίτηση. Παρακαλούμε επικοινωνήστε με το συντηρητή της εφαρμογής που προσπαθήσατε να εξουσιοδοτήσετε.
@@ -427,8 +425,6 @@ activate_email.title=%s, παρακαλώ επαληθεύστε τη διεύθ
activate_email.text=Παρακαλώ κάντε κλικ στον παρακάτω σύνδεσμο για να επαληθεύσετε τη διεύθυνση email σας στο %s:
register_notify.title=%[1]s, καλώς ήρθατε στο %[2]s
-register_notify.text_1=αυτό είναι το email επιβεβαίωσης εγγραφής για το %s!
-register_notify.text_2=Τώρα μπορείτε να συνδεθείτε μέσω του ονόματος χρήστη: %s.
register_notify.text_3=Εάν αυτός ο λογαριασμός έχει δημιουργηθεί για εσάς, παρακαλώ ορίστε πρώτα τον κωδικό πρόσβασής σας.
reset_password=Ανάκτηση του λογαριασμού σας
@@ -622,7 +618,6 @@ uid=UID
public_profile=Δημόσιο Προφίλ
biography_placeholder=Πείτε μας λίγο για τον εαυτό σας! (Μπορείτε να γράψετε με Markdown)
location_placeholder=Μοιραστείτε την κατά προσέγγιση τοποθεσία σας με άλλους
-profile_desc=Ελέγξτε πώς εμφανίζεται το προφίλ σας σε άλλους χρήστες. Η κύρια διεύθυνση email σας θα χρησιμοποιηθεί για ειδοποιήσεις, ανάκτηση κωδικού πρόσβασης και λειτουργίες Git που βασίζονται στο web.
full_name=Πλήρες Όνομα
website=Ιστοσελίδα
location=Τοποθεσία
@@ -695,7 +690,6 @@ activations_pending=Εκκρεμούν Ενεργοποιήσεις
can_not_add_email_activations_pending=Εκκρεμεί μια ενεργοποίηση, δοκιμάστε ξανά σε λίγα λεπτά αν θέλετε να προσθέσετε ένα νέο email.
delete_email=Αφαίρεση
email_deletion=Αφαίρεση Διεύθυνσης Email
-email_deletion_desc=Η διεύθυνση ηλεκτρονικού ταχυδρομείου και οι σχετικές πληροφορίες θα αφαιρεθούν από τον λογαριασμό σας. Οι υποβολές Git από αυτή τη διεύθυνση email θα παραμείνουν αμετάβλητες. Συνέχεια;
email_deletion_success=Η διεύθυνση email σας έχει καταργηθεί.
theme_update_success=Το θέμα διεπαφής σας ενημερώθηκε.
theme_update_error=Το επιλεγμένο θέμα διεπαφής δεν υπάρχει.
@@ -871,7 +865,6 @@ webauthn_alternative_tip=Μπορεί να θέλετε να ρυθμίσετε
manage_account_links=Διαχείριση Συνδεδεμένων Λογαριασμών
manage_account_links_desc=Αυτοί οι εξωτερικοί λογαριασμοί είναι συνδεδεμένοι στον Gitea λογαριασμό σας.
-account_links_not_available=Προς το παρόν δεν υπάρχουν εξωτερικοί λογαριασμοί συνδεδεμένοι με τον λογαριασμό σας στο Gitea.
link_account=Σύνδεση Λογαριασμού
remove_account_link=Αφαίρεση Συνδεδεμένου Λογαριασμού
remove_account_link_desc=Η κατάργηση ενός συνδεδεμένου λογαριασμού θα ανακαλέσει την πρόσβασή του στο λογαριασμό σας στο Gitea. Συνέχεια;
@@ -926,7 +919,6 @@ fork_to_different_account=Fork σε διαφορετικό λογαριασμό
fork_visibility_helper=Η ορατότητα ενός fork αποθετηρίου δεν μπορεί να αλλάξει.
fork_branch=Κλάδος που θα κλωνοποιηθεί στο fork
all_branches=Όλοι οι κλάδοι
-fork_no_valid_owners=Αυτό το αποθετήριο δεν μπορεί να γίνει fork επειδή δεν υπάρχουν έγκυροι ιδιοκτήτες.
use_template=Χρήση αυτού του πρότυπου
download_zip=Λήψη ZIP
download_tar=Λήψη TAR.GZ
@@ -962,7 +954,6 @@ mirror_interval_invalid=Το χρονικό διάστημα του ειδώλο
mirror_sync_on_commit=Συγχρονισμός κατά την ώθηση
mirror_address=Κλωνοποίηση Από Το URL
mirror_address_desc=Τοποθετήστε όλα τα απαιτούμενα διαπιστευτήρια στην ενότητα Εξουσιοδότηση.
-mirror_address_url_invalid=Η διεύθυνση URL που δόθηκε δεν είναι έγκυρη. Πρέπει να κάνετε escape όλα τα στοιχεία του url σωστά.
mirror_address_protocol_invalid=Η παρεχόμενη διεύθυνση URL δεν είναι έγκυρη. Μόνο οι τοποθεσίες http(s):// ή git:// μπορούν να χρησιμοποιηθούν για τη δημιουργία ειδώλου.
mirror_lfs=Large File Storage (LFS)
mirror_lfs_desc=Ενεργοποίηση αντικατοπτρισμού δεδομένων LFS.
@@ -1015,8 +1006,6 @@ template.issue_labels=Σήματα Ζητήματος
template.one_item=Πρέπει να επιλέξετε τουλάχιστον ένα αντικείμενο στο πρότυπο
template.invalid=Πρέπει να επιλέξετε ένα πρότυπο αποθετήριο
-archive.title=Αυτό το αποθετήρειο αρχειοθετήθηκε. Μπορείτε να προβάλετε αρχεία και να τα κλωνοποιήσετε, αλλά δεν μπορείτε να ωθήσετε ή να ανοίξετε ζητήματα ή pull requests.
-archive.title_date=Αυτό το αποθετήριο έχει αρχειοθετηθεί στο %s. Μπορείτε να προβάλετε αρχεία και να κλωνοποιήσετε, αλλά δεν μπορείτε να ωθήσετε ή να ανοίξετε ζητήματα ή pull requests.
archive.issue.nocomment=Αυτό το αποθετήριο αρχειοθετήθηκε. Δεν μπορείτε να σχολιάσετε σε ζητήματα.
archive.pull.nocomment=Αυτό το repo αρχειοθετήθηκε. Δεν μπορείτε να σχολιάσετε στα pull requests.
@@ -1045,7 +1034,6 @@ migrate_items_releases=Κυκλοφορίες
migrate_repo=Μεταφορά Αποθετηρίου
migrate.clone_address=Μεταφορά / Κλωνοποίηση Από Το URL
migrate.clone_address_desc=Το HTTP(S) ή Git URL 'κλωνοποίησης' ενός υπάρχοντος αποθετηρίου
-migrate.github_token_desc=Μπορείτε να βάλετε ένα ή περισσότερα διακριτικά εδώ, χωρισμένα με κόμμα, για να κάνετε τη μετεγκατάσταση πιο γρήγορα, λόγω του ορίου ρυθμού του GitHub API. ΠΡΟΣΟΧΗ: Η κατάχρηση αυτής της δυνατότητας μπορεί να παραβιάσει την πολιτική του παρόχου υπηρεσιών και να οδηγήσει σε αποκλεισμό του λογαριασμού σας.
migrate.clone_local_path=ή μια διαδρομή τοπικού διακομιστή
migrate.permission_denied=Δεν επιτρέπεται η εισαγωγή τοπικών αποθετηρίων.
migrate.permission_denied_blocked=Δεν μπορείτε να εισαγάγετε από μη επιτρεπόμενους υπολογιστές, παρακαλούμε ζητήστε από τον διαχειριστή να ελέγξει τις ρυθμίσεις ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS.
@@ -1499,7 +1487,6 @@ issues.lock_no_reason=κλειδωμένη και περιορισμένη συ
issues.unlock_comment=ξεκλείδωσε αυτή τη συνομιλία %s
issues.lock_confirm=Κλείδωμα
issues.unlock_confirm=Ξεκλείδωμα
-issues.lock.notice_1=- Άλλοι χρήστες δεν μπορούν να προσθέσουν νέα σχόλια σε αυτό το ζήτημα.
issues.lock.notice_2=- Εσείς και άλλοι συνεργάτες με πρόσβαση σε αυτό το αποθετήριο μπορούν ακόμα να αφήσουν σχόλια που μπορούν να δουν άλλοι.
issues.lock.notice_3=- Μπορείτε πάντα να ξεκλειδώσετε αυτό το ζήτημα ξανά στο μέλλον.
issues.unlock.notice_1=- Όλοι θα ήταν σε θέση να σχολιάσουν αυτό το ζήτημα για άλλη μια φορά.
@@ -1537,7 +1524,6 @@ issues.due_date_form=εεεε-μμ-ηη
issues.due_date_form_add=Προσθήκη ημερομηνίας παράδοσης
issues.due_date_form_edit=Επεξεργασία
issues.due_date_form_remove=Διαγραφή
-issues.due_date_not_writer=Χρειάζεστε πρόσβαση εγγραφής στο αποθετήριο για να ενημερώσετε την ημερομηνία λήξης ενός προβλήματος.
issues.due_date_not_set=Δεν ορίστηκε ημερομηνία παράδοσης.
issues.due_date_added=πρόσθεσε την ημερομηνία παράδοσης %s %s
issues.due_date_modified=τροποποίησε την ημερομηνία παράδοσης από %[2]s σε %[1]s %[3]s
@@ -1788,7 +1774,6 @@ milestones.filter_sort.most_issues=Περισσότερα ζητήματα
milestones.filter_sort.least_issues=Λιγότερα ζητήματα
signing.will_sign=Αυτή η υποβολή θα υπογραφεί με το κλειδί "%s".
-signing.wont_sign.error=Παρουσιάστηκε σφάλμα κατά τον έλεγχο για το αν η υποβολή μπορεί να υπογραφεί.
signing.wont_sign.nokey=Δεν υπάρχει διαθέσιμο κλειδί για να υπογραφεί αυτή η υποβολή.
signing.wont_sign.never=Οι υποβολές δεν υπογράφονται ποτέ.
signing.wont_sign.always=Οι υποβολές υπογράφονται πάντα.
@@ -1875,7 +1860,6 @@ activity.title.releases_1=%d Κυκλοφορία
activity.title.releases_n=%d Εκδόσεις
activity.title.releases_published_by=%s δημοσιεύτηκε από %s
activity.published_release_label=Δημοσιεύθηκε
-activity.no_git_activity=Δεν έχει υπάρξει καμία δραστηριότητα υποβολών σε αυτήν την περίοδο.
activity.git_stats_exclude_merges=Εκτός τις συγχωνεύσεις,
activity.git_stats_author_1=%d συγγραφέας
activity.git_stats_author_n=%d συγγραφείς
@@ -2634,8 +2618,6 @@ dashboard.resync_all_sshprincipals=Ενημέρωση του αρχείου '.ss
dashboard.resync_all_hooks=Επανασυγχρονισμός των hook pre-receive, update και post-receive όλων των αποθετηρίων.
dashboard.reinit_missing_repos=Επανεκκινήστε όλα τα αποθετήρια Git που λείπουν και για τα οποία υπάρχουν εγγραφές
dashboard.sync_external_users=Συγχρονισμός δεδομένων εξωτερικών χρηστών
-dashboard.cleanup_hook_task_table=Εκκαθάριση πίνακα hook_task
-dashboard.cleanup_packages=Εκκαθάριση ληγμένων πακέτων
dashboard.server_uptime=Διάρκεια Διακομιστή
dashboard.current_goroutine=Τρέχουσες Goroutines
dashboard.current_memory_usage=Τρέχουσα Χρήση Μνήμης
@@ -3290,7 +3272,6 @@ owner.settings.cargo.initialize.success=Ο ευρετήριο Cargo δημιου
owner.settings.cargo.rebuild=Αναδημιουργία Ευρετηρίου
owner.settings.cargo.rebuild.description=Η ανοικοδόμηση μπορεί να είναι χρήσιμη εάν ο δείκτης δεν είναι συγχρονισμένος με τα αποθηκευμένα πακέτα Cargo.
owner.settings.cargo.rebuild.error=Αποτυχία αναδόμησης του ευρετηρίου Cargo: %v
-owner.settings.cargo.rebuild.success=Το ευρετήριο Cargo αναδομήθηκε με επιτυχία.
owner.settings.cleanuprules.title=Διαχείριση Κανόνων Εκκαθάρισης
owner.settings.cleanuprules.add=Προσθήκη Κανόνα Εκκαθάρισης
owner.settings.cleanuprules.edit=Επεξεργασία Κανόνα Εκκαθάρισης
@@ -3373,7 +3354,6 @@ runners.delete_runner=Διαγραφή του εκτελεστή
runners.delete_runner_success=Ο εκτελεστής διαγράφηκε επιτυχώς
runners.delete_runner_failed=Αποτυχία διαγραφής εκτελεστή
runners.delete_runner_header=Επιβεβαιώστε για τη διαγραφή του εκτελεστή
-runners.delete_runner_notice=Αν μια εργασία εκτελείται σε αυτόν τον εκτελεστή, θα τερματιστεί και θα επισημανθεί ως αποτυχημένη. Μπορεί να σπάσει το χτίσιμο της ροής εργασίας.
runners.none=Δεν υπάρχουν διαθέσιμοι εκτελεστές
runners.status.unspecified=Άγνωστη
runners.status.idle=Αδρανής
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index f0f5e323631..fe4b188243f 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -117,7 +117,7 @@ files = Files
error = Error
error404 = The page you are trying to reach either does not exist or you are not authorized to view it.
-error503 = The server was unable to complete your request. Please try again later.
+error503 = The server could not complete your request. Please try again later.
go_back = Go Back
invalid_data = Invalid data: %v
nothing_has_been_changed = Nothing has been changed.
@@ -132,7 +132,7 @@ unpin = Unpin
artifacts = Artifacts
expired = Expired
-confirm_delete_artifact = Are you sure you want to delete the artifact '%s' ?
+confirm_delete_artifact = Are you sure you want to delete the artifact '%s'?
archived = Archived
@@ -172,7 +172,7 @@ internal_error_skipped = Internal error occurred but is skipped: %s
search = Search...
type_tooltip = Search type
fuzzy = Fuzzy
-fuzzy_tooltip = Include results that also match the search term closely
+fuzzy_tooltip = Include results that closely match the search term
words = Words
words_tooltip = Include only results that match the search term words
regexp = Regexp
@@ -359,7 +359,7 @@ no_reply_address = Hidden Email Domain
no_reply_address_helper = Domain name for users with a hidden email address. For example, the username 'joe' will be logged in Git as 'joe@noreply.example.org' if the hidden email domain is set to 'noreply.example.org'.
password_algorithm = Password Hash Algorithm
invalid_password_algorithm = Invalid password hash algorithm
-password_algorithm_helper = Set the password hashing algorithm. Algorithms have differing requirements and strength. The argon2 algorithm is rather secure but uses a lot of memory and may be inappropriate for small systems.
+password_algorithm_helper = Set the password hashing algorithm. Algorithms have differing requirements and strengths. The argon2 algorithm is rather secure but uses a lot of memory and may be inappropriate for small systems.
enable_update_checker = Enable Update Checker
enable_update_checker_helper = Checks for new version releases periodically by connecting to gitea.io.
env_config_keys = Environment Configuration
@@ -453,7 +453,7 @@ use_scratch_code = Use a scratch code
twofa_scratch_used = You have used your scratch code. You have been redirected to the two-factor settings page so you may remove your device enrollment or generate a new scratch code.
twofa_passcode_incorrect = Your passcode is incorrect. If you misplaced your device, use your scratch code to sign in.
twofa_scratch_token_incorrect = Your scratch code is incorrect.
-twofa_required = You must setup Two-Factor Authentication to get access to repositories, or try to login again.
+twofa_required = You must set up Two-Factor Authentication to get access to repositories, or try to log in again.
login_userpass = Sign In
login_openid = OpenID
oauth_signup_tab = Register New Account
@@ -465,7 +465,7 @@ oauth_signin_submit = Link Account
oauth.signin.error.general = There was an error processing the authorization request: %s. If this error persists, please contact the site administrator.
oauth.signin.error.access_denied = The authorization request was denied.
oauth.signin.error.temporarily_unavailable = Authorization failed because the authentication server is temporarily unavailable. Please try again later.
-oauth_callback_unable_auto_reg = Auto Registration is enabled, but OAuth2 Provider %[1]s returned missing fields: %[2]s, unable to create an account automatically, please create or link to an account, or contact the site administrator.
+oauth_callback_unable_auto_reg = Auto Registration is enabled, but OAuth2 Provider %[1]s returned missing fields: %[2]s, unable to create an account automatically. Please create or link to an account, or contact the site administrator.
openid_connect_submit = Connect
openid_connect_title = Connect to an existing account
openid_connect_desc = The chosen OpenID URI is unknown. Associate it with a new account here.
@@ -478,7 +478,7 @@ email_domain_blacklisted = You cannot register with your email address.
authorize_application = Authorize Application
authorize_redirect_notice = You will be redirected to %s if you authorize this application.
authorize_application_created_by = This application was created by %s.
-authorize_application_description = If you grant the access, it will be able to access and write to all your account information, including private repos and organisations.
+authorize_application_description = If you grant access, it will be able to access and write to all your account information, including private repos and organisations.
authorize_application_with_scopes = With scopes: %s
authorize_title = Authorize "%s" to access your account?
authorization_failed = Authorization failed
@@ -507,8 +507,8 @@ activate_email.text = Please click the following link to verify your email addre
register_notify = Welcome to %s
register_notify.title = %[1]s, welcome to %[2]s
-register_notify.text_1 = this is your registration confirmation email for %s!
-register_notify.text_2 = You can now login via username: %s.
+register_notify.text_1 = This is your registration confirmation email for %s!
+register_notify.text_2 = You can now log in via username: %s.
register_notify.text_3 = If this account has been created for you, please set your password first.
reset_password = Recover your account
@@ -690,7 +690,7 @@ form.name_chars_not_allowed = User name "%s" contains invalid characters.
block.block = Block
block.block.user = Block user
-block.block.org = Block user for organization
+block.block.org = Block user from organization
block.block.failure = Failed to block user: %s
block.unblock = Unblock
block.unblock.failure = Failed to unblock user: %s
@@ -734,7 +734,7 @@ webauthn = Two-Factor Authentication (Security Keys)
public_profile = Public Profile
biography_placeholder = Tell us a little bit about yourself! (You can use Markdown)
location_placeholder = Share your approximate location with others
-profile_desc = Control how your profile is show to other users. Your primary email address will be used for notifications, password recovery and web-based Git operations.
+profile_desc = Control how your profile is shown to other users. Your primary email address will be used for notifications, password recovery and web-based Git operations.
password_username_disabled = You are not allowed to change your username. Please contact your site administrator for more details.
password_full_name_disabled = You are not allowed to change your full name. Please contact your site administrator for more details.
full_name = Full Name
@@ -813,7 +813,7 @@ activations_pending = Activations Pending
can_not_add_email_activations_pending = There is a pending activation, try again in a few minutes if you want to add a new email.
delete_email = Remove
email_deletion = Remove Email Address
-email_deletion_desc = The email address and related information will be removed from your account. Git commits by this email address will remain unchanged. Continue?
+email_deletion_desc = This email address and related information will be removed from your account. Git commits by this email address will remain unchanged. Continue?
email_deletion_success = The email address has been removed.
theme_update_success = Your theme was updated.
theme_update_error = The selected theme does not exist.
@@ -999,7 +999,7 @@ webauthn_alternative_tip = You may want to configure an additional authenticatio
manage_account_links = Manage Linked Accounts
manage_account_links_desc = These external accounts are linked to your Gitea account.
-account_links_not_available = There are currently no external accounts linked to your Gitea account.
+account_links_not_available = No external accounts are currently linked to your Gitea account.
link_account = Link Account
remove_account_link = Remove Linked Account
remove_account_link_desc = Removing a linked account will revoke its access to your Gitea account. Continue?
@@ -1022,6 +1022,8 @@ email_notifications.onmention = Only Email on Mention
email_notifications.disable = Disable Email Notifications
email_notifications.submit = Set Email Preference
email_notifications.andyourown = And Your Own Notifications
+email_notifications.actions.desc = Notifications for workflow runs on repositories set up with Gitea Actions.
+email_notifications.actions.failure_only = Only notify for failed workflow runs
visibility = User visibility
visibility.public = Public
@@ -1036,8 +1038,8 @@ new_repo_helper = A repository contains all project files, including revision hi
owner = Owner
owner_helper = Some organizations may not show up in the dropdown due to a maximum repository count limit.
repo_name = Repository Name
-repo_name_profile_public_hint= .profile is a special repository that you can use to add README.md to your public organization profile, visible to anyone. Make sure it’s public and initialize it with a README in the profile directory to get started.
-repo_name_profile_private_hint = .profile-private is a special repository that you can use to add a README.md to your organization member profile, visible only to organization members. Make sure it’s private and initialize it with a README in the profile directory to get started.
+repo_name_profile_public_hint= .profile is a special repository that you can use to add README.md to your public organization profile, visible to anyone. Make sure it's public and initialize it with a README in the profile directory to get started.
+repo_name_profile_private_hint = .profile-private is a special repository that you can use to add a README.md to your organization member profile, visible only to organization members. Make sure it's private and initialize it with a README in the profile directory to get started.
repo_name_helper = Good repository names use short, memorable and unique keywords. A repository named ".profile" or ".profile-private" could be used to add a README.md for the user/organization profile.
repo_size = Repository Size
template = Template
@@ -1059,7 +1061,7 @@ fork_branch = Branch to be cloned to the fork
all_branches = All branches
view_all_branches = View all branches
view_all_tags = View all tags
-fork_no_valid_owners = This repository can not be forked because there are no valid owners.
+fork_no_valid_owners = This repository cannot be forked because there are no valid owners.
fork.blocked_user = Cannot fork the repository because you are blocked by the repository owner.
use_template = Use this template
open_with_editor = Open with %s
@@ -1103,7 +1105,7 @@ mirror_sync = synced
mirror_sync_on_commit = Sync when commits are pushed
mirror_address = Clone From URL
mirror_address_desc = Put any required credentials in the Authorization section.
-mirror_address_url_invalid = The provided URL is invalid. You must escape all components of the url correctly.
+mirror_address_url_invalid = The provided URL is invalid. Make sure all components of the URL are escaped correctly.
mirror_address_protocol_invalid = The provided URL is invalid. Only http(s):// or git:// locations can be used for mirroring.
mirror_lfs = Large File Storage (LFS)
mirror_lfs_desc = Activate mirroring of LFS data.
@@ -1163,8 +1165,8 @@ template.issue_labels = Issue Labels
template.one_item = Must select at least one template item
template.invalid = Must select a template repository
-archive.title = This repo is archived. You can view files and clone it, but cannot push or open issues or pull requests.
-archive.title_date = This repository has been archived on %s. You can view files and clone it, but cannot push or open issues or pull requests.
+archive.title = This repo is archived. You can view files and clone it. You cannot open issues, pull requests or push a commit.
+archive.title_date = This repository has been archived on %s. You can view files and clone it. You cannot open issues, pull requests or push a commit.
archive.issue.nocomment = This repo is archived. You cannot comment on issues.
archive.pull.nocomment = This repo is archived. You cannot comment on pull requests.
@@ -1193,7 +1195,7 @@ migrate_items_releases = Releases
migrate_repo = Migrate Repository
migrate.clone_address = Migrate / Clone From URL
migrate.clone_address_desc = The HTTP(S) or Git 'clone' URL of an existing repository
-migrate.github_token_desc = You can put one or more tokens with comma separated here to make migrating faster because of GitHub API rate limit. WARN: Abusing this feature may violate the service provider's policy and lead to account blocking.
+migrate.github_token_desc = You can put one or more tokens here separated by commas to make migrating faster by circumventing the GitHub API rate limit. WARNING: Abusing this feature may violate the service provider's policy and may lead to getting your account(s) blocked.
migrate.clone_local_path = or a local server path
migrate.permission_denied = You are not allowed to import local repositories.
migrate.permission_denied_blocked = You cannot import from disallowed hosts, please ask the admin to check ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS settings.
@@ -1255,7 +1257,7 @@ create_new_repo_command = Creating a new repository on the command line
push_exist_repo = Pushing an existing repository from the command line
empty_message = This repository does not contain any content.
broken_message = The Git data underlying this repository cannot be read. Contact the administrator of this instance or delete this repository.
-no_branch = This repository doesn’t have any branches.
+no_branch = This repository doesn't have any branches.
code = Code
code.desc = Access source code, files, commits and branches.
@@ -1401,8 +1403,8 @@ editor.failed_to_commit = Failed to commit changes.
editor.failed_to_commit_summary = Error Message:
editor.fork_create = Fork Repository to Propose Changes
-editor.fork_create_description = You can not edit this repository directly. Instead you can create a fork, make edits and create a pull request.
-editor.fork_edit_description = You can not edit this repository directly. The changes will be written to your fork %s, so you can create a pull request.
+editor.fork_create_description = You cannot edit this repository directly. Instead you can create a fork, make edits and create a pull request.
+editor.fork_edit_description = You cannot edit this repository directly. The changes will be written to your fork %s, so you can create a pull request.
editor.fork_not_editable = You have forked this repository but your fork is not editable.
editor.fork_failed_to_push_branch = Failed to push branch %s to your repository.
editor.fork_branch_exists = Branch "%s" already exists in your fork, please choose a new branch name.
@@ -1701,7 +1703,7 @@ issues.lock_no_reason = "locked and limited conversation to collaborators %s"
issues.unlock_comment = "unlocked this conversation %s"
issues.lock_confirm = Lock
issues.unlock_confirm = Unlock
-issues.lock.notice_1 = - Other users can’t add new comments to this issue.
+issues.lock.notice_1 = - Other users cannot add new comments to this issue.
issues.lock.notice_2 = - You and other collaborators with access to this repository can still leave comments that others can see.
issues.lock.notice_3 = - You can always unlock this issue again in the future.
issues.unlock.notice_1 = - Everyone would be able to comment on this issue once more.
@@ -1756,7 +1758,7 @@ issues.due_date_form = "yyyy-mm-dd"
issues.due_date_form_add = "Add due date"
issues.due_date_form_edit = "Edit"
issues.due_date_form_remove = "Remove"
-issues.due_date_not_writer = "You need write access to this repository in order to update the due date of an issue."
+issues.due_date_not_writer = "You need write access to this repository to update the due date of an issue."
issues.due_date_not_set = "No due date set."
issues.due_date_added = "added the due date %s %s"
issues.due_date_modified = "modified the due date from %[2]s to %[1]s %[3]s"
@@ -1870,7 +1872,7 @@ pulls.select_commit_hold_shift_for_range = Select commit. Hold shift + click to
pulls.review_only_possible_for_full_diff = Review is only possible when viewing the full diff
pulls.filter_changes_by_commit = Filter by commit
pulls.nothing_to_compare = These branches are equal. There is no need to create a pull request.
-pulls.nothing_to_compare_have_tag = The selected branch/tag are equal.
+pulls.nothing_to_compare_have_tag = The selected branches/tags are equal.
pulls.nothing_to_compare_and_allow_empty_pr = These branches are equal. This PR will be empty.
pulls.has_pull_request = `A pull request between these branches already exists: %[2]s#%[3]d`
pulls.create = Create Pull Request
@@ -2033,7 +2035,7 @@ milestones.filter_sort.most_issues = Most issues
milestones.filter_sort.least_issues = Least issues
signing.will_sign = This commit will be signed with key "%s".
-signing.wont_sign.error = There was an error whilst checking if the commit could be signed.
+signing.wont_sign.error = There was an error while checking if the commit could be signed.
signing.wont_sign.nokey = There is no key available to sign this commit.
signing.wont_sign.never = Commits are never signed.
signing.wont_sign.always = Commits are always signed.
@@ -2124,7 +2126,7 @@ activity.title.releases_1 = %d Release
activity.title.releases_n = %d Releases
activity.title.releases_published_by = %s published by %s
activity.published_release_label = Published
-activity.no_git_activity = There has not been any commit activity in this period.
+activity.no_git_activity = There has been no commit activity in this period.
activity.git_stats_exclude_merges = Excluding merges,
activity.git_stats_author_1 = %d author
activity.git_stats_author_n = %d authors
@@ -2542,7 +2544,7 @@ settings.block_on_official_review_requests_desc = Merging will not be possible w
settings.block_outdated_branch = Block merge if pull request is outdated
settings.block_outdated_branch_desc = Merging will not be possible when head branch is behind base branch.
settings.block_admin_merge_override = Administrators must follow branch protection rules
-settings.block_admin_merge_override_desc = Administrators must follow branch protection rules and can not circumvent it.
+settings.block_admin_merge_override_desc = Administrators must follow branch protection rules and cannot circumvent it.
settings.default_branch_desc = Select a default repository branch for pull requests and code commits:
settings.merge_style_desc = Merge Styles
settings.default_merge_style_desc = Default Merge Style
@@ -2569,10 +2571,10 @@ settings.matrix.homeserver_url = Homeserver URL
settings.matrix.room_id = Room ID
settings.matrix.message_type = Message Type
settings.visibility.private.button = Make Private
-settings.visibility.private.text = Changing the visibility to private will not only make the repo visible to only allowed members but may remove the relation between it and forks, watchers, and stars.
+settings.visibility.private.text = Changing the visibility to private will make the repo visible only to allowed members and may remove the relationship between it and existing forks, watchers, and stars.
settings.visibility.private.bullet_title = Changing the visibility to private will:
-settings.visibility.private.bullet_one = Make the repo visible to only allowed members.
-settings.visibility.private.bullet_two = May remove the relation between it and forks, watchers, and stars.
+settings.visibility.private.bullet_one = Make the repo visible only to allowed members.
+settings.visibility.private.bullet_two = May remove the relationship between it and forks, watchers, and stars.
settings.visibility.public.button = Make Public
settings.visibility.public.text = Changing the visibility to public will make the repo visible to anyone.
settings.visibility.public.bullet_title= Changing the visibility to public will:
@@ -2827,7 +2829,7 @@ team_permission_desc = Permission
team_unit_desc = Allow Access to Repository Sections
team_unit_disabled = (Disabled)
-form.name_been_taken = The organisation name "%s" has already been taken.
+form.name_been_taken = The organization name "%s" has already been taken.
form.name_reserved = The organization name "%s" is reserved.
form.name_pattern_not_allowed = The pattern "%s" is not allowed in an organization name.
form.create_org_not_allowed = You are not allowed to create an organization.
@@ -2875,7 +2877,7 @@ settings.delete_notices_2 = This operation will permanently delete all the packages of %s.
settings.delete_notices_4 = This operation will permanently delete all the projects of %s.
settings.confirm_delete_account = Confirm Deletion
-settings.delete_failed = Delete Organization failed because of internal error
+settings.delete_failed = Delete Organization failed due to an internal error
settings.delete_successful = Organization %s has been deleted successfully.
settings.hooks_desc = Add webhooks which will be triggered for all repositories under this organization.
@@ -3025,9 +3027,9 @@ dashboard.resync_all_sshprincipals = Update the '.ssh/authorized_principals' fil
dashboard.resync_all_hooks = Resynchronize pre-receive, update and post-receive hooks of all repositories.
dashboard.reinit_missing_repos = Reinitialize all missing Git repositories for which records exist
dashboard.sync_external_users = Synchronize external user data
-dashboard.cleanup_hook_task_table = Cleanup hook_task table
-dashboard.cleanup_packages = Cleanup expired packages
-dashboard.cleanup_actions = Cleanup expired actions resources
+dashboard.cleanup_hook_task_table = Clean up hook_task table
+dashboard.cleanup_packages = Clean up expired packages
+dashboard.cleanup_actions = Clean up expired actions' resources
dashboard.server_uptime = Server Uptime
dashboard.current_goroutine = Current Goroutines
dashboard.current_memory_usage = Current Memory Usage
@@ -3258,6 +3260,8 @@ auths.oauth2_required_claim_name_helper = Set this name to restrict login from t
auths.oauth2_required_claim_value = Required Claim Value
auths.oauth2_required_claim_value_helper = Set this value to restrict login from this source to users with a claim with this name and value
auths.oauth2_group_claim_name = Claim name providing group names for this source. (Optional)
+auths.oauth2_full_name_claim_name = Full Name Claim Name. (Optional, if set, the user's full name will always be synchronized with this claim)
+auths.oauth2_ssh_public_key_claim_name = SSH Public Key Claim Name
auths.oauth2_admin_group = Group Claim value for administrator users. (Optional - requires claim name above)
auths.oauth2_restricted_group = Group Claim value for restricted users. (Optional - requires claim name above)
auths.oauth2_map_group_to_team = Map claimed groups to Organization teams. (Optional - requires claim name above)
@@ -3462,7 +3466,7 @@ monitor.start = Start Time
monitor.execute_time = Execution Time
monitor.last_execution_result = Result
monitor.process.cancel = Cancel process
-monitor.process.cancel_desc = Cancelling a process may cause data loss
+monitor.process.cancel_desc = Canceling a process may cause data loss
monitor.process.children = Children
monitor.queues = Queues
@@ -3734,7 +3738,7 @@ owner.settings.cargo.initialize.success = The Cargo index was successfully creat
owner.settings.cargo.rebuild = Rebuild Index
owner.settings.cargo.rebuild.description = Rebuilding can be useful if the index is not synchronized with the stored Cargo packages.
owner.settings.cargo.rebuild.error = Failed to rebuild Cargo index: %v
-owner.settings.cargo.rebuild.success = The Cargo index was successfully rebuild.
+owner.settings.cargo.rebuild.success = The Cargo index was successfully rebuilt.
owner.settings.cleanuprules.title = Manage Cleanup Rules
owner.settings.cleanuprules.add = Add Cleanup Rule
owner.settings.cleanuprules.edit = Edit Cleanup Rule
@@ -3822,7 +3826,7 @@ runners.delete_runner = Delete this runner
runners.delete_runner_success = Runner deleted successfully
runners.delete_runner_failed = Failed to delete runner
runners.delete_runner_header = Confirm to delete this runner
-runners.delete_runner_notice = If a task is running on this runner, it will be terminated and mark as failed. It may break building workflow.
+runners.delete_runner_notice = If a task is running on this runner, it will be terminated and marked as failed. It may break building workflow.
runners.none = No runners available
runners.status.unspecified = Unknown
runners.status.idle = Idle
diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini
index 9359bacc046..0ee3080cb6a 100644
--- a/options/locale/locale_es-ES.ini
+++ b/options/locale/locale_es-ES.ini
@@ -301,7 +301,6 @@ no_reply_address=Dominio de correos electrónicos ocultos
no_reply_address_helper=Nombre de dominio para usuarios con dirección de correo electrónico oculta. Por ejemplo, el usuario 'joe' quedará registrado en Git como 'joe@noreply.example.org' si el dominio de correo electrónico oculto se establece a 'noreply.example.org'.
password_algorithm=Algoritmo Hash de Contraseña
invalid_password_algorithm=Algoritmo hash de contraseña no válido
-password_algorithm_helper=Establece el algoritmo de hashing de contraseña. Los algoritmos tienen diferentes requisitos y fuerza. El algoritmo argon2 es bastante seguro, pero usa mucha memoria y puede ser inapropiado para sistemas pequeños.
enable_update_checker=Activar comprobador de actualizaciones
enable_update_checker_helper=Comprueba el lanzamiento de nuevas versiones periódicamente en gitea.io.
env_config_keys=Configuración del entorno
@@ -401,7 +400,6 @@ email_domain_blacklisted=No puede registrarse con su correo electrónico.
authorize_application=Autorizar aplicación
authorize_redirect_notice=Será redirigido a %s si autoriza esta aplicación.
authorize_application_created_by=Esta aplicación fue creada por %s.
-authorize_application_description=Si concede el acceso, podrá acceder y escribir a toda la información de su cuenta, incluyendo repositorios privado y organizaciones.
authorize_title=¿Autorizar a "%s" a acceder a su cuenta?
authorization_failed=Autorización fallida
authorization_failed_desc=La autorización ha fallado porque hemos detectado una solicitud no válida. Por favor, póngase en contacto con el responsable de la aplicación que ha intentado autorizar.
@@ -424,8 +422,6 @@ activate_email.title=%s, por favor verifique su dirección de correo electrónic
activate_email.text=Por favor, haga clic en el siguiente enlace para verificar su dirección de correo electrónico dentro de %s:
register_notify.title=%[1]s, bienvenido a %[2]s
-register_notify.text_1=este es tu correo de confirmación de registro para %s!
-register_notify.text_2=Ahora puede iniciar sesión vía nombre de usuario: %s.
register_notify.text_3=Si esta cuenta ha sido creada para usted, por favor establezca su contraseña primero.
reset_password=Recupere su cuenta
@@ -619,7 +615,6 @@ uid=UID
public_profile=Perfil público
biography_placeholder=¡Cuéntanos un poco sobre ti mismo! (Puedes usar Markdown)
location_placeholder=Comparte tu ubicación aproximada con otros
-profile_desc=Controla cómo se muestra su perfil a otros usuarios. Tu dirección de correo electrónico principal se utilizará para notificaciones, recuperación de contraseña y operaciones de Git basadas en la web.
full_name=Nombre completo
website=Página web
location=Localización
@@ -692,7 +687,6 @@ activations_pending=Activaciones pendientes
can_not_add_email_activations_pending=Hay una activación pendiente, inténtelo de nuevo en unos minutos si desea agregar un nuevo correo electrónico.
delete_email=Eliminar
email_deletion=Eliminar dirección de correo electrónico
-email_deletion_desc=La dirección de correo electrónico e información relacionada se eliminará de su cuenta. Los commits de Git hechos por esta dirección de correo electrónico permanecerán inalterados. ¿Continuar?
email_deletion_success=La dirección de correo electrónico ha sido eliminada.
theme_update_success=Su tema fue actualizado.
theme_update_error=El tema seleccionado no existe.
@@ -862,7 +856,6 @@ webauthn_delete_key_desc=Si elimina una llave de seguridad ya no podrá utilizar
manage_account_links=Administrar cuentas vinculadas
manage_account_links_desc=Estas cuentas externas están vinculadas a su cuenta de Gitea.
-account_links_not_available=Actualmente no hay cuentas externas vinculadas a su cuenta de Gitea.
link_account=Enlazar cuenta
remove_account_link=Eliminar cuenta vinculada
remove_account_link_desc=Eliminar una cuenta vinculada revocará su acceso a su cuenta de Gitea. ¿Continuar?
@@ -916,7 +909,6 @@ fork_to_different_account=Forkear a una cuenta diferente
fork_visibility_helper=La visibilidad de un repositorio del cual se ha hecho fork no puede ser cambiada.
fork_branch=Rama a clonar en la bifurcación
all_branches=Todas las ramas
-fork_no_valid_owners=Este repositorio no puede ser bifurcado porque no hay propietarios válidos.
use_template=Utilizar esta plantilla
download_zip=Descargar ZIP
download_tar=Descargar TAR.GZ
@@ -952,7 +944,6 @@ mirror_interval_invalid=El intervalo de réplica no es válido.
mirror_sync_on_commit=Sincronizar cuando los commits sean subidos
mirror_address=Clonar desde URL
mirror_address_desc=Ponga cualquier credencial requerida en la sección de Autorización.
-mirror_address_url_invalid=La URL proporcionada no es válida. Debe escapar todos los componentes de la url correctamente.
mirror_address_protocol_invalid=La URL proporcionada no es válida. Sólo http(s):// o git:// se puede utilizar para ser replicadas.
mirror_lfs=Almacenamiento de archivos grande (LFS)
mirror_lfs_desc=Activar la reproducción de datos LFS.
@@ -1005,8 +996,6 @@ template.issue_labels=Etiquetas de incidencia
template.one_item=Debe seleccionar al menos un elemento de plantilla
template.invalid=Debe seleccionar una plantilla de repositorio
-archive.title=Este repositorio está archivado. Usted puede ver los archivos y clonarlos, pero no puede hace push o abrir incidencias o pull requests.
-archive.title_date=Este repositorio ha sido archivado en %s. Puedes ver archivos y clonarlo, pero no puedes hacer push o abrir incidencias o pull request.
archive.issue.nocomment=Este repositorio está archivado. No se puede comentar en las incidencias.
archive.pull.nocomment=Este repositorio está archivado. No se puede comentar en los pull requests.
@@ -1035,7 +1024,6 @@ migrate_items_releases=Lanzamientos
migrate_repo=Migrar Repositorio
migrate.clone_address=Migrar / Clonar desde URL
migrate.clone_address_desc=La URL HTTP(S) o de Git 'clone' de un repositorio existente
-migrate.github_token_desc=Puedes poner uno o más tokens con comas separadas aquí para hacer migrar más rápido debido al límite de velocidad de GitHub API. PRECAUCIÓN: Abusar esta característica puede violar la política del proveedor de servicios y llevar a bloquear la cuenta.
migrate.clone_local_path=o una ruta local del servidor
migrate.permission_denied=No te está permitido importar repositorios locales.
migrate.permission_denied_blocked=No puede importar desde hosts no permitidos, por favor pida al administrador que marque ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS configuración.
@@ -1489,7 +1477,6 @@ issues.lock_no_reason=conversación limitada y bloqueada a los colaboradores %s
issues.unlock_comment=desbloqueó esta conversación %s
issues.lock_confirm=Bloquear
issues.unlock_confirm=Desbloquear
-issues.lock.notice_1=- Otros usuarios no pueden añadir nuevos comentarios a esta incidencia.
issues.lock.notice_2=- Usted y otros colaboradores con acceso a este repositorio todavía pueden dejar comentarios que otros pueden ver.
issues.lock.notice_3=- Siempre puede desbloquear esta incidencia de nuevo en el futuro.
issues.unlock.notice_1=- Todos podrían comentar esta incidencia de nuevo.
@@ -1527,7 +1514,6 @@ issues.due_date_form=aaaa-mm-dd
issues.due_date_form_add=Añadir fecha de vencimiento
issues.due_date_form_edit=Editar
issues.due_date_form_remove=Eliminar
-issues.due_date_not_writer=Necesita acceso de escritura a este repositorio para actualizar la fecha límite de de una incidencia.
issues.due_date_not_set=Sin fecha de vencimiento.
issues.due_date_added=añadió la fecha de vencimiento %s %s
issues.due_date_modified=modificó la fecha de vencimiento de %[2]s a %[1]s %[3]s
@@ -1772,7 +1758,6 @@ milestones.filter_sort.most_issues=Mayoría de los problemas
milestones.filter_sort.least_issues=Menos problemas
signing.will_sign=Este commit se firmará con la clave "%s".
-signing.wont_sign.error=Hubo un error mientras se comprobaba si la confirmación podía ser firmada.
signing.wont_sign.nokey=No hay ninguna clave disponible para firmar este commit.
signing.wont_sign.never=Nunca se firman los commits.
signing.wont_sign.always=Siempre se firman los commits.
@@ -1859,7 +1844,6 @@ activity.title.releases_1=%d Lanzamiento
activity.title.releases_n=%d Lanzamientos
activity.title.releases_published_by=%s publicado por %s
activity.published_release_label=Publicado
-activity.no_git_activity=No ha habido ningún commit en este período.
activity.git_stats_exclude_merges=Excluyendo fusiones,
activity.git_stats_author_1=%d autor
activity.git_stats_author_n=%d autores
@@ -2616,8 +2600,6 @@ dashboard.resync_all_sshprincipals=Actualizar el archivo '.ssh/authorized_princi
dashboard.resync_all_hooks=Resincronizar los hooks de pre-recepción, actualización y post-recepción de todos los repositorios.
dashboard.reinit_missing_repos=Reiniciar todos los repositorios Git faltantes de los que existen registros
dashboard.sync_external_users=Sincronizar datos de usuario externo
-dashboard.cleanup_hook_task_table=Limpiar tabla hook_task
-dashboard.cleanup_packages=Limpieza de paquetes caducados
dashboard.server_uptime=Tiempo de actividad del servidor
dashboard.current_goroutine=Gorutinas actuales
dashboard.current_memory_usage=Uso de memoria actual
@@ -3270,7 +3252,6 @@ owner.settings.cargo.initialize.success=El índice de Cargo se ha creado correct
owner.settings.cargo.rebuild=Reconstruir índice
owner.settings.cargo.rebuild.description=Reconstruir puede ser útil si el índice no se sincroniza con los paquetes de Cargo almacenados.
owner.settings.cargo.rebuild.error=Fallo al reconstruir el índice de Cargo: %v
-owner.settings.cargo.rebuild.success=El índice de Cargo se ha reconstruido correctamente.
owner.settings.cleanuprules.title=Administrar reglas de limpieza
owner.settings.cleanuprules.add=Añadir regla de limpieza
owner.settings.cleanuprules.edit=Editar regla de limpieza
@@ -3353,7 +3334,6 @@ runners.delete_runner=Eliminar este nodo
runners.delete_runner_success=Nodo eliminado con éxito
runners.delete_runner_failed=Fallo al eliminar el nodo
runners.delete_runner_header=Confirma para eliminar el nodo
-runners.delete_runner_notice=Si una tarea se está ejecutando en este nodo, se terminará y marcará como fallida. Puede romper el flujo de trabajo en curso.
runners.none=No hay nodos disponibles
runners.status.unspecified=Desconocido
runners.status.idle=Inactivo
diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini
index c201973a095..56582510434 100644
--- a/options/locale/locale_fa-IR.ini
+++ b/options/locale/locale_fa-IR.ini
@@ -312,7 +312,6 @@ email_domain_blacklisted=شما نمیتوانید با ایمیل خود ثبت
authorize_application=برنامه احراز هویت
authorize_redirect_notice=اگر شما این برنامه را تایید کنید، به %s منتقل خواهید شد.
authorize_application_created_by=این برنامه توسط %s ساخته شده است.
-authorize_application_description=اگر شما دسترسی داشته باشید. میتوانید تمامی فیلد های حساب کاربری خود را تغییر دهید. از جمله مخازن و سازمان های خصوصی.
authorize_title=تاییدیه "%s" برای دسترسی به اکانت شما؟
authorization_failed=احراز هویت انجام نشد
sspi_auth_failed=SSPI عدم احراز هویت
@@ -332,8 +331,6 @@ activate_email=نشانی ایمیل خود را تایید کنید
activate_email.text=لطفاً روی پیوند زیر کلیک کنید تا رایانامهی خود را در %s تأیید کنید:
register_notify.title=%[1]s، به %[2]s خوشآمدید
-register_notify.text_1=این رایانامهی تأیید عضویت شما در %s است!
-register_notify.text_2=حالا شما میتوانید با نام کاربری وارد شوید: %s.
register_notify.text_3=اگر این حساب برای شما ایجاد شده، لطفاً ابتدا گذرواژهی خود را تنظیم کنید.
reset_password=حساب خود را دوباره فعال کنید
@@ -541,7 +538,6 @@ activate_email=ارسال فعالسازی
activations_pending=کدهای فعالسازی در انتظار
delete_email=حذف
email_deletion=حذف نشانی ایمیل
-email_deletion_desc=نشانی ایمیل و اطلاعات مربوطه از حساب شما حذف خواهد شد. تمامی کامیت ها توسط این نشانی ایمیل بدون تغییر باقی می ماند. ادامه می دهید؟
email_deletion_success=آدرس ایمیل شما حذف شده است.
theme_update_success=پوسته شما آپدیت شد.
theme_update_error=پوسته انتخاب شده موجود نیست.
@@ -675,7 +671,6 @@ twofa_failed_get_secret=خطا در دریافت رمز.
manage_account_links=مدیریت حساب های مرتبط شده
manage_account_links_desc=این حساب های خارجی به حساب Gitea ارتباط دارد.
-account_links_not_available=اکنون دیگر هیچ پیوند حسابهای کاربری خارجی به حساب کاربری شما وجود ندارد.
link_account=پیوند به حساب
remove_account_link=حذف حساب پیوند خرده
remove_account_link_desc=با حذف پیوند خارجی حساب کاربری دسترسی شما به حساب کابریتان توسط آن از بین میرود. آیا ادامه میدهید؟
@@ -1152,7 +1147,6 @@ issues.lock_no_reason=قفل شده و مکالمه برای همکاران %s
issues.unlock_comment=باز کردن این مکالمه %s
issues.lock_confirm=قفل کردن
issues.unlock_confirm=رفع انسداد
-issues.lock.notice_1=- دیگر کاربران نمیتوانند یک مولفه جدید به مسئله اضافه کنند.
issues.lock.notice_2=- شما و سایر همکاران با دسترسی به این مخزن هنوز میتوانید اظهار نظر کنید و سایرین آن را مشاهده میکنند.
issues.lock.notice_3=- شما همیشه میتوانید مجدداً در آینده این مسئله را باز کنید.
issues.unlock.notice_1=- همه می توانند بار دیگر درباره این موضوع اظهارنظر کنند.
@@ -1437,7 +1431,6 @@ activity.title.releases_1=%d انتشار
activity.title.releases_n=%d انتشار
activity.title.releases_published_by=%s منشتر شده توسط %s
activity.published_release_label=منتشر شده
-activity.no_git_activity=در این دوره فعالیت کامیتی ارسال نشده است.
activity.git_stats_exclude_merges=به استثنای ادغامها ،
activity.git_stats_author_1=%d بانی
activity.git_stats_author_n=%d بانی
@@ -2036,7 +2029,6 @@ dashboard.resync_all_sshprincipals=فایل '.ssh/authorized_principals' را ب
dashboard.resync_all_hooks=همگام سازی مجدد hook های pre-receive و update و post-receive برای تمامی مخازن.
dashboard.reinit_missing_repos=تمامی مخازنی که سوابقشان وجود دارند مجدداً گیت آنها مفقود شده است مجدداً مقدمات آنها فراهم شود
dashboard.sync_external_users=همگام سازی اطلاعات کاربر خارجی
-dashboard.cleanup_hook_task_table=جدول hook_task تمیز کردن
dashboard.server_uptime=فعالیت بیوقفه سرور
dashboard.current_goroutine=Goroutine های فعلی
dashboard.current_memory_usage=میزان مصرف فعلی از حافظه
diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini
index fc48f1b7aa2..b60a88f1c00 100644
--- a/options/locale/locale_fi-FI.ini
+++ b/options/locale/locale_fi-FI.ini
@@ -321,7 +321,6 @@ email_domain_blacklisted=Et voi rekisteröityä sähköpostiosoittellasi.
authorize_application=Valtuuta sovellus
authorize_redirect_notice=Sinut uudelleen ohjataan osoitteeseen %s jos valtuutat tämän sovelluksen.
authorize_application_created_by=Tämän sovelluksen on luonnut %s.
-authorize_application_description=Jos myönnät valtuuden, sovellus voi käyttää kaikkia tilitietojasi ja kirjoittaa niihin, mukaan lukien yksityiset repot ja organisaatiot.
authorize_title=Valtuutatko "%s" pääsemään tilillesi?
authorization_failed=Käyttöoikeuden varmistus epäonnistui
sspi_auth_failed=SSPI todennus epäonnistui
@@ -335,7 +334,6 @@ activate_account=Ole hyvä ja aktivoi tilisi
activate_email=Vahvista sähköpostiosoitteesi
-register_notify.text_2=Voit nyt kirjautua käyttäjätunnuksella: %s.
reset_password=Palauta käyttäjätili
reset_password.title=%s, olet pyytänyt tilisi palauttamista
@@ -513,7 +511,6 @@ activate_email=Lähetä aktivointi
activations_pending=Odottaa aktivointia
delete_email=Poista
email_deletion=Poista sähköpostiosoite
-email_deletion_desc=Sähköpostiosoite ja siihen liittyvät tiedot poistetaan tililtäsi. Kyseisen sähköpostiosoitteen sisältävät commitit pysyvät muuttumattomia. Jatketaanko?
email_deletion_success=Sähköpostiosoite on poistettu.
theme_update_success=Teemasi on päivitetty.
theme_update_error=Valittua teemaa ei löydy.
@@ -690,7 +687,6 @@ migrate_items_pullrequests=Vetopyynnöt
migrate_items_releases=Julkaisut
migrate_repo=Siirrä repo
migrate.clone_address=Migraation / Kloonaa URL osoitteesta
-migrate.github_token_desc=Voit laittaa yhden tai useamman pääsymerkin pilkulla erotellen tähän nopeuttaaksesi migraatiota GitHub APIn vauhtirajojen takia. VAROITUS: Tämän ominaisuuden väärinkäyttö voi rikkoa palveluntarjoajan ehtoja ja johtaa tilin estämiseen.
migrate.permission_denied=Sinun ei sallita tuovan paikallisia repoja.
migrate.failed=Siirto epäonnistui: %v
migrate.migrate_items_options=Pääsymerkki vaaditaan lisäkohteiden siirtämiseen
@@ -908,7 +904,6 @@ issues.unlock=Avaa keskustelu
issues.unlock_comment=aukaisi tämän keskustelun uudelleen %s
issues.lock_confirm=Lukitse
issues.unlock_confirm=Avaa
-issues.lock.notice_1=- Muut käyttäjät eivät voi lisätä uusia kommentteja tähän ongelmaan.
issues.lock.notice_3=- Voit aina myöhemmin avata tämän ongelman lukituksesta.
issues.unlock.notice_2=- Voit aina myöhemmin lukita tämän ongelman uudelleen.
issues.lock.reason=Lukitsemisen syy
diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini
index b72eb2bb7f8..a796659e94d 100644
--- a/options/locale/locale_fr-FR.ini
+++ b/options/locale/locale_fr-FR.ini
@@ -117,7 +117,7 @@ files=Fichiers
error=Erreur
error404=La page que vous essayez d'atteindre n'existe pas ou vous n'êtes pas autorisé à la voir.
-error503=Le serveur n’a pas pu répondre à votre requête. Veuillez réessayer plus tard.
+error503=Le serveur n’a pas pu répondre à votre demande. Veuillez réessayer plus tard.
go_back=Retour
invalid_data=Données invalides : %v
@@ -131,7 +131,7 @@ unpin=Désépingler
artifacts=Artefacts
expired=Expiré
-confirm_delete_artifact=Êtes-vous sûr de vouloir supprimer l‘artefact « %s » ?
+confirm_delete_artifact=Êtes-vous sûr de vouloir supprimer l’artefact « %s » ?
archived=Archivé
@@ -275,7 +275,7 @@ reinstall_confirm_check_3=Vous confirmez : vous êtes absolument certain que ce
err_empty_db_path=Le chemin de la base de données SQLite3 ne peut être vide.
no_admin_and_disable_registration=Vous ne pouvez pas désactiver la création de nouveaux utilisateurs avant d'avoir créé un compte administrateur.
err_empty_admin_password=Le mot de passe administrateur ne peut pas être vide.
-err_empty_admin_email=L’adresse courriel de l'administrateur ne peut être vide.
+err_empty_admin_email=Le courriel de l’administrateur ne peut être vide.
err_admin_name_is_reserved=Le nom d'utilisateur de l'administrateur est invalide, le nom d'utilisateur est réservé
err_admin_name_pattern_not_allowed=Le nom d'utilisateur de l'administrateur est invalide, le nom d'utilisateur est réservé
err_admin_name_is_invalid=Le nom d'utilisateur de l'administrateur est invalide
@@ -309,7 +309,7 @@ smtp_from_invalid=L’adresse « Envoyer le courriel sous » est invalide
smtp_from_helper=Adresse courriel utilisée par Gitea. Utilisez directement votre adresse ou la forme « Nom ».
mailer_user=Utilisateur SMTP
mailer_password=Mot de passe SMTP
-register_confirm=Exiger la confirmation du courriel lors de l'inscription
+register_confirm=Exiger la confirmation du courriel lors de l’inscription
mail_notify=Activer les notifications par courriel
server_service_title=Paramètres Serveur et Tierce Parties
offline_mode=Activer le mode hors-ligne
@@ -349,7 +349,7 @@ save_config_failed=L'enregistrement de la configuration %v a échoué
invalid_admin_setting=Paramètres du compte administrateur invalides : %v
invalid_log_root_path=Le répertoire des fichiers de journalisation est invalide : %v
default_keep_email_private=Masquer les adresses courriels par défaut
-default_keep_email_private_popup=Masquer par défaut les adresses courriels des nouveaux utilisateurs.
+default_keep_email_private_popup=Masquer par défaut les courriels des nouveaux utilisateurs.
default_allow_create_organization=Autoriser la création d'organisations par défaut
default_allow_create_organization_popup=Permettre aux nouveaux comptes utilisateurs de créer des organisations par défaut.
default_enable_timetracking=Activer le suivi de temps par défaut
@@ -358,7 +358,6 @@ no_reply_address=Domaine pour les courriels cachés
no_reply_address_helper=Nom de domaine pour les utilisateurs ayant une adresse courriel cachée. Par exemple, l’utilisateur « fred » sera associé à « fred@noreply.example.org » par Git si le domaine est « noreply.example.org ».
password_algorithm=Algorithme de hachage du mot de passe
invalid_password_algorithm=Algorithme de hachage du mot de passe invalide
-password_algorithm_helper=Définissez l’algorithme de hachage du mot de passe. Les algorithmes ont des exigences matérielles et une résistance différentes. L’algorithme argon2 est bien sécurisé mais utilise beaucoup de mémoire et peut être inapproprié pour les systèmes limités en ressources.
enable_update_checker=Activer la vérification des mises-à-jour
enable_update_checker_helper=Vérifie les mises à jour régulièrement en se connectant à gitea.io.
env_config_keys=Configuration de l'environnement
@@ -432,10 +431,10 @@ active_your_account=Activer votre compte
account_activated=Le compte a été activé
prohibit_login=Connexion interdite
prohibit_login_desc=Votre compte n'autorise pas la connexion, veuillez contacter l'administrateur de votre site.
-resent_limit_prompt=Désolé, vous avez récemment demandé un courriel d'activation. Veuillez réessayer dans 3 minutes.
-has_unconfirmed_mail=Bonjour %s, votre adresse courriel (%s) n’a pas été confirmée. Si vous n’avez reçu aucun mail de confirmation ou souhaitez renouveler l’envoi, cliquez sur le bouton ci-dessous.
-change_unconfirmed_mail_address=Si votre adresse courriel d’inscription est incorrecte, vous pouvez la modifier ici et renvoyer un nouvel courriel de confirmation.
-resend_mail=Cliquez ici pour renvoyer un mail de confirmation
+resent_limit_prompt=Désolé, vous avez récemment demandé un courriel d’activation. Veuillez réessayer dans 3 minutes.
+has_unconfirmed_mail=Bonjour %s, votre adresse courriel %s n’a pas été confirmée. Si vous n’avez reçu aucun mail de confirmation ou souhaitez renouveler l’envoi, cliquez sur le bouton ci-dessous.
+change_unconfirmed_mail_address=Si votre adresse courriel d’inscription est incorrecte, vous pouvez la modifier ici et renvoyer un nouveau courriel de confirmation.
+resend_mail=Cliquez ici pour renvoyer un courriel de confirmation
email_not_associate=L’adresse courriel n’est associée à aucun compte.
send_reset_mail=Envoyer un courriel de récupération du compte
reset_password=Récupération du compte
@@ -452,7 +451,6 @@ use_scratch_code=Utiliser un code de secours
twofa_scratch_used=Vous avez utilisé votre code de secours. Vous avez été redirigé vers cette page de configuration afin de supprimer l'authentification à deux facteurs de votre appareil ou afin de générer un nouveau code de secours.
twofa_passcode_incorrect=Votre code d’accès n’est pas correct. Si vous avez égaré votre appareil, utilisez votre code de secours pour vous connecter.
twofa_scratch_token_incorrect=Votre code de secours est incorrect.
-twofa_required=Vous devez configurer l’authentification à deux facteurs pour avoir accès aux dépôts, ou essayer de vous reconnecter.
login_userpass=Connexion
login_openid=OpenID
oauth_signup_tab=Créer un compte
@@ -464,20 +462,18 @@ oauth_signin_submit=Lier un compte
oauth.signin.error.general=Une erreur s’est produite lors du traitement de la demande d’autorisation : %s. Si l’erreur persiste, veuillez contacter l’administrateur du site.
oauth.signin.error.access_denied=La demande d'autorisation a été refusée.
oauth.signin.error.temporarily_unavailable=L'autorisation a échoué car le serveur d'authentification est temporairement indisponible. Veuillez réessayer plus tard.
-oauth_callback_unable_auto_reg=L’inscription automatique est activée, mais le fournisseur OAuth2 %[1]s a signalé des champs manquants : %[2]s, impossible de créer un compte automatiquement, veuillez créer ou lier un compte, ou bien contacter l’administrateur du site.
openid_connect_submit=Se connecter
openid_connect_title=Se connecter à un compte existant
openid_connect_desc=L'URI OpenID choisie est inconnue. Associez-le à un nouveau compte ici.
openid_register_title=Créer un nouveau compte
openid_register_desc=L'URI OpenID choisie est inconnue. Associez-le à un nouveau compte ici.
openid_signin_desc=Entrez l'URI de votre OpenID. Par exemple : alice.openid.example.org ou https://openid.example.org/alice.
-disable_forgot_password_mail=La récupération du compte est désactivée car aucune adresse courriel n’est configurée. Veuillez contacter l'administrateur de votre site.
-disable_forgot_password_mail_admin=La récupération du compte est disponible uniquement lorsque l’adresse courriel est configurée. Veuillez configurer l’adresse courriel pour activer la récupération du compte.
+disable_forgot_password_mail=La récupération du compte est désactivée car aucun courriel n’est configuré. Veuillez contacter l’administrateur de votre site.
+disable_forgot_password_mail_admin=La récupération du compte n’est possible que lorsqu’un courriel est configurée. Veuillez ajouter une adresse courriel à votre compte.
email_domain_blacklisted=Vous ne pouvez pas vous enregistrer avec votre adresse courriel.
authorize_application=Autoriser l'application
authorize_redirect_notice=Vous serez redirigé vers %s si vous autorisez cette application.
authorize_application_created_by=Cette application a été créée par %s.
-authorize_application_description=Si vous accordez l'accès, il sera en mesure d'accéder et d'écrire toutes les informations de votre compte, y compris les dépôts privés et les organisations.
authorize_application_with_scopes=Avec des contextes : %s
authorize_title=Autoriser "%s" à accéder à votre compte ?
authorization_failed=L’autorisation a échoué
@@ -502,12 +498,11 @@ activate_account.text_2=Veuillez cliquer sur ce lien pour activer votre compte c
activate_email=Veuillez vérifier votre adresse courriel
activate_email.title=%s, veuillez vérifier votre adresse courriel
-activate_email.text=Veuillez cliquer sur le lien suivant pour vérifier votre adresse courriel dans %s:
+activate_email.text=Veuillez cliquer sur le lien suivant pour vérifier votre adresse courriel dans %s :
register_notify=Bienvenue sur %s
register_notify.title=%[1]s, bienvenue à %[2]s
-register_notify.text_1=ceci est votre courriel de confirmation d'inscription pour %s!
-register_notify.text_2=Vous pouvez maintenant vous connecter avec le nom d'utilisateur : %s.
+register_notify.text_1=Voici votre courriel d’inscription pour %s !
register_notify.text_3=Si ce compte a été créé pour vous, veuillez définir votre mot de passe d'abord.
reset_password=Récupérer votre compte
@@ -620,8 +615,8 @@ visit_rate_limit=Le taux d'appel à distance autorisé a été dépassé.
org_name_been_taken=Ce nom d'organisation est déjà pris.
team_name_been_taken=Le nom d'équipe est déjà pris.
team_no_units_error=Autoriser l’accès à au moins une section du dépôt.
-email_been_used=Cette adresse courriel est déjà utilisée.
-email_invalid=Cette adresse courriel est invalide.
+email_been_used=Ce courriel est déjà utilisé.
+email_invalid=Ce courriel est invalide.
email_domain_is_not_allowed=Le domaine %s du courriel utilisateur entre en conflit avec EMAIL_DOMAIN_ALLOWLIST ou EMAIL_DOMAIN_BLOCKLIST. Veuillez vous assurer que votre opération est attendue.
openid_been_used=Adresse OpenID "%s" déjà utilisée.
username_password_incorrect=Identifiant ou mot de passe invalide.
@@ -679,7 +674,7 @@ unfollow=Ne plus suivre
user_bio=Biographie
disabled_public_activity=Cet utilisateur a désactivé la visibilité publique de l'activité.
email_visibility.limited=Votre adresse courriel est visible pour tous les utilisateurs authentifiés
-email_visibility.private=Votre adresse courriel n'est visible que pour vous et les administrateurs
+email_visibility.private=Votre adresse courriel n’est visible que pour vous et les administrateurs
show_on_map=Afficher ce lieu sur une carte
settings=Paramètres utilisateur
@@ -689,7 +684,6 @@ form.name_chars_not_allowed=Le nom d'utilisateur "%s" contient des caractères n
block.block=Bloquer
block.block.user=Bloquer l’utilisateur
-block.block.org=Bloquer l’utilisateur pour l’organisation
block.block.failure=Impossible de bloquer l’utilisateur : %s
block.unblock=Débloquer
block.unblock.failure=Impossible de débloquer l’utilisateur : %s
@@ -733,7 +727,6 @@ webauthn=Authentification à deux facteurs (Clés de sécurité)
public_profile=Profil public
biography_placeholder=Parlez-nous un peu de vous ! (Vous pouvez utiliser Markdown)
location_placeholder=Partagez votre position approximative avec d'autres personnes
-profile_desc=Contrôlez comment votre profil est affiché aux autres utilisateurs. Votre adresse courriel principale sera utilisée pour les notifications, la récupération de mot de passe et les opérations Git basées sur le Web.
password_username_disabled=Vous n’êtes pas autorisé à modifier votre nom d’utilisateur. Veuillez contacter l’administrateur de votre site pour plus de détails.
password_full_name_disabled=Vous n’êtes pas autorisé à modifier votre nom complet. Veuillez contacter l’administrateur du site pour plus de détails.
full_name=Nom complet
@@ -799,36 +792,35 @@ emails=Adresses courriels
manage_emails=Gérer les adresses courriels
manage_themes=Sélectionner le thème par défaut
manage_openid=Gérer les adresses OpenID
-email_desc=Votre adresse courriel principale sera utilisée pour les notifications, la récupération de mot de passe et, à condition qu'elle ne soit pas cachée, les opérations Git basées sur le Web.
+email_desc=Votre courriel principal sera utilisé pour les notifications, la récupération de mot de passe et, à condition qu’il ne soit pas caché, les opérations Git basées sur le Web.
theme_desc=Ce sera votre thème par défaut sur le site.
theme_colorblindness_help=Support du thème daltonien
theme_colorblindness_prompt=Gitea fournit depuis peu des thèmes daltonien basé sur un spectre coloré réduit. Encore en développement, de futures améliorations devraient enrichir les fichiers de thèmes CSS.
primary=Principale
activated=Activé
requires_activation=Nécessite une activation
-primary_email=Faire de cette adresse votre adresse principale
+primary_email=Rendre Principal
activate_email=Envoyer l’activation
activations_pending=Activations en attente
-can_not_add_email_activations_pending=Il y a une activation en attente, réessayez dans quelques minutes si vous souhaitez ajouter un nouvel e-mail.
+can_not_add_email_activations_pending=Il y a une activation en attente, réessayez dans quelques minutes si vous souhaitez ajouter un nouveau courriel.
delete_email=Exclure
-email_deletion=Supprimer l'adresse e-mail
-email_deletion_desc=L’adresse e-mail et les informations associées seront retirées de votre compte. Les révisions Git effectuées par cette adresse resteront inchangées. Continuer ?
-email_deletion_success=L'adresse e-mail a été supprimée.
+email_deletion=Supprimer l’adresse courriel
+email_deletion_success=L’adresse courriel a été supprimée.
theme_update_success=Votre thème a été mis à jour.
theme_update_error=Le thème sélectionné n'existe pas.
openid_deletion=Supprimer l’adresse OpenID
openid_deletion_desc=Supprimer cette adresse OpenID de votre compte vous empêchera de vous connecter avec. Continuer ?
openid_deletion_success=L'adresse OpenID a été supprimée.
-add_new_email=Ajouter une nouvelle adresse e-mail
+add_new_email=Ajouter un nouveau courriel
add_new_openid=Ajouter une nouvelle URI OpenID
-add_email=Ajouter une adresse e-mail
+add_email=Ajouter un courriel
add_openid=Ajouter une URI OpenID
-add_email_confirmation_sent=Un e-mail de confirmation a été envoyé à "%s". Veuillez vérifier votre boîte de réception dans les %s suivants pour confirmer votre adresse e-mail.
-add_email_success=La nouvelle adresse e-mail a été ajoutée.
-email_preference_set_success=L'e-mail de préférence a été défini avec succès.
+add_email_confirmation_sent=Un courriel de confirmation a été envoyé à « %s ». Veuillez vérifier votre boîte de réception dans les %s suivants pour confirmer votre adresse.
+add_email_success=La nouvelle adresse a été ajoutée.
+email_preference_set_success=Le courriel de préférence a été défini avec succès.
add_openid_success=La nouvelle adresse OpenID a été ajoutée.
-keep_email_private=Cacher l'adresse e-mail
-keep_email_private_popup=Ceci masquera votre adresse e-mail de votre profil, de vos demandes d’ajout et des fichiers modifiés depuis l'interface Web. Les révisions déjà soumises ne seront pas modifiés. Utilisez %s dans les révisions pour les associer à votre compte.
+keep_email_private=Cacher l’adresse e-mail
+keep_email_private_popup=Ceci masquera votre adresse courriel de votre profil, de vos demandes d’ajout et des fichiers modifiés depuis l’interface Web. Les révisions déjà soumises ne seront pas modifiés. Utilisez %s dans les révisions pour les associer à votre compte.
openid_desc=OpenID vous permet de confier l'authentification à une tierce partie.
manage_ssh_keys=Gérer les clés SSH
@@ -849,9 +841,9 @@ ssh_key_been_used=Cette clé SSH a déjà été ajoutée au serveur.
ssh_key_name_used=Une clé SSH avec le même nom existe déjà sur votre compte.
ssh_principal_been_used=Ce principal a déjà été ajouté au serveur.
gpg_key_id_used=Une clé publique GPG avec le même ID existe déjà.
-gpg_no_key_email_found=Cette clé GPG ne correspond à aucune adresse e-mail activée associée à votre compte. Elle peut toujours être ajoutée si vous signez le jeton fourni.
+gpg_no_key_email_found=Cette clé GPG ne correspond à aucun courriel actif associé à votre compte. Elle peut toujours être ajoutée si vous signez le jeton fourni.
gpg_key_matched_identities=Identités correspondantes :
-gpg_key_matched_identities_long=Les identités intégrées dans cette clé correspondent aux adresses e-mail activées suivantes pour cet utilisateur. Les révisions correspondant à ces adresses e-mail peuvent être vérifiés avec cette clé.
+gpg_key_matched_identities_long=Les identités intégrées dans cette clé correspondent aux courriels actifs suivants pour cet utilisateur. Les révisions correspondant à ces courriels peuvent être vérifiés avec cette clé.
gpg_key_verified=Clé vérifiée
gpg_key_verified_long=Cette clé a été vérifiée à l’aide d’un jeton et peut dorénavant être utilisée pour authentifier vos révisions lorsqu’elles contiennent l’un de vos courriels actifs ou des identités associées à cette clé.
gpg_key_verify=Vérifier
@@ -863,7 +855,7 @@ gpg_token_signature=Signature GPG renforcée
key_signature_gpg_placeholder=Commence par '-----BEGIN PGP SIGNATURE-----'
verify_gpg_key_success=La clé GPG "%s" a été vérifiée.
ssh_key_verified=Clé vérifiée
-ssh_key_verified_long=La clé a été vérifiée avec un jeton et peut dorénavant être utilisée pour vérifier les révisions comportant l'une des adresses e-mails activées de cet utilisateur.
+ssh_key_verified_long=La clé a été vérifiée avec un jeton et peut dorénavant être utilisée pour vérifier les révisions comportant l’un des courriels actifs de cet utilisateur.
ssh_key_verify=Vérifier
ssh_invalid_token_signature=La clé SSH, la signature ou le jeton fournis ne correspondent pas ou le jeton est périmé.
ssh_token_required=Vous devez fournir une signature pour le jeton ci-dessous
@@ -903,7 +895,7 @@ principal_state_desc=Ce Principal a été utilisé au cours des 7 derniers jours
show_openid=Afficher sur le profil
hide_openid=Masquer du profil
ssh_disabled=SSH désactivé
-ssh_signonly=SSH étant désactivé, ces clés ne servent qu'à vérifier la signature des révisions.
+ssh_signonly=SSH étant désactivé, ces clés ne servent qu’à vérifier la signature des révisions.
ssh_externally_managed=Cette clé SSH est gérée de manière externe pour cet utilisateur
manage_social=Gérer les réseaux sociaux associés
social_desc=Ces comptes sociaux peuvent être utilisés pour vous connecter à votre compte. Assurez-vous de les reconnaître tous.
@@ -998,7 +990,7 @@ webauthn_alternative_tip=Vous devriez configurer une méthode d’authentificati
manage_account_links=Gérer les comptes liés
manage_account_links_desc=Ces comptes externes sont liés à votre compte Gitea.
-account_links_not_available=Il n'y a pour l'instant pas de compte externe connecté à votre compte Gitea.
+account_links_not_available=Il n’y a pour l’instant pas de compte externe connecté à votre compte Gitea.
link_account=Lier un Compte
remove_account_link=Supprimer un compte lié
remove_account_link_desc=La suppression d'un compte lié révoquera son accès à votre compte Gitea. Continuer ?
@@ -1016,11 +1008,11 @@ confirm_delete_account=Confirmer la suppression
delete_account_title=Supprimer cet utilisateur
delete_account_desc=Êtes-vous sûr de vouloir supprimer définitivement ce compte d'utilisateur ?
-email_notifications.enable=Activer les notifications par e-mail
-email_notifications.onmention=N'envoyer un e-mail que si vous êtes mentionné
-email_notifications.disable=Désactiver les notifications par e-mail
-email_notifications.submit=Définir les préférences d'e-mail
-email_notifications.andyourown=Et vos propres notifications
+email_notifications.enable=Notifier par courriel
+email_notifications.onmention=Seulement sur Mention
+email_notifications.disable=Ne pas notifier
+email_notifications.submit=Définir les préférences de courriel
+email_notifications.andyourown=Inclure vos propres notifications
visibility=Visibilité de l'utilisateur
visibility.public=Public
@@ -1035,8 +1027,8 @@ new_repo_helper=Un dépôt contient tous les fichiers d’un projet, ainsi que l
owner=Propriétaire
owner_helper=Certaines organisations peuvent ne pas apparaître dans la liste déroulante en raison d'une limite maximale du nombre de dépôts.
repo_name=Nom du dépôt
-repo_name_profile_public_hint=.profile est un dépôt spécial que vous pouvez utiliser pour ajouter un README.md à votre profil public d’organisation, visible à tout le monde. Assurez-vous qu’il soit public et initialisez-le avec un README dans le répertoire de profil pour commencer.
-repo_name_profile_private_hint=.profile-private est un dépôt spécial que vous pouvez utiliser pour ajouter un README.md à votre profil d’organisation, visible uniquement aux membres de l’organisation. Assurez-vous qu’il soit privé et initialisez-le avec un README dans le répertoire de profil pour commencer.
+repo_name_profile_public_hint=.profile est un dépôt spécial que vous pouvez utiliser pour ajouter un README.md à votre profil public d’organisation, visible par tous. Assurez-vous qu’il soit public et initialisez-le avec un README dans le répertoire de profil pour commencer.
+repo_name_profile_private_hint=.profile-private est un dépôt spécial que vous pouvez utiliser pour ajouter un README.md à votre profil d’organisation, visible uniquement à ses membres. Assurez-vous qu’il soit privé et initialisez-le avec un README dans le répertoire de profil pour commencer.
repo_name_helper=Idéalement, le nom d’un dépôt devrait être court, mémorisable et unique. Vous pouvez personnaliser votre profil ou celui de votre organisation en créant un dépôt nommé « .profile » ou « .profile-private » et contenant un README.md.
repo_size=Taille du dépôt
template=Modèle
@@ -1058,7 +1050,7 @@ fork_branch=Branche à cloner sur la bifurcation
all_branches=Toutes les branches
view_all_branches=Voir toutes les branches
view_all_tags=Voir toutes les étiquettes
-fork_no_valid_owners=Ce dépôt ne peut pas être bifurqué car il n’a pas de propriétaire valide.
+fork_no_valid_owners=Ce dépôt ne peut pas être bifurqué car il n'y a pas de propriétaire(s) valide(s).
fork.blocked_user=Impossible de bifurquer le dépôt car vous êtes bloqué par son propriétaire.
use_template=Utiliser ce modèle
open_with_editor=Ouvrir avec %s
@@ -1087,13 +1079,13 @@ readme_helper_desc=Le README est l'endroit idéal pour décrire votre projet et
auto_init=Initialiser le dépôt (avec un .gitignore, une Licence et un README.md)
trust_model_helper=Choisissez, parmi les éléments suivants, les règles de confiance des signatures paraphant les révisions :
trust_model_helper_collaborator=Collaborateur : ne se fier qu'aux signatures des collaborateurs du dépôt
-trust_model_helper_committer=Auteur : ne se fier qu'aux signatures des auteurs de révisions
+trust_model_helper_committer=Auteur : ne se fier qu’aux signatures des auteurs de révisions
trust_model_helper_collaborator_committer=Collaborateur et Auteur : ne se fier qu'aux signatures des auteurs collaborant au dépôt
trust_model_helper_default=Par défaut : valeur configurée par défaut pour cette instance Gitea
create_repo=Créer un dépôt
default_branch=Branche par défaut
default_branch_label=défaut
-default_branch_helper=La branche par défaut est la branche de base pour les demandes d'ajout et les révisions de code.
+default_branch_helper=La branche par défaut est la branche de base pour les demandes d’ajout et les révisions de code.
mirror_prune=Purger
mirror_prune_desc=Supprimer les références externes obsolètes
mirror_interval=Intervalle de synchronisation (les unités de temps valides sont 'h', 'm' et 's'). 0 pour désactiver la synchronisation automatique. (Intervalle minimum : %s)
@@ -1102,7 +1094,6 @@ mirror_sync=synchronisé
mirror_sync_on_commit=Synchroniser quand les révisions sont soumis
mirror_address=Cloner depuis une URL
mirror_address_desc=Insérez tous les identifiants requis dans la section Autorisation.
-mirror_address_url_invalid=L’URL fournie est invalide. Vous devez échapper tous les composants de l'URL correctement.
mirror_address_protocol_invalid=L'URL fournie est invalide. Seuls les protocoles http(s):// ou git:// peuvent référencer un miroir.
mirror_lfs=Stockage de fichiers volumineux (LFS)
mirror_lfs_desc=Activer la mise en miroir des données LFS.
@@ -1162,8 +1153,6 @@ template.issue_labels=Labels de ticket
template.one_item=Vous devez sélectionner au moins un élément du modèle
template.invalid=Vous devez sélectionner un modèle de dépôt
-archive.title=Ce dépôt est archivé. Vous pouvez voir ses fichiers ou le cloner, mais pas ouvrir de ticket ou de demandes d'ajout, ni soumettre de changements.
-archive.title_date=Ce dépôt a été archivé le %s. Vous pouvez voir ses fichiers ou le cloner, mais pas ouvrir de ticket ou de demandes d'ajout, ni soumettre de changements.
archive.issue.nocomment=Ce dépôt est archivé. Vous ne pouvez pas commenter de tickets.
archive.pull.nocomment=Ce dépôt est archivé. Vous ne pouvez pas commenter de demande d'ajout.
@@ -1192,7 +1181,6 @@ migrate_items_releases=Publications
migrate_repo=Migrer le dépôt
migrate.clone_address=Migrer/Cloner depuis une URL
migrate.clone_address_desc=L'URL HTTP(S) ou Git "clone" d'un dépôt existant
-migrate.github_token_desc=Vous pouvez mettre un ou plusieurs jetons séparés par des virgules ici pour rendre la migration plus rapide et contourner la limite de débit de l’API GitHub. ATTENTION : Abuser de cette fonctionnalité peut enfreindre la politique du fournisseur de service et entraîner un blocage de votre compte.
migrate.clone_local_path=ou un chemin serveur local
migrate.permission_denied=Vous n'êtes pas autorisé à importer des dépôts locaux.
migrate.permission_denied_blocked=Vous ne pouvez pas importer depuis des hôtes interdits, veuillez demander à l'administrateur de vérifier les paramètres ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS.
@@ -1254,7 +1242,6 @@ create_new_repo_command=Création d'un nouveau dépôt en ligne de commande
push_exist_repo=Soumission d'un dépôt existant par ligne de commande
empty_message=Ce dépôt n'a pas de contenu.
broken_message=Les données git de ce dépôt ne peuvent pas être lues. Contactez l'administrateur de cette instance ou supprimez ce dépôt.
-no_branch=Ce dépôt n’a aucune branche.
code=Code
code.desc=Accéder au code source, fichiers, révisions et branches.
@@ -1314,7 +1301,7 @@ vendored=Externe
generated=Générée
commit_graph=Graphe des révisions
commit_graph.select=Sélectionner les branches
-commit_graph.hide_pr_refs=Masquer les demandes d'ajout
+commit_graph.hide_pr_refs=Masquer les demandes d’ajout
commit_graph.monochrome=Monochrome
commit_graph.color=Couleur
commit.contained_in=Cette révision appartient à :
@@ -1400,8 +1387,6 @@ editor.failed_to_commit=Impossible de réviser les modifications.
editor.failed_to_commit_summary=Message d’erreur :
editor.fork_create=Bifurquer le Dépôt pour proposer vos modifications
-editor.fork_create_description=Vous ne pouvez pas modifier ce dépôt directement. Cependant, vous pouvez bifurquer ce dépôt, et créer une demande d’ajout avec vos contributions.
-editor.fork_edit_description=Vous ne pouvez pas modifier ce dépôt directement. Les modifications seront écrites sur une bifurcation %s, et ainsi faire une demande d’ajout.
editor.fork_not_editable=Vous avez bifurqué ce dépôt mais votre copie n’est pas modifiable.
editor.fork_failed_to_push_branch=Impossible de pousser la branche %s vers votre dépôt.
editor.fork_branch_exists=La branche « %s » existe déjà dans votre bifurcation, veuillez choisir un nouveau nom de branche.
@@ -1700,7 +1685,6 @@ issues.lock_no_reason=a verrouillé et limité la conversation aux collaborateur
issues.unlock_comment=a déverrouillé cette conversation %s
issues.lock_confirm=Verrouiller
issues.unlock_confirm=Déverrouiller
-issues.lock.notice_1=- Les autres utilisateurs ne peuvent pas ajouter de nouveaux commentaires à ce ticket.
issues.lock.notice_2=- Vous et les autres collaborateurs ayant accès à ce dépôt peuvent toujours laisser des commentaires que d’autres peuvent voir.
issues.lock.notice_3=- Vous pouvez toujours déverrouiller ce ticket à l'avenir.
issues.unlock.notice_1=- Tout le monde sera de nouveau en mesure de commenter ce ticket.
@@ -1869,7 +1853,6 @@ pulls.select_commit_hold_shift_for_range=Maintenir Maj et cliquer sur des révis
pulls.review_only_possible_for_full_diff=Une évaluation n'est possible que lorsque vous affichez le différentiel complet.
pulls.filter_changes_by_commit=Filtrer par révision
pulls.nothing_to_compare=Ces branches sont identiques. Il n’y a pas besoin de créer une demande d'ajout.
-pulls.nothing_to_compare_have_tag=Les branches/étiquettes sélectionnées sont équivalentes.
pulls.nothing_to_compare_and_allow_empty_pr=Ces branches sont égales. Cette demande d'ajout sera vide.
pulls.has_pull_request='Il existe déjà une demande d'ajout entre ces deux branches : %[2]s#%[3]d'
pulls.create=Créer une demande d'ajout
@@ -2032,7 +2015,6 @@ milestones.filter_sort.most_issues=Le plus de tickets
milestones.filter_sort.least_issues=Le moins de tickets
signing.will_sign=Cette révision sera signée avec la clé « %s ».
-signing.wont_sign.error=Impossible de vérifier la signature de la révision.
signing.wont_sign.nokey=Aucune clé n’est disponible pour signer cette révision.
signing.wont_sign.never=Les révisions ne sont jamais signées.
signing.wont_sign.always=Les révisions sont toujours signées.
@@ -2123,7 +2105,7 @@ activity.title.releases_1=%d publication
activity.title.releases_n=%d publications
activity.title.releases_published_by=%s publiée par %s
activity.published_release_label=Publiée
-activity.no_git_activity=Il n'y a pas eu de nouvelle révision dans cette période.
+activity.no_git_activity=Il n’y a pas de révision durant cette période.
activity.git_stats_exclude_merges=En excluant les fusions,
activity.git_stats_author_1=%d auteur
activity.git_stats_author_n=%d auteurs
@@ -2157,8 +2139,8 @@ settings.public_access=Accès public
settings.public_access_desc=Configurer les permissions des visiteurs publics remplaçant les valeurs par défaut de ce dépôt.
settings.public_access.docs.not_set=Non défini : ne donne aucune permission supplémentaire. Les règles du dépôt et les permissions des utilisateurs font foi.
settings.public_access.docs.anonymous_read=Lecture anonyme : les utilisateurs qui ne sont pas connectés peuvent consulter la ressource.
-settings.public_access.docs.everyone_read=Consultation publique : tous les utilisateurs connectés peuvent consulter la ressource. Mettre les tickets et demandes d’ajouts en accès public signifie que les utilisateurs connectés peuvent en créer.
-settings.public_access.docs.everyone_write=Participation publique : tous les utilisateurs connectés ont la permission d’écrire sur la ressource. Seule le Wiki supporte cette autorisation.
+settings.public_access.docs.everyone_read=Consultation collective : tous les utilisateurs connectés peuvent consulter la ressource. Mettre les tickets et demandes d’ajouts en accès public signifie que les utilisateurs connectés peuvent en créer.
+settings.public_access.docs.everyone_write=Participation collective : tous les utilisateurs connectés ont la permission d’écrire sur la ressource. Seule le Wiki supporte cette autorisation.
settings.collaboration=Collaborateurs
settings.collaboration.admin=Administrateur
settings.collaboration.write=Écriture
@@ -2334,6 +2316,8 @@ settings.hooks_desc=Les Webhooks font automatiquement des requêtes HTTP POST à
settings.webhook_deletion=Retirer le Webhook
settings.webhook_deletion_desc=Supprimer un webhook supprime ses paramètres et son historique. Continuer ?
settings.webhook_deletion_success=Le webhook a été supprimé.
+settings.webhook.test_delivery=Tester l’envoi
+settings.webhook.test_delivery_desc=Testez ce webhook avec un faux événement.
settings.webhook.test_delivery_desc_disabled=Pour tester ce webhook avec un faux événement, activez-le.
settings.webhook.request=Requête
settings.webhook.response=Réponse
@@ -2353,6 +2337,7 @@ settings.payload_url=URL cible
settings.http_method=Méthode HTTP
settings.content_type=Type de contenu POST
settings.secret=Secret
+settings.webhook_secret_desc=Si le serveur webhook supporte l’usage de secrets, vous pouvez indiquer un secret ici en vous basant sur leur documentation.
settings.slack_username=Nom d'utilisateur
settings.slack_icon_url=URL de l'icône
settings.slack_color=Couleur
@@ -2538,7 +2523,6 @@ settings.block_on_official_review_requests_desc=La fusion ne sera pas possible t
settings.block_outdated_branch=Bloquer la fusion si la demande d'ajout est obsolète
settings.block_outdated_branch_desc=La fusion ne sera pas possible lorsque la branche principale est derrière la branche de base.
settings.block_admin_merge_override=Les administrateurs doivent respecter les règles de protection des branches
-settings.block_admin_merge_override_desc=Les administrateurs doivent respecter les règles de protection des branches et ne peuvent pas les contourner.
settings.default_branch_desc=Sélectionnez une branche par défaut pour les demandes de fusion et les révisions :
settings.merge_style_desc=Styles de fusion
settings.default_merge_style_desc=Méthode de fusion par défaut
@@ -2565,10 +2549,7 @@ settings.matrix.homeserver_url=URL du serveur d'accueil
settings.matrix.room_id=ID de la salle
settings.matrix.message_type=Type de message
settings.visibility.private.button=Rendre privé
-settings.visibility.private.text=Rendre le dépôt privé rendra non seulement le dépôt visible uniquement aux membres autorisés, mais peut également rompre la relation entre lui et ses bifurcations, observateurs, et favoris.
settings.visibility.private.bullet_title=Changer la visibilité en privé :
-settings.visibility.private.bullet_one=Va rendre le dépôt visible uniquement par les membres autorisés
-settings.visibility.private.bullet_two=Peut supprimer la relation avec ses bifurcations, ses observateurs et ses favoris
settings.visibility.public.button=Rendre public
settings.visibility.public.text=Rendre le dépôt public rendra le dépôt visible à tout le monde.
settings.visibility.public.bullet_title=Changer la visibilité en public va :
@@ -2782,6 +2763,7 @@ topic.done=Terminé
topic.count_prompt=Vous ne pouvez pas sélectionner plus de 25 sujets
topic.format_prompt=Les sujets doivent commencer par un caractère alphanumérique, peuvent inclure des traits d’union « - » et des points « . », et mesurer jusqu'à 35 caractères. Les lettres doivent être en minuscules.
+find_file.follow_symlink=Suivre ce lien symbolique vers sa cible
find_file.go_to_file=Aller au fichier
find_file.no_matching=Aucun fichier correspondant trouvé
@@ -2822,7 +2804,6 @@ team_permission_desc=Autorisation
team_unit_desc=Permettre l’accès aux Sections du dépôt
team_unit_disabled=(Désactivé)
-form.name_been_taken=Le nom d’organisation « %s » a déjà été utilisé.
form.name_reserved=Le nom d'organisation "%s" est réservé.
form.name_pattern_not_allowed=Le motif « %s » n'est pas autorisé dans un nom d'organisation.
form.create_org_not_allowed=Vous n'êtes pas autorisé à créer une organisation.
@@ -2864,7 +2845,6 @@ settings.delete_notices_2=Cette opération supprimera définitivement to
settings.delete_notices_3=Cette opération supprimera définitivement tous les paquets de %s.
settings.delete_notices_4=Cette opération supprimera définitivement tous les projets de %s.
settings.confirm_delete_account=Confirmer la suppression
-settings.delete_failed=La suppression de l’organisation a échoué en raison d’une erreur interne.
settings.delete_successful=L’organisation %s a été supprimée avec succès.
settings.hooks_desc=Vous pouvez ajouter des webhooks qui seront activés pour tous les dépôts de cette organisation.
@@ -2962,7 +2942,7 @@ repositories=Dépôts
hooks=Déclencheurs web
integrations=Intégrations
authentication=Sources d'authentification
-emails=Emails de l'utilisateur
+emails=Courriels de l’utilisateur
config=Configuration
config_summary=Résumé
config_settings=Paramètres
@@ -3014,9 +2994,6 @@ dashboard.resync_all_sshprincipals=Mettre à jour le fichier « .ssh/authorized
dashboard.resync_all_hooks=Re-synchroniser les déclencheurs Git pre-receive, update et post-receive de tous les dépôts.
dashboard.reinit_missing_repos=Réinitialiser tous les dépôts Git manquants pour lesquels un enregistrement existe
dashboard.sync_external_users=Synchroniser les données de l’utilisateur externe
-dashboard.cleanup_hook_task_table=Nettoyer la table hook_task
-dashboard.cleanup_packages=Nettoyer des paquets expirés
-dashboard.cleanup_actions=Nettoyer les reliquats des actions obsolètes
dashboard.server_uptime=Uptime du serveur
dashboard.current_goroutine=Goroutines actuelles
dashboard.current_memory_usage=Utilisation Mémoire actuelle
@@ -3118,22 +3095,22 @@ users.list_status_filter.is_2fa_enabled=2FA Activé
users.list_status_filter.not_2fa_enabled=2FA désactivé
users.details=Informations de l’utilisateur
-emails.email_manage_panel=Gestion des emails des utilisateurs
+emails.email_manage_panel=Gestion des courriels des utilisateurs
emails.primary=Principale
emails.activated=Activée
emails.filter_sort.email=Courriel
emails.filter_sort.email_reverse=Courriel (inversé)
-emails.filter_sort.name=Nom d'utilisateur
-emails.filter_sort.name_reverse=Nom d'utilisateur (inverse)
+emails.filter_sort.name=Nom d’utilisateur
+emails.filter_sort.name_reverse=Nom d’utilisateur (inversé)
emails.updated=Courriel mis à jour
-emails.not_updated=Impossible de mettre à jour l’adresse courriel demandée : %v
-emails.duplicate_active=Cette adresse courriel est déjà active pour un autre utilisateur.
+emails.not_updated=Impossible de mettre à jour le courriel demandé : %v
+emails.duplicate_active=Ce courriel est déjà attribué à un autre utilisateur.
emails.change_email_header=Mettre à jour les propriétés du courriel
emails.change_email_text=Êtes-vous sûr de vouloir mettre à jour cette adresse courriel ?
-emails.delete=Supprimer l’e-mail
-emails.delete_desc=Êtes-vous sûr de vouloir supprimer cette adresse e-mail ?
-emails.deletion_success=L’adresse e-mail a été supprimée.
-emails.delete_primary_email_error=Vous ne pouvez pas supprimer l’e-mail principal.
+emails.delete=Supprimer le courriel
+emails.delete_desc=Êtes-vous sûr de vouloir supprimer ce courriel ?
+emails.deletion_success=L’adresse courriel a été supprimée.
+emails.delete_primary_email_error=Vous ne pouvez pas supprimer le courriel principal.
orgs.org_manage_panel=Gestion des organisations
orgs.name=Nom
@@ -3196,7 +3173,7 @@ auths.attribute_username=Attribut nom d'utilisateur
auths.attribute_username_placeholder=Laisser vide afin d'utiliser le nom d'utilisateur spécifié dans Gitea.
auths.attribute_name=Attribut prénom
auths.attribute_surname=Attribut nom de famille
-auths.attribute_mail=Attribut e-mail
+auths.attribute_mail=Attribut courriel
auths.attribute_ssh_public_key=Attribut clé SSH publique
auths.attribute_avatar=Attribut de l'avatar
auths.attributes_in_bind=Aller chercher les attributs dans le contexte de liaison DN
@@ -3237,7 +3214,7 @@ auths.oauth2_use_custom_url=Utiliser des URLs personnalisées au lieu de l’URL
auths.oauth2_tokenURL=URL du jeton
auths.oauth2_authURL=URL d'autorisation
auths.oauth2_profileURL=URL du profil
-auths.oauth2_emailURL=URL de l'e-mail
+auths.oauth2_emailURL=URL du courriel
auths.skip_local_two_fa=Ignorer l’authentification à deux facteurs locale
auths.skip_local_two_fa_helper=Laisser indéfini signifie que les utilisateurs locaux avec l’authentification à deux facteurs activée devront tout de même s’y soumettre pour se connecter
auths.oauth2_tenant=Locataire
@@ -3247,6 +3224,8 @@ auths.oauth2_required_claim_name_helper=Définissez ce nom pour restreindre la c
auths.oauth2_required_claim_value=Valeur de réclamation requise
auths.oauth2_required_claim_value_helper=Restreindre la connexion depuis cette source aux utilisateurs ayant réclamé cette valeur.
auths.oauth2_group_claim_name=Réclamer le nom fournissant les noms de groupe pour cette source. (facultatif)
+auths.oauth2_full_name_claim_name=Nom complet réclamé. (Optionnel. Si défini, le nom complet de l’utilisateur sera toujours synchronisé avec cette réclamation)
+auths.oauth2_ssh_public_key_claim_name=Nom réclamé de la clé publique SSH
auths.oauth2_admin_group=Valeur de réclamation de groupe pour les administrateurs. (Optionnel, nécessite un nom de réclamation)
auths.oauth2_restricted_group=Valeur de réclamation de groupe pour les utilisateurs restreints. (Optionnel, nécessite un nom de réclamation)
auths.oauth2_map_group_to_team=Associe les groupes réclamés avec les équipes de l'organisation. (Optionnel, nécessite un nom de réclamation)
@@ -3277,7 +3256,7 @@ auths.tip.openid_connect=Utilisez l’URL de découverte OpenID « https://{ser
auths.tip.twitter=Rendez-vous sur %s, créez une application et assurez-vous que l’option « Autoriser l’application à être utilisée avec Twitter Connect » est activée.
auths.tip.discord=Enregistrer une nouvelle application sur %s
auths.tip.gitea=Enregistrez une nouvelle application OAuth2. Le guide peut être trouvé sur %s.
-auths.tip.yandex=Créez une nouvelle application sur %s. Sélectionnez les autorisations suivantes dans la section « Yandex.Passport API » : « Accès à l’adresse e-mail », « Accès à l’avatar de l’utilisateur » et « Accès au nom d’utilisateur, prénom, surnom et genre ».
+auths.tip.yandex=Créez une nouvelle application sur %s. Sélectionnez les autorisations suivantes dans la section « Yandex.Passport API » : « Accès au courriel », « Accès à l’avatar de l’utilisateur » et « Accès au nom d’utilisateur, prénom, surnom et genre ».
auths.tip.mastodon=Entrez une URL d'instance personnalisée pour l'instance mastodon avec laquelle vous voulez vous authentifier (ou utiliser celle par défaut)
auths.edit=Mettre à jour la source d'authentification
auths.activated=Cette source d'authentification est activée
@@ -3338,7 +3317,7 @@ config.db_ssl_mode=SSL
config.db_path=Emplacement
config.service_config=Configuration du service
-config.register_email_confirm=Exiger la confirmation de l'e-mail lors de l'inscription
+config.register_email_confirm=Exiger la confirmation du courriel lors de l’inscription
config.disable_register=Désactiver le formulaire d'inscription
config.allow_only_internal_registration=Autoriser l'inscription uniquement via Gitea lui-même
config.allow_only_external_registration=N'autoriser l'inscription qu'à partir des services externes
@@ -3346,16 +3325,16 @@ config.enable_openid_signup=Activer l'inscription avec OpenID
config.enable_openid_signin=Activer la connexion avec OpenID
config.show_registration_button=Afficher le bouton d'enregistrement
config.require_sign_in_view=Exiger la connexion pour afficher les pages
-config.mail_notify=Activer les notifications par e-mail
+config.mail_notify=Activer les notifications par courriel
config.enable_captcha=Activer le CAPTCHA
config.active_code_lives=Limites de Code Actif
config.reset_password_code_lives=Durée d'expiration du code de récupération de compte
-config.default_keep_email_private=Masquer les adresses e-mail par défaut
+config.default_keep_email_private=Masquer les adresses courriels par défaut
config.default_allow_create_organization=Autoriser la création d'organisations par défaut
config.enable_timetracking=Activer le suivi du temps
config.default_enable_timetracking=Activer le suivi de temps par défaut
config.default_allow_only_contributors_to_track_time=Restreindre le suivi de temps aux contributeurs
-config.no_reply_address=Domaine pour les e-mails cachés
+config.no_reply_address=Domaine pour les courriels cachés
config.default_visibility_organization=Visibilité par défaut des nouvelles organisations
config.default_enable_dependencies=Activer les dépendances pour les tickets par défaut
@@ -3377,11 +3356,11 @@ config.mailer_sendmail_path=Chemin d’accès à Sendmail
config.mailer_sendmail_args=Arguments supplémentaires pour Sendmail
config.mailer_sendmail_timeout=Délai d’attente de Sendmail
config.mailer_use_dummy=Factice
-config.test_email_placeholder=E-mail (ex: test@example.com)
-config.send_test_mail=Envoyer un e-mail de test
+config.test_email_placeholder=Courriel (ex : test@exemple.com)
+config.send_test_mail=Envoyer un courriel de test
config.send_test_mail_submit=Envoyer
-config.test_mail_failed=Impossible d'envoyer un email de test à "%s" : %v
-config.test_mail_sent=Un e-mail de test a été envoyé à "%s".
+config.test_mail_failed=Impossible d’envoyer un courriel de test à « %s » : %v
+config.test_mail_sent=Un courriel de test a été envoyé à « %s ».
config.oauth_config=Configuration OAuth
config.oauth_enabled=Activé
@@ -3451,7 +3430,6 @@ monitor.start=Heure de démarrage
monitor.execute_time=Heure d'Éxécution
monitor.last_execution_result=Résultat
monitor.process.cancel=Annuler le processus
-monitor.process.cancel_desc=L’annulation d’un processus peut entraîner une perte de données.
monitor.process.children=Enfant
monitor.queues=Files d'attente
@@ -3575,7 +3553,7 @@ no_subscriptions=Pas d'abonnements
default_key=Signé avec la clé par défaut
error.extract_sign=Impossible d'extraire la signature
error.generate_hash=Impossible de générer la chaine de hachage de la révision
-error.no_committer_account=Aucun compte lié à l'adresse e-mail de l'auteur
+error.no_committer_account=Aucun compte lié au courriel de l’auteur
error.no_gpg_keys_found=Signature inconnue de Gitea
error.not_signed_commit=Révision non signée
error.failed_retrieval_gpg_keys=Impossible de récupérer la clé liée au compte de l'auteur
@@ -3583,7 +3561,7 @@ error.probable_bad_signature=AVERTISSEMENT ! Bien qu'il y ait une clé avec cet
error.probable_bad_default_signature=AVERTISSEMENT ! Bien que la clé par défaut ait cet ID, elle ne vérifie pas cette livraison ! Cette livraison est SUSPECTE.
[units]
-unit=Unité
+unit=Ressource
error.no_unit_allowed_repo=Vous n'êtes pas autorisé à accéder à n'importe quelle section de ce dépôt.
error.unit_not_allowed=Vous n'êtes pas autorisé à accéder à cette section du dépôt.
@@ -3723,7 +3701,6 @@ owner.settings.cargo.initialize.success=L'index Cargo a été créé avec succè
owner.settings.cargo.rebuild=Reconstruire l'index
owner.settings.cargo.rebuild.description=La reconstruction peut être utile si l'index n'est pas synchronisé avec les paquets Cargo stockés.
owner.settings.cargo.rebuild.error=Impossible de reconstruire l'index Cargo : %v
-owner.settings.cargo.rebuild.success=L'index Cargo a été reconstruit avec succès.
owner.settings.cleanuprules.title=Gérer les règles de nettoyage
owner.settings.cleanuprules.add=Ajouter une règle de nettoyage
owner.settings.cleanuprules.edit=Modifier la règle de nettoyage
@@ -3811,7 +3788,6 @@ runners.delete_runner=Supprimer cet exécuteur
runners.delete_runner_success=Exécuteur supprimé avec succès
runners.delete_runner_failed=Impossible de supprimer l'Exécuteur
runners.delete_runner_header=Êtes-vous sûr de vouloir supprimer cet exécuteur ?
-runners.delete_runner_notice=Si une tâche est en cours sur cet exécuteur, elle sera terminée et marquée comme échouée. Cela risque d’interrompre le flux de travail.
runners.none=Aucun exécuteur disponible
runners.status.unspecified=Inconnu
runners.status.idle=Inactif
diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini
index 965cce0c682..23f7d045c8f 100644
--- a/options/locale/locale_ga-IE.ini
+++ b/options/locale/locale_ga-IE.ini
@@ -117,7 +117,7 @@ files=Comhaid
error=Earráid
error404=Níl an leathanach atá tú ag iarraidh a bhaint amach ann nó níl tú údaraithe chun é a fheiceáil.
-error503=Níorbh fhéidir leis an bhfreastalaí d'iarratas a chur i gcrích. Bain triail eile as ar ball.
+error503=Níorbh fhéidir leis an bhfreastalaí d’iarratas a chomhlánú. Déan iarracht arís ar ball.
go_back=Ar ais
invalid_data=Sonraí neamhbhailí: %v
@@ -131,7 +131,7 @@ unpin=Díphoráil
artifacts=Déantáin
expired=Imithe in éag
-confirm_delete_artifact=An bhfuil tú cinnte gur mhaith leat an déantán '%s' a scriosadh?
+confirm_delete_artifact=An bhfuil tú cinnte gur mian leat an déantán '%s' a scriosadh?
archived=Cartlann
@@ -171,7 +171,7 @@ internal_error_skipped=Tharla earráid inmheánach ach éirithe as: %s
search=Cuardaigh...
type_tooltip=Cineál cuardaigh
fuzzy=Doiléir
-fuzzy_tooltip=Cuir san áireamh torthaí a mheaitseálann an téarma cuardaigh go dlúth freisin
+fuzzy_tooltip=Cuir torthaí san áireamh a mheaitseálann go dlúth leis an téarma cuardaigh
words=Focail
words_tooltip=Ná cuir san áireamh ach torthaí a mheaitseálann na focail téarma cuardaigh
regexp=Nathanna Rialta
@@ -358,7 +358,7 @@ no_reply_address=Fearann Ríomhphoist Folaite
no_reply_address_helper=Ainm fearainn d'úsáideoirí a bhfuil seoladh ríomhphoist i bhfolach acu. Mar shampla, logálfar an t-ainm úsáideora 'joe' i Git mar 'joe@noreply.example.org' má tá an fearainn ríomhphoist i bhfolach socraithe go 'noreply.example.org'.
password_algorithm=Algartam Hais Pasfhocal
invalid_password_algorithm=Algartam hais pasfhocail neamhbhailí
-password_algorithm_helper=Socraigh an algartam hashing pasfhocal. Tá riachtanais agus neart éagsúla ag halgartaim. Tá an algartam argon2 sách slán ach úsáideann sé go leor cuimhne agus d'fhéadfadh sé a bheith míchuí do chórais bheaga.
+password_algorithm_helper=Socraigh an algartam haiseála pasfhocail. Bíonn riachtanais agus láidreachtaí difriúla ag halgartaim. Tá an algartam argon2 sách slán ach úsáideann sé go leor cuimhne agus d'fhéadfadh sé a bheith mí-oiriúnach do chórais bheaga.
enable_update_checker=Cumasaigh Seiceoir Nuashonraithe
enable_update_checker_helper=Seiceálacha ar eisiúintí leagan nua go tréimhsiúil trí nascadh le gitea.io.
env_config_keys=Cumraíocht Comhshaoil
@@ -464,7 +464,7 @@ oauth_signin_submit=Cuntas Nasc
oauth.signin.error.general=Tharla earráid agus an t-iarratas údaraithe á phróiseáil: %s. Má leanann an earráid seo, téigh i dteagmháil le riarthóir an tsuímh.
oauth.signin.error.access_denied=Diúltaíodh an t-iarratas ar údarú.
oauth.signin.error.temporarily_unavailable=Theip ar údarú toisc nach bhfuil an fhreastalaí fíordheimhnithe ar fáil Bain triail as arís níos déanaí.
-oauth_callback_unable_auto_reg=Tá Clárú Uathoibríoch cumasaithe, ach sheol Soláthraí OAuth2 %[1]s réimsí in easnamh ar ais: %[2]s, ní raibh sé in ann cuntas a chruthú go huathoibríoch, cruthaigh nó nasc le cuntas, nó déan teagmháil le riarthóir an tsuímh.
+oauth_callback_unable_auto_reg=Tá Clárú Uathoibríoch cumasaithe, ach thug Soláthraí OAuth2 %[1]s réimsí ar iarraidh ar ais: %[2]s, ní féidir cuntas a chruthú go huathoibríoch. Cruthaigh cuntas nó déan nasc leis, nó déan teagmháil le riarthóir an tsuímh.
openid_connect_submit=Ceangail
openid_connect_title=Ceangail le cuntas atá ann cheana
openid_connect_desc=Níl an URI OpenID roghnaithe ar eolas. Comhcheangail é le cuntas nua anseo.
@@ -477,7 +477,7 @@ email_domain_blacklisted=Ní féidir leat clárú le do sheoladh ríomhphoist.
authorize_application=Údaraigh an Feidhmchlár
authorize_redirect_notice=Déanfar tú a atreorú chuig %s má údaraíonn tú an feidhmchlár seo.
authorize_application_created_by=Chruthaigh %s an feidhmchlár seo.
-authorize_application_description=Má dheonaíonn tú an rochtain, beidh sé in ann rochtain a fháil agus scríobh chuig faisnéis uile do chuntais, lena n-áirítear repos príobháideacha agus eagraíochtaí.
+authorize_application_description=Má dheonaíonn tú rochtain, beidh sé in ann rochtain a fháil ar fhaisnéis do chuntais go léir agus scríobh chuici, lena n-áirítear stórtha príobháideacha agus eagraíochtaí.
authorize_application_with_scopes=Le scóip: %s
authorize_title=Údaraigh "%s" chun rochtain a fháil ar do chuntas?
authorization_failed=Theip ar údarú
@@ -506,8 +506,8 @@ activate_email.text=Cliceáil ar an nasc seo a leanas le do sheoladh ríomhphois
register_notify=Fáilte go dtí %s
register_notify.title=%[1]s, fáilte go %[2]s
-register_notify.text_1=is é seo do ríomhphost deimhnithe clárúcháin do %s!
-register_notify.text_2=Is féidir leat logáil isteach anois trí ainm úsáideora: %s.
+register_notify.text_1=Seo do ríomhphost deimhnithe clárúcháin le haghaidh %s!
+register_notify.text_2=Is féidir leat logáil isteach anois tríd an ainm úsáideora: %s.
register_notify.text_3=Má cruthaíodh an cuntas seo duit, socraigh do phasfhocal ar dtús.
reset_password=Aisghabháil do chuntas
@@ -689,7 +689,7 @@ form.name_chars_not_allowed=Tá carachtair neamhbhailí in ainm úsáideora "%s"
block.block=Bloc
block.block.user=Bloc úsáideoir
-block.block.org=Bloc úsáideoir don eagraíocht
+block.block.org=Bac úsáideoir ón eagraíocht
block.block.failure=Theip ar an úsáideoir a bhac: %s
block.unblock=Díbhlocáil
block.unblock.failure=Theip ar an úsáideoir a díbhlocáil: %s
@@ -733,7 +733,7 @@ webauthn=Fíordheimhniú Dhá-Fachtóir (Eochracha Slándála)
public_profile=Próifíl Phoiblí
biography_placeholder=Inis dúinn beagán fút féin! (Is féidir leat Markdown a úsáid)
location_placeholder=Comhroinn do shuíomh thart le daoine eile
-profile_desc=Rialú conas a thaispeánfar do phróifíl d'úsáideoirí eile. Úsáidfear do phríomhsheoladh ríomhphoist le haghaidh fógraí, aisghabháil pasfhocail agus oibríochtaí Git gréasán-bhunaithe.
+profile_desc=Rialú conas a thaispeántar do phróifíl d'úsáideoirí eile. Úsáidfear do phríomhsheoladh ríomhphoist le haghaidh fógraí, aisghabháil pasfhocal agus oibríochtaí Git gréasánbhunaithe.
password_username_disabled=Níl cead agat d'ainm úsáideora a athrú. Déan teagmháil le do riarthóir suímh le haghaidh tuilleadh sonraí.
password_full_name_disabled=Níl cead agat d’ainm iomlán a athrú. Déan teagmháil le do riarthóir suímh le haghaidh tuilleadh sonraí.
full_name=Ainm Iomlán
@@ -812,7 +812,7 @@ activations_pending=Gníomhartha ar Feitheamh
can_not_add_email_activations_pending=Tá gníomhachtú ar feitheamh, déan iarracht arís i gceann cúpla nóiméad más mian leat ríomhphost nua a chur leis.
delete_email=Bain
email_deletion=Bain Seoladh R-phoist
-email_deletion_desc=Bainfear an seoladh ríomhphoist agus an fhaisnéis ghaolmhar as do chuntas. Ní bheidh na tiomáintí Git a bhaineann leis an seoladh ríomhphoist seo athraithe. Lean ar aghaidh?
+email_deletion_desc=Bainfear an seoladh ríomhphoist seo agus faisnéis ghaolmhar as do chuntas. Fanfaidh na gealltanais Git ón seoladh ríomhphoist seo gan athrú. Ar mhaith leat leanúint ar aghaidh?
email_deletion_success=Tá an seoladh ríomhphoist bainte.
theme_update_success=Nuashonraíodh do théama.
theme_update_error=Níl an téama roghnaithe ann.
@@ -1021,6 +1021,8 @@ email_notifications.onmention=Ríomhphost amháin ar luaigh
email_notifications.disable=Díchumasaigh Fógraí Ríomhphoist
email_notifications.submit=Socraigh rogha ríomhphoist
email_notifications.andyourown=Agus Do Fógraí Féin
+email_notifications.actions.desc=Fógraí le haghaidh rith sreabha oibre ar stórtha atá socraithe le Gníomhartha Gitea.
+email_notifications.actions.failure_only=Fógra a thabhairt ach amháin i gcás ritheanna sreabha oibre nár éirigh leo
visibility=Infheictheacht úsáideora
visibility.public=Poiblí
@@ -1035,8 +1037,8 @@ new_repo_helper=Tá gach comhad tionscadail i stór, lena n-áirítear stair ath
owner=Úinéir
owner_helper=B'fhéidir nach dtaispeánfar roinnt eagraíochtaí sa anuas mar gheall ar theorainn uasta comhaireamh stórais.
repo_name=Ainm Stórais
-repo_name_profile_public_hint=Is stóras speisialta é .profile is féidir leat a úsáid chun README.md a chur le do phróifíl eagraíochta poiblí, le feiceáil ag aon duine. Cinntigh go bhfuil sé poiblí agus tosaigh é le README san eolaire próifíle le tosú.
-repo_name_profile_private_hint=Is stóras speisialta é .profile-private is féidir leat a úsáid chun README.md a chur le do phróifíl bhall eagraíochta, nach féidir a fheiceáil ach ag baill eagraíochta. Cinntigh go bhfuil sé príobháideach agus tosaigh le README sa eolaire próifíle chun tús a chur leis.
+repo_name_profile_public_hint=Is stóras speisialta é .profile ar féidir leat a úsáid chun README.md a chur le do phróifíl eagraíochta poiblí, le feiceáil ag aon duine. Déan cinnte go bhfuil sé poiblí agus cuir README sa chomhadlann próifíle chun tús a chur leis.
+repo_name_profile_private_hint=Is stóras speisialta é .profile-private ar féidir leat a úsáid chun README.md a chur le próifíl bhall d'eagraíochta, nach mbeidh le feiceáil ach ag baill na heagraíochta. Déan cinnte go bhfuil sé príobháideach agus cuir README sa chomhadlann próifíle chun tús a chur leis.
repo_name_helper=Úsáideann ainmneacha maith stóras focail eochair gairide, áithnid agus uathúla. D'fhéadfaí stóras darbh ainm '.profile' nó '.profile-private' a úsáid chun README.md a chur leis an bpróifíl úsáideora/eagraíochta.
repo_size=Méid an Stóras
template=Teimpléad
@@ -1058,7 +1060,7 @@ fork_branch=Brainse le clónú chuig an bhforc
all_branches=Gach brainse
view_all_branches=Féach ar gach brainse
view_all_tags=Féach ar gach clib
-fork_no_valid_owners=Ní féidir an stór seo a fhorcáil toisc nach bhfuil úinéirí bailí ann.
+fork_no_valid_owners=Ní féidir an stóras seo a fhorcadh mar nach bhfuil aon úinéirí bailí ann.
fork.blocked_user=Ní féidir an stór a fhorcáil toisc go bhfuil úinéir an stórais bac ort.
use_template=Úsáid an teimpléad seo
open_with_editor=Oscail le %s
@@ -1102,7 +1104,7 @@ mirror_sync=sioncronaithe
mirror_sync_on_commit=Sioncrónaigh nuair a bhrúitear geallúintí
mirror_address=Clón Ó URL
mirror_address_desc=Cuir aon dhintiúir riachtanacha sa chuid Údaraithe.
-mirror_address_url_invalid=Tá an URL curtha ar fáil neamhbhailí. Caithfidh tú gach comhpháirt den url a éalú i gceart.
+mirror_address_url_invalid=Tá an URL a cuireadh ar fáil neamhbhailí. Cinntigh go bhfuil gach comhpháirt den URL escaped i gceart.
mirror_address_protocol_invalid=Tá an URL curtha ar fáil neamhbhailí. Ní féidir ach suíomhanna http (s)://nó git://a úsáid le haghaidh scátháin.
mirror_lfs=Stóráil Comhad Móra (LFS)
mirror_lfs_desc=Gníomhachtaigh scáthú sonraí LFS.
@@ -1162,8 +1164,8 @@ template.issue_labels=Lipéid Eisiúna
template.one_item=Ní mór mír teimpléad amháin ar a laghad a roghnú
template.invalid=Ní mór stór teimpléad a roghnú
-archive.title=Tá an stóras seo i gcartlann. Is féidir leat comhaid a fheiceáil agus iad a chlónáil, ach ní féidir leat ceisteanna a bhrú ná a oscailt ná iarratais a tharraingt.
-archive.title_date=Tá an stóras seo cartlannaithe ar %s. Is féidir leat comhaid a fheiceáil agus é a chlónú, ach ní féidir leat saincheisteanna a bhrú nó a oscailt ná iarratais a tharraingt.
+archive.title=Tá an stór seo cartlannaithe. Is féidir leat comhaid a fheiceáil agus é a chlónáil. Ní féidir leat saincheisteanna a oscailt, iarratais a tharraingt ná tiomnú a bhrú.
+archive.title_date=Tá an stórlann seo cartlannaithe ar %s. Is féidir leat comhaid a fheiceáil agus é a chlónáil. Ní féidir leat saincheisteanna a oscailt, iarratais a tharraingt ná tiomnú a bhrú.
archive.issue.nocomment=Tá an stóras seo i gcartlann. Ní féidir leat trácht a dhéanamh ar shaincheisteanna.
archive.pull.nocomment=Tá an stóras seo i gcartlann. Ní féidir leat trácht a dhéanamh ar iarratais tarraingthe.
@@ -1192,7 +1194,7 @@ migrate_items_releases=Eisiúintí
migrate_repo=Stóras Imirc
migrate.clone_address=Aimirce/ Clón Ó URL
migrate.clone_address_desc=An URL 'clón' HTTP(S) nó Git de stóras atá ann cheana
-migrate.github_token_desc=Is féidir leat comhartha amháin nó níos mó a chur le camóg scartha anseo chun imirce a dhéanamh níos gasta mar gheall ar theorainn ráta API GitHub. RABHADH: D'fhéadfadh mí-úsáid na ngné seo beartas an sholáthraí seirbhíse a shárú agus blocáil cuntais a bheith mar thoradh air.
+migrate.github_token_desc=Is féidir leat comhartha amháin nó níos mó a chur anseo scartha le camóga chun an t-aistriú a dhéanamh níos tapúla trí theorainn ráta API GitHub a sheachaint. RABHADH: D’fhéadfadh mí-úsáid a bhaint as an ngné seo sárú a dhéanamh ar pholasaí an tsoláthraí seirbhíse agus d’fhéadfadh sé go gcuirfí bac ar do chuntas(í).
migrate.clone_local_path=nó cosán freastalaí áitiúil
migrate.permission_denied=Ní cheadaítear duit stórais áitiúla a iompórtáil.
migrate.permission_denied_blocked=Ní féidir leat allmhairiú ó óstaigh neamh-cheadaithe, iarr ar an riarachán socruithe ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS a sheiceáil le do thoil.
@@ -1254,7 +1256,7 @@ create_new_repo_command=Stóras nua a chruthú ar an líne ordaithe
push_exist_repo=Stóras atá ann cheana a bhrú ón líne ordaithe
empty_message=Níl aon ábhar sa stóras seo.
broken_message=Ní féidir na sonraí Git atá mar bhunús leis an stóras seo a léamh. Déan teagmháil le riarthóir an chás seo nó scrios an stóras seo.
-no_branch=Níl aon bhrainsí ag an stóras seo.
+no_branch=Níl aon bhrainse ag an stóras seo.
code=Cód
code.desc=Rochtain ar chód foinse, comhaid, gealltanais agus brainsí.
@@ -1400,8 +1402,8 @@ editor.failed_to_commit=Theip ar athruithe a chur i bhfeidhm.
editor.failed_to_commit_summary=Teachtaireacht Earráide:
editor.fork_create=Stóras Forc chun Athruithe a Mholadh
-editor.fork_create_description=Ní féidir leat an stóras seo a chur in eagar go díreach. Ina áit sin, is féidir leat forc a chruthú, eagarthóireachtaí a dhéanamh agus iarratas tarraingthe a chruthú.
-editor.fork_edit_description=Ní féidir leat an stóras seo a chur in eagar go díreach. Scríobhfar na hathruithe chuig do fhorc %s, ionas gur féidir leat iarratas tarraingthe a chruthú.
+editor.fork_create_description=Ní féidir leat an stórlann seo a chur in eagar go díreach. Ina áit sin, is féidir leat forc a chruthú, eagarthóireachtaí a dhéanamh agus iarratas tarraingthe a chruthú.
+editor.fork_edit_description=Ní féidir leat an stórlann seo a chur in eagar go díreach. Scríobhfar na hathruithe chuig do fhorc %s, ionas gur féidir leat iarratas tarraingthe a chruthú.
editor.fork_not_editable=Tá forc déanta agat ar an stóras seo ach ní féidir do fhorc a chur in eagar.
editor.fork_failed_to_push_branch=Theip ar bhrainse %s a bhrú chuig do stóras.
editor.fork_branch_exists=Tá brainse "%s" ann cheana féin i do fhorc, roghnaigh ainm brainse nua le do thoil.
@@ -1755,7 +1757,7 @@ issues.due_date_form=bbbb-mm-ll
issues.due_date_form_add=Cuir dáta dlite leis
issues.due_date_form_edit=Cuir in eagar
issues.due_date_form_remove=Bain
-issues.due_date_not_writer=Ní mór duit rochtain scríofa ar an stór seo d'fhonn dáta dlite eisiúna a nuashonrú.
+issues.due_date_not_writer=Ní mór duit rochtain scríbhneoireachta a fháil ar an stóras seo chun dáta dlite saincheiste a nuashonrú.
issues.due_date_not_set=Níl aon dáta dlite socraithe.
issues.due_date_added=cuireadh an dáta dlite %s %s
issues.due_date_modified=d'athraigh an dáta dlite ó %[2]s go %[1]s %[3]s
@@ -1869,7 +1871,7 @@ pulls.select_commit_hold_shift_for_range=Roghnaigh tiomantas. Coinnigh shift + c
pulls.review_only_possible_for_full_diff=Ní féidir athbhreithniú a dhéanamh ach amháin nuair a bhreathnaítear ar an difríocht iomlán
pulls.filter_changes_by_commit=Scagaigh de réir tiomantas
pulls.nothing_to_compare=Tá na brainsí seo cothrom. Ní gá iarratas tarraingthe a chruthú.
-pulls.nothing_to_compare_have_tag=Tá an brainse/clib roghnaithe cothrom.
+pulls.nothing_to_compare_have_tag=Tá na brainsí/clibeanna roghnaithe comhionann.
pulls.nothing_to_compare_and_allow_empty_pr=Tá na brainsí seo cothrom. Beidh an PR seo folamh.
pulls.has_pull_request=`Tá iarratas tarraingthe idir na brainsí seo ann cheana: %[2]s#%[3]d`
pulls.create=Cruthaigh Iarratas Tarraing
@@ -2032,7 +2034,7 @@ milestones.filter_sort.most_issues=Saincheisteanna is mó
milestones.filter_sort.least_issues=Saincheisteanna is lú
signing.will_sign=Síneofar an gealltanas seo le heochair "%s".
-signing.wont_sign.error=Bhí earráid ann agus tú ag seiceáil an féidir an tiomantas a shíniú.
+signing.wont_sign.error=Tharla earráid agus seiceáil á dhéanamh an bhféadfaí an tiomnú a shíniú.
signing.wont_sign.nokey=Níl aon eochair ar fáil chun an tiomantas seo a shíniú.
signing.wont_sign.never=Ní shínítear tiomáintí riamh.
signing.wont_sign.always=Sínítear tiomáintí i gcónaí.
@@ -2123,7 +2125,7 @@ activity.title.releases_1=Scaoileadh %d
activity.title.releases_n=Eisiúintí %d
activity.title.releases_published_by=%s foilsithe ag %s
activity.published_release_label=Foilsithe
-activity.no_git_activity=Níor rinneadh aon ghníomhaíocht tiomanta sa tréimhse seo.
+activity.no_git_activity=Ní raibh aon ghníomhaíocht tiomantais ann sa tréimhse seo.
activity.git_stats_exclude_merges=Gan cumaisc a áireamh,
activity.git_stats_author_1=%d údar
activity.git_stats_author_n=%d údair
@@ -2541,7 +2543,7 @@ settings.block_on_official_review_requests_desc=Ní bheidh sé indéanta cumasc
settings.block_outdated_branch=Cuir bac ar chumasc má tá an t-iarratas tarraingthe as dáta
settings.block_outdated_branch_desc=Ní bheidh cumasc indéanta nuair a bhíonn ceannbhrainse taobh thiar de bhronnbhrainse.
settings.block_admin_merge_override=Ní mór do riarthóirí rialacha cosanta brainse a leanúint
-settings.block_admin_merge_override_desc=Ní mór do riarthóirí rialacha cosanta brainse a leanúint agus ní féidir leo dul timpeall air.
+settings.block_admin_merge_override_desc=Ní mór do riarthóirí rialacha cosanta brainse a leanúint agus ní féidir leo iad a sheachaint.
settings.default_branch_desc=Roghnaigh brainse stóras réamhshocraithe le haghaidh iarratas tarraingte agus geallann an cód:
settings.merge_style_desc=Stíleanna Cumaisc
settings.default_merge_style_desc=Stíl Cumaisc Réamhshocraithe
@@ -2568,10 +2570,10 @@ settings.matrix.homeserver_url=URL sheirbhíse baile
settings.matrix.room_id=ID seomra
settings.matrix.message_type=Cineál teachtaireachta
settings.visibility.private.button=Déan Príobháideach
-settings.visibility.private.text=Ní amháin go gcuirfidh an infheictheacht a athrú go príobháideach an repo infheicthe amháin do bhaill cheadaithe ach féadfaidh sé an gaol idir é agus forcanna, féachadóirí agus réaltaí a bhaint.
+settings.visibility.private.text=Má athraítear an infheictheacht go príobháideach, ní bheidh an stór le feiceáil ach ag baill cheadaithe agus d’fhéadfadh sé go mbainfí an gaol idir é agus forcanna, faireoirí agus réaltaí atá ann cheana féin.
settings.visibility.private.bullet_title=An infheictheacht a athrú go toil phríobháide
-settings.visibility.private.bullet_one=Déan an stóras infheicthe do chomhaltaí ceadaithe amháin.
-settings.visibility.private.bullet_two=B’fhéidir go mbainfear an gaol idir é agus forcanna, faireoirí, agus réaltaí.
+settings.visibility.private.bullet_one=Déan an stóras le feiceáil ag baill cheadaithe amháin.
+settings.visibility.private.bullet_two=D’fhéadfadh sé an gaol idir é agus forcanna, faireoirí, agus réaltaí a bhaint.
settings.visibility.public.button=Déan Poiblí
settings.visibility.public.text=Má athraíonn an infheictheacht don phobal, beidh an stóras le feiceáil do dhuine ar bith.
settings.visibility.public.bullet_title=Athróidh an infheictheacht go poiblí:
@@ -2868,7 +2870,7 @@ settings.delete_notices_2=Scriosfaidh an oibríocht seo go buan gach st
settings.delete_notices_3=Scriosfaidh an oibríocht seo gach pacáiste de chuid %s go buan.
settings.delete_notices_4=Scriosfaidh an oibríocht seo gach tionscadal de chuid %s go buan.
settings.confirm_delete_account=Deimhnigh scriosadh
-settings.delete_failed=Theip ar Scriosadh na hEagraíochta mar gheall ar earráid inmheánach
+settings.delete_failed=Theip ar Scriosadh Eagraíochta mar gheall ar earráid inmheánach
settings.delete_successful=Scriosadh an eagraíocht %s go rathúil.
settings.hooks_desc=Cuir crúcaí gréasán in leis a spreagfar do gach stóras faoin eagraíocht seo.
@@ -3018,9 +3020,9 @@ dashboard.resync_all_sshprincipals=Nuashonraigh an comhad '.ssh/authorized_princ
dashboard.resync_all_hooks=Athshioncrónaigh crúcaí réamhfhála, nuashonraithe agus iar-fhála na stórtha go léir.
dashboard.reinit_missing_repos=Aththosaigh gach stórais Git atá in easnamh a bhfuil taifid ann dóibh
dashboard.sync_external_users=Sioncrónaigh sonraí úsáideoirí seachtracha
-dashboard.cleanup_hook_task_table=Tábla hook_task glantacháin
-dashboard.cleanup_packages=Pacáistí glanta in éag
-dashboard.cleanup_actions=Gníomhaíochtaí glanta in éag acmhainní
+dashboard.cleanup_hook_task_table=Glan suas an tábla hook_task
+dashboard.cleanup_packages=Glan suas pacáistí atá imithe in éag
+dashboard.cleanup_actions=Glan suas acmhainní gníomhartha atá imithe in éag
dashboard.server_uptime=Aga fónaimh Freastalaí
dashboard.current_goroutine=Goroutines Reatha
dashboard.current_memory_usage=Úsáid Cuimhne Reatha
@@ -3251,6 +3253,8 @@ auths.oauth2_required_claim_name_helper=Socraigh an t-ainm seo chun logáil iste
auths.oauth2_required_claim_value=Luach Éilimh Riachtanach
auths.oauth2_required_claim_value_helper=Socraigh an luach seo chun logáil isteach ón bhfoinse seo a shrianadh chuig úsáideoirí a bhfuil éileamh acu leis an ainm agus an luach seo
auths.oauth2_group_claim_name=Ainm éileamh ag soláthar ainmneacha grúpa don fhoinse seo (Roghnach)
+auths.oauth2_full_name_claim_name=Ainm Iomlán Éilimh. (Roghnach, má shocraítear é, déanfar ainm iomlán an úsáideora a shioncrónú leis an éileamh seo i gcónaí)
+auths.oauth2_ssh_public_key_claim_name=Ainm Éilimh Eochrach Phoiblí SSH
auths.oauth2_admin_group=Luach Éilimh Grúpa d'úsáideoirí riarthóra. (Roghnach - teastaíonn ainm éilimh thuas)
auths.oauth2_restricted_group=Luach Éilimh Grúpa d'úsáideoirí srianta. (Roghnach - teastaíonn ainm éilimh thuas)
auths.oauth2_map_group_to_team=Map mhaígh grúpaí chuig foirne Eagraíochta. (Roghnach - éilíonn ainm an éilimh thuas)
@@ -3455,7 +3459,7 @@ monitor.start=Am Tosaigh
monitor.execute_time=Am Forghníomhaithe
monitor.last_execution_result=Toradh
monitor.process.cancel=Cealaigh próiseas
-monitor.process.cancel_desc=Má chuirtear próiseas ar ceal d'fhéadfadh go gcaillfí sonraí
+monitor.process.cancel_desc=D’fhéadfadh caillteanas sonraí a bheith mar thoradh ar phróiseas a chealú
monitor.process.children=Leanaí
monitor.queues=Scuaineanna
@@ -3727,7 +3731,7 @@ owner.settings.cargo.initialize.success=Cruthaíodh an t-innéacs Cargo go rath
owner.settings.cargo.rebuild=Innéacs Atógáil
owner.settings.cargo.rebuild.description=Is féidir atógáil a bheith úsáideach mura bhfuil an t-innéacs sioncronaithe leis na pacáistí Cargo stóráilte.
owner.settings.cargo.rebuild.error=Níorbh fhéidir an t-innéacs Cargo a atógáil: %v
-owner.settings.cargo.rebuild.success=D'éirigh leis an innéacs Cargo a atógáil.
+owner.settings.cargo.rebuild.success=Rinneadh innéacs an Charga a atógáil go rathúil.
owner.settings.cleanuprules.title=Bainistigh Rialacha Glanta
owner.settings.cleanuprules.add=Cuir Riail Glantacháin leis
owner.settings.cleanuprules.edit=Cuir Riail Glantacháin in eagar
@@ -3815,7 +3819,7 @@ runners.delete_runner=Scrios an reathaí seo
runners.delete_runner_success=Scriosadh an reathaí go rathúil
runners.delete_runner_failed=Theip ar an reathaí a scriosadh
runners.delete_runner_header=Deimhnigh an reathaí seo a scriosadh
-runners.delete_runner_notice=Má tá tasc ar siúl ar an reathaí seo, cuirfear deireadh leis agus marcáil mar theip. Féadfaidh sé sreabhadh oibre tógála a bhriseadh.
+runners.delete_runner_notice=Má tá tasc á rith ar an rithóir seo, cuirfear deireadh leis agus marcálfar é mar theip air. D’fhéadfadh sé seo cur isteach ar shreabhadh oibre na tógála.
runners.none=Níl aon reathaí ar fáil
runners.status.unspecified=Anaithnid
runners.status.idle=Díomhaoin
diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini
index e823b325a50..612d92709f3 100644
--- a/options/locale/locale_hu-HU.ini
+++ b/options/locale/locale_hu-HU.ini
@@ -848,7 +848,6 @@ issues.lock_duplicate=Egy hibajegy nem zárható be kétszer.
issues.unlock_error=Nem nyithatsz meg egy hibajegyet ami nincs is lezárva.
issues.lock_confirm=Lezárás
issues.unlock_confirm=Feloldás
-issues.lock.notice_1=- Más felhasználók nem szólhatnak hozzá ehhez a hibajegyhez.
issues.lock.reason=Zárolás oka
issues.lock.title=Beszélgetés lezárása ezen a hibajegyen.
issues.unlock.title=Hibajegy újranyitása.
@@ -1017,7 +1016,6 @@ activity.title.releases_1=%d Kiadás
activity.title.releases_n=%d Kiadások
activity.title.releases_published_by=%s publikálta %s
activity.published_release_label=Publikálva
-activity.no_git_activity=Nem voltak commit-ok ebben az időszakban.
activity.git_stats_commit_1=%d commit
activity.git_stats_commit_n=%d commit
activity.git_stats_file_n=%d fájl
diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini
index 10b600128d6..a93ac26a14b 100644
--- a/options/locale/locale_id-ID.ini
+++ b/options/locale/locale_id-ID.ini
@@ -117,7 +117,6 @@ pin=Sematkan
unpin=Lepas sematan
artifacts=Artefak
-confirm_delete_artifact=Apakah Anda yakin ingin menghapus artefak '%s' ?
archived=Diarsipkan
@@ -147,7 +146,6 @@ no_results_found=Hasil tidak ditemukan.
[search]
search=Cari...
type_tooltip=Tipe pencarian
-fuzzy_tooltip=Termasuk juga hasil yang mendekati kata pencarian
exact_tooltip=Hanya menampilkan hasil yang cocok dengan istilah pencarian
repo_kind=Cari repo...
user_kind=Telusuri pengguna...
@@ -294,7 +292,6 @@ email_domain_blacklisted=Anda tidak dapat mendaftar dengan alamat email.
authorize_application=Izinkan aplikasi
authorize_redirect_notice=Anda akan dialihkan ke %s apabila Anda mengizinkan aplikasi ini.
authorize_application_created_by=Aplikasi ini dibuat oleh %s.
-authorize_application_description=Jika Anda memberikan akses, itu akan bisa mengakses dan menulis semua informasi akun Anda, termasuk repositori pribadi dan organisasi.
authorize_title=Izinkan "%s" untuk mengakses akun Anda?
authorization_failed=Otorisasi gagal
sspi_auth_failed=Autentikasi SSPI gagal
@@ -456,7 +453,6 @@ activated=Diaktifkan
primary_email=Buat Utama
delete_email=Hapus
email_deletion=Hapus Alamat Email
-email_deletion_desc=Alamat email dan informasi terkait akan dihapus dari akun. Git commit dengan alamat email ini akan tetap tidak berubah. Lanjutkan?
email_deletion_success=Alamat email Anda telah dihapus.
theme_update_success=Tema Anda diperbarui.
theme_update_error=Thema yang dipilih tidak ada.
@@ -561,7 +557,6 @@ passcode_invalid=Kode sandi salah. Coba lagi.
manage_account_links=Kelola akun tertaut
manage_account_links_desc=Semua akun eksternal ini sementara tertaut dengan akun Gitea Anda.
-account_links_not_available=Saat ini tidak ada akun eksternal yang tertaut ke akun Gitea ini.
link_account=Tautan Akun
remove_account_link=Hapus Akun Tertaut
remove_account_link_desc=Menghapus akun tertaut akan membuat akun itu tidak bisa mengakses akun Gitea Anda. Lanjutkan?
diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini
index 3b4c6058019..0acd248d21c 100644
--- a/options/locale/locale_is-IS.ini
+++ b/options/locale/locale_is-IS.ini
@@ -298,8 +298,6 @@ activate_email=Staðfestu netfangið þitt
activate_email.text=Vinsamlegast smelltu á eftirfarandi tengil til að staðfesta netfangið þitt innan %s:
register_notify.title=%[1]s, velkomin(n) í %[2]s
-register_notify.text_1=þetta er staðfestingarpóstur þinn fyrir skráningu á %s!
-register_notify.text_2=Þú getur nú skráð þig inn með notandanafni: %s.
register_notify.text_3=Ef þessi reikningur hefur verið búinn til fyrir þig, vinsamlegast stilltu lykilorðið þitt fyrst.
reset_password=Endurheimta reikning þinn
@@ -479,7 +477,6 @@ activate_email=Senda Virkjun
activations_pending=Virkjanir í Bið
delete_email=Fjarlægja
email_deletion=Fjarlægja Netfang
-email_deletion_desc=Netfangið og tengdar upplýsingar verða fjarlægðar af reikningnum þínum. Git framlög með þessu netfangi verða óbreyttar. Halda áfram?
email_deletion_success=Netfangið hefur verið fjarlægt.
theme_update_success=Þeman þín var uppfærð.
theme_update_error=Valin þema er ekki til.
diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini
index 52fb0a3a506..80a3951e6b4 100644
--- a/options/locale/locale_it-IT.ini
+++ b/options/locale/locale_it-IT.ini
@@ -336,7 +336,6 @@ email_domain_blacklisted=Non è possibile registrarsi con il proprio indirizzo e
authorize_application=Autorizza applicazione
authorize_redirect_notice=Verrai reindirizzato a %s se autorizzi questa applicazione.
authorize_application_created_by=Questa applicazione è stata creata da %s.
-authorize_application_description=Se concedi l'accesso, l'app sarà in grado di accedere e modificare tutte le informazioni del tuo account, inclusi i repository privati e le organizzazioni.
authorize_title=Vuoi autorizzare "%s" ad accedere al tuo account?
authorization_failed=Autorizzazione fallita
sspi_auth_failed=Autenticazione SSPI fallita
@@ -356,8 +355,6 @@ activate_email=Verifica il tuo indirizzo e-mail
activate_email.text=Clicca sul seguente link per verificare il tuo indirizzo email entro %s:
register_notify.title=%[1]s, benvenuto in %[2]s
-register_notify.text_1=questa è la tua email di conferma di registrazione per %s!
-register_notify.text_2=Ora è possibile accedere tramite nome utente: %s.
register_notify.text_3=Se questo account è stato creato per te, per favore imposta prima la tua password.
reset_password=Recupera il tuo account
@@ -581,7 +578,6 @@ activate_email=Invia Attivazione
activations_pending=Attivazioni in sospeso
delete_email=Rimuovi
email_deletion=Rimuovi indirizzo Email
-email_deletion_desc=L'indirizzo email e le relativa informazioni verranno rimosse dal tuo account. I Git commits di questa email rimarranno invariati. Continuare?
email_deletion_success=L'indirizzo email è stato eliminato.
theme_update_success=Il tema è stato aggiornato.
theme_update_error=Il tema selezionato non esiste.
@@ -725,7 +721,6 @@ webauthn_delete_key_desc=Se si rimuove una chiave di sicurezza non è più possi
manage_account_links=Gestisci gli account collegati
manage_account_links_desc=Questi account esterni sono collegati al tuo account Gitea.
-account_links_not_available=Attualmente non è collegato alcun account esterno al tuo account Gitea.
link_account=Collega Account
remove_account_link=Rimuovi account collegato
remove_account_link_desc=Rimuovere un account collegato ne revoca l'accesso al tuo account Gitea. Continuare?
@@ -876,7 +871,6 @@ migrate_items_releases=Rilasci
migrate_repo=Migra Repository
migrate.clone_address=Migra / Clona da URL
migrate.clone_address_desc=URL HTTP (S) o Git 'clone' di un repository esistente
-migrate.github_token_desc=È possibile mettere uno o più token con virgola separati qui per rendere la migrazione più veloce a causa del limite di velocità API GitHub. ATTENZIONE: L'abuso di questa funzione potrebbe violare la politica del fornitore di servizi e portare al blocco dell'account.
migrate.clone_local_path=o un percorso del server locale
migrate.permission_denied=Non è consentito importare repository locali.
migrate.permission_denied_blocked=Non è possibile importare da host non consentiti, si prega di chiedere all'amministratore di controllare ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS impostazioni.
@@ -1242,7 +1236,6 @@ issues.lock_no_reason=ha bloccato e limitato la conversazione ai collaboratori %
issues.unlock_comment=ha sbloccato questa conversazione %s
issues.lock_confirm=Blocca
issues.unlock_confirm=Sblocca
-issues.lock.notice_1=- Altri utenti non possono aggiungere nuovi commenti a questo problema.
issues.lock.notice_2=- Tu e altri collaboratori con accesso a questo repository potete ancora lasciare commenti che altri possono vedere.
issues.lock.notice_3=- Puoi sempre sbloccare questo problema in futuro.
issues.unlock.notice_1=- Tutti potranno commentare nuovamente questo problema.
@@ -1555,7 +1548,6 @@ activity.title.releases_1=%d Release
activity.title.releases_n=%d Release
activity.title.releases_published_by=%s pubblicata da %s
activity.published_release_label=Pubblicata
-activity.no_git_activity=In questo periodo non c'è stata alcuna attività di commit.
activity.git_stats_exclude_merges=Escludendo i merge,
activity.git_stats_author_1=%d autore
activity.git_stats_author_n=%d autori
@@ -2198,8 +2190,6 @@ dashboard.resync_all_sshprincipals=Aggiornare il file '.ssh/authorized_keys' con
dashboard.resync_all_hooks=Sincronizza nuovamente gli hook di pre-ricezione, di aggiornamento e di post-ricezione di tutti i repository.
dashboard.reinit_missing_repos=Reinizializza tutti i repository Git mancanti per i quali esistono cambiamenti registrati esistenti
dashboard.sync_external_users=Sincronizza dati utente esterno
-dashboard.cleanup_hook_task_table=Pulisci tabella hook_task
-dashboard.cleanup_packages=Pulizia pacchetti scaduti
dashboard.server_uptime=Tempo in Attività del Server
dashboard.current_goroutine=Goroutine Correnti
dashboard.current_memory_usage=Utilizzo di Memoria Corrente
diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini
index face0881163..17bab4b451e 100644
--- a/options/locale/locale_ja-JP.ini
+++ b/options/locale/locale_ja-JP.ini
@@ -117,7 +117,6 @@ files=ファイル
error=エラー
error404=アクセスしようとしたページは存在しないか、閲覧が許可されていません。
-error503=サーバーはリクエストを完了できませんでした。 後でもう一度お試しください。
go_back=戻る
invalid_data=無効なデータ: %v
@@ -131,7 +130,6 @@ unpin=ピン留め解除
artifacts=成果物
expired=期限切れ
-confirm_delete_artifact=アーティファクト %s を削除してよろしいですか?
archived=アーカイブ
@@ -171,7 +169,6 @@ internal_error_skipped=内部エラーが発生しましたがスキップされ
search=検索…
type_tooltip=検索タイプ
fuzzy=あいまい
-fuzzy_tooltip=検索語におおよそ一致する結果も含めます
words=単語
words_tooltip=検索語と一致する結果だけを含めます
regexp=正規表現
@@ -358,7 +355,6 @@ no_reply_address=メールを隠すときのドメイン
no_reply_address_helper=メールアドレスを隠しているユーザーに使用するドメイン名。 例えば 'noreply.example.org' と設定した場合、ユーザー名 'joe' はGitに 'joe@noreply.example.org' としてログインすることになります。
password_algorithm=パスワードハッシュアルゴリズム
invalid_password_algorithm=無効なパスワードハッシュアルゴリズム
-password_algorithm_helper=パスワードハッシュアルゴリズムを設定します。 アルゴリズムにより動作要件と強度が異なります。 argon2アルゴリズムはかなり安全ですが、多くのメモリを使用するため小さなシステムには適さない場合があります。
enable_update_checker=アップデートチェッカーを有効にする
enable_update_checker_helper=gitea.ioに接続して定期的に新しいバージョンのリリースを確認します。
env_config_keys=環境設定
@@ -452,7 +448,6 @@ use_scratch_code=スクラッチコードを使う
twofa_scratch_used=あなたはスクラッチコードを使用しました。 2要素認証の設定ページにリダイレクトしましたので、デバイスの登録を解除するか、新しいスクラッチコードを生成しましょう。
twofa_passcode_incorrect=パスコードが正しくありません。デバイスを紛失した場合は、スクラッチコードを使ってサインインしてください。
twofa_scratch_token_incorrect=スクラッチコードが正しくありません。
-twofa_required=リポジトリにアクセスするには2段階認証を設定するか、再度ログインしてください。
login_userpass=サインイン
login_openid=OpenID
oauth_signup_tab=新規アカウント登録
@@ -464,7 +459,6 @@ oauth_signin_submit=アカウントにリンク
oauth.signin.error.general=認可リクエストの処理中にエラーが発生しました: %s 。このエラーが解決しない場合は、サイト管理者に問い合わせてください。
oauth.signin.error.access_denied=認可リクエストが拒否されました。
oauth.signin.error.temporarily_unavailable=認証サーバーが一時的に利用できないため、認可に失敗しました。後でもう一度やり直してください。
-oauth_callback_unable_auto_reg=自動登録が有効になっていますが、OAuth2プロバイダー %[1]s の応答はフィールド %[2]s が不足しており、自動でアカウントを作成することができません。 アカウントを作成またはリンクするか、サイト管理者に問い合わせてください。
openid_connect_submit=接続
openid_connect_title=既存のアカウントに接続
openid_connect_desc=選択したOpenID URIは未登録です。 ここで新しいアカウントと関連付けます。
@@ -477,7 +471,6 @@ email_domain_blacklisted=あなたのメールアドレスでは登録するこ
authorize_application=アプリケーションを許可
authorize_redirect_notice=このアプリケーションを許可すると %s にリダイレクトします。
authorize_application_created_by=このアプリケーションは %s が作成しました。
-authorize_application_description=アクセスを許可すると、このアプリケーションは、プライベート リポジトリや組織を含むあなたのすべてのアカウント情報に対して、アクセスと書き込みができるようになります。
authorize_application_with_scopes=スコープ: %s
authorize_title=`"%s"にあなたのアカウントへのアクセスを許可しますか?`
authorization_failed=認可失敗
@@ -506,8 +499,6 @@ activate_email.text=あなたのメールアドレスを確認するため、
register_notify=%s へようこそ
register_notify.title=%[1]s さん、%[2]s にようこそ
-register_notify.text_1=これは %s への登録確認メールです!
-register_notify.text_2=あなたはユーザー名 %s でログインできるようになりました。
register_notify.text_3=このアカウントがあなたに作成されたものであれば、最初にパスワードを設定してください。
reset_password=アカウントを回復
@@ -689,7 +680,6 @@ form.name_chars_not_allowed=ユーザー名 "%s" には無効な文字が含ま
block.block=ブロック
block.block.user=ユーザーをブロック
-block.block.org=組織向けにユーザーをブロック
block.block.failure=ユーザーのブロックに失敗しました: %s
block.unblock=ブロックを解除
block.unblock.failure=ユーザーのブロック解除に失敗しました: %s
@@ -733,7 +723,6 @@ webauthn=2要素認証 (セキュリティキー)
public_profile=公開プロフィール
biography_placeholder=自己紹介してください!(Markdownを使うことができます)
location_placeholder=おおよその場所を他の人と共有
-profile_desc=あなたのプロフィールが他のユーザーにどのように表示されるかを制御します。あなたのプライマリメールアドレスは、通知、パスワードの回復、WebベースのGit操作に使用されます。
password_username_disabled=ユーザー名の変更は許可されていません。詳細はサイト管理者にお問い合わせください。
password_full_name_disabled=フルネームの変更は許可されていません。詳細はサイト管理者にお問い合わせください。
full_name=フルネーム
@@ -812,7 +801,6 @@ activations_pending=アクティベーション待ち
can_not_add_email_activations_pending=保留中のアクティベーションがあります。新しいメールを追加する場合は、数分後にもう一度お試しください。
delete_email=削除
email_deletion=メールアドレスの削除
-email_deletion_desc=メールアドレスと関連情報をアカウントから削除します。 このメールアドレスを使ったGitのコミットはそのまま残ります。 続行しますか?
email_deletion_success=メールアドレスを削除しました。
theme_update_success=テーマを更新しました。
theme_update_error=選択されたテーマが存在しません。
@@ -998,7 +986,6 @@ webauthn_alternative_tip=もうひとつ別の認証方法も設定しておく
manage_account_links=連携アカウントの管理
manage_account_links_desc=これらの外部アカウントがGiteaアカウントと連携されています。
-account_links_not_available=現在このGiteaアカウントが連携している外部アカウントはありません。
link_account=アカウントをリンク
remove_account_link=連携アカウントの削除
remove_account_link_desc=連携アカウントを削除し、Giteaアカウントへのアクセス権を取り消します。 続行しますか?
@@ -1035,8 +1022,6 @@ new_repo_helper=リポジトリには、プロジェクトのすべてのファ
owner=オーナー
owner_helper=リポジトリ数の上限により、一部の組織はドロップダウンに表示されない場合があります。
repo_name=リポジトリ名
-repo_name_profile_public_hint=.profile は特別なリポジトリで、これを使用して、あなたの組織の公開プロフィール(誰でも閲覧可能)に README.md を追加することができます。 利用を開始するには、必ず公開リポジトリとし、プロフィールディレクトリにREADMEを追加して初期化してください。
-repo_name_profile_private_hint=.profile-private は特別なリポジトリで、これを使用して、あなたの組織のメンバー向けプロフィール(組織メンバーのみ閲覧可能)に README.md を追加することができます。 利用を開始するには、必ずプライベートリポジトリとし、プロフィールディレクトリにREADMEを追加して初期化してください。
repo_name_helper=リポジトリ名は、短く、覚えやすく、他と重複しないキーワードを使用しましょう。 リポジトリ名を ".profile" または ".profile-private" にして README.md を追加すると、ユーザーや組織のプロフィールとなります。
repo_size=リポジトリサイズ
template=テンプレート
@@ -1058,7 +1043,6 @@ fork_branch=フォークにクローンされるブランチ
all_branches=すべてのブランチ
view_all_branches=すべてのブランチを表示
view_all_tags=すべてのタグを表示
-fork_no_valid_owners=このリポジトリには有効なオーナーがいないため、フォークできません。
fork.blocked_user=リポジトリのオーナーがあなたをブロックしているため、リポジトリをフォークできません。
use_template=このテンプレートを使用
open_with_editor=%s で開く
@@ -1102,7 +1086,6 @@ mirror_sync=前回の同期
mirror_sync_on_commit=コミットがプッシュされたときに同期
mirror_address=クローンするURL
mirror_address_desc=必要な資格情報は「認証」セクションに設定してください。
-mirror_address_url_invalid=入力したURLは無効です。 URLの構成要素はすべて正しくエスケープする必要があります。
mirror_address_protocol_invalid=入力したURLは無効です。 ミラーできるのは、http(s):// または git:// からだけです。
mirror_lfs=Large File Storage (LFS)
mirror_lfs_desc=LFS データのミラーリングを有効にする。
@@ -1162,8 +1145,6 @@ template.issue_labels=イシューラベル
template.one_item=最低一つはテンプレート項目を選択する必要があります
template.invalid=テンプレートリポジトリを選択する必要があります
-archive.title=このリポジトリはアーカイブされています。 ファイルの閲覧とクローンは可能ですが、プッシュ、イシューの作成、プルリクエストはできません。
-archive.title_date=このリポジトリは%sにアーカイブされています。 ファイルの閲覧とクローンは可能ですが、プッシュ、イシューの作成、プルリクエストはできません。
archive.issue.nocomment=このリポジトリはアーカイブされています。 イシューにコメントを追加することはできません。
archive.pull.nocomment=このリポジトリはアーカイブされています。 プルリクエストにコメントを追加することはできません。
@@ -1192,7 +1173,6 @@ migrate_items_releases=リリース
migrate_repo=リポジトリを移行
migrate.clone_address=移行 / クローンするURL
migrate.clone_address_desc=既存リポジトリの、HTTP(S)またはGit形式のクローンURL
-migrate.github_token_desc=GitHub APIにはレート制限があります。移行をより速くするために、ここにカンマ区切りで複数のトークンを入力することができます。 警告: この機能を悪用すると、サービスプロバイダのポリシーに違反し、アカウントがブロックされる可能性があります。
migrate.clone_local_path=、またはローカルサーバー上のパス
migrate.permission_denied=ローカルリポジトリをインポートする権限がありません。
migrate.permission_denied_blocked=許可されていないホストからインポートできません。管理者に問い合わせて、ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS の設定を確認してください。
@@ -1253,7 +1233,6 @@ create_new_repo_command=コマンドラインから新しいリポジトリを
push_exist_repo=コマンドラインから既存のリポジトリをプッシュ
empty_message=このリポジトリの中には何もありません。
broken_message=このリポジトリの基礎となる Git のデータを読み取れません。このインスタンスの管理者に相談するか、このリポジトリを削除してください。
-no_branch=このリポジトリにはブランチがありません。
code=コード
code.desc=ソースコード、ファイル、コミット、ブランチにアクセス。
@@ -1693,7 +1672,6 @@ issues.lock_no_reason=がロックして会話を共同作業者に限定 %s
issues.unlock_comment=がこの会話をアンロック %s
issues.lock_confirm=ロック
issues.unlock_confirm=アンロック
-issues.lock.notice_1=- 他のユーザーはこのイシューに新しいコメントを追加できません。
issues.lock.notice_2=- あなたとこのリポジトリにアクセスできる共同作業者はまだコメントを残すことができ、そのコメントは他の人も見ることができます。
issues.lock.notice_3=- アンロックはいつでも可能です。
issues.unlock.notice_1=- 誰でもこのイシューにもう一度コメントできるようになります。
@@ -1746,7 +1724,6 @@ issues.due_date_form=yyyy-mm-dd
issues.due_date_form_add=期日の追加
issues.due_date_form_edit=変更
issues.due_date_form_remove=削除
-issues.due_date_not_writer=イシューの期日を変更するには、リポジトリへの書き込み権限が必要です。
issues.due_date_not_set=期日は設定されていません。
issues.due_date_added=が期日 %s を追加 %s
issues.due_date_modified=が期日を %[2]s から %[1]s に変更 %[3]s
@@ -1860,7 +1837,6 @@ pulls.select_commit_hold_shift_for_range=コミットを選択。シフトを押
pulls.review_only_possible_for_full_diff=すべての差分を表示しているときだけレビューが可能です
pulls.filter_changes_by_commit=コミットで絞り込み
pulls.nothing_to_compare=同じブランチ同士のため、 プルリクエストを作成する必要がありません。
-pulls.nothing_to_compare_have_tag=選択したブランチ/タグは同一のものです。
pulls.nothing_to_compare_and_allow_empty_pr=これらのブランチは内容が同じです。 空のプルリクエストになります。
pulls.has_pull_request=`同じブランチのプルリクエストはすでに存在します: %[2]s#%[3]d`
pulls.create=プルリクエストを作成
@@ -2022,7 +1998,6 @@ milestones.filter_sort.most_issues=イシューの多い順
milestones.filter_sort.least_issues=イシューの少ない順
signing.will_sign=このコミットは鍵 "%s" で署名されます。
-signing.wont_sign.error=コミットの署名可否を確認中にエラーが発生しました。
signing.wont_sign.nokey=このコミットに署名するための鍵がありません。
signing.wont_sign.never=コミットが署名されることはありません。
signing.wont_sign.always=コミットは常に署名されます。
@@ -2113,7 +2088,6 @@ activity.title.releases_1=%d件のリリース
activity.title.releases_n=%d件のリリース
activity.title.releases_published_by=%sが%sによって発行されました
activity.published_release_label=発行
-activity.no_git_activity=この期間にはコミットのアクティビティがありません。
activity.git_stats_exclude_merges=マージを除くと、
activity.git_stats_author_1=%d人の作成者
activity.git_stats_author_n=%d人の作成者
@@ -2525,7 +2499,6 @@ settings.block_on_official_review_requests_desc=公式レビュー依頼があ
settings.block_outdated_branch=遅れているプルリクエストのマージをブロック
settings.block_outdated_branch_desc=baseブランチがheadブランチより進んでいる場合、マージできないようにします。
settings.block_admin_merge_override=管理者もブランチ保護のルールに従う
-settings.block_admin_merge_override_desc=管理者はブランチ保護のルールに従う必要があり、回避することはできません。
settings.default_branch_desc=プルリクエストやコミット表示のデフォルトのブランチを選択:
settings.merge_style_desc=マージ スタイル
settings.default_merge_style_desc=デフォルトのマージスタイル
@@ -2552,10 +2525,7 @@ settings.matrix.homeserver_url=ホームサーバー URL
settings.matrix.room_id=ルーム ID
settings.matrix.message_type=メッセージ種別
settings.visibility.private.button=プライベートにする
-settings.visibility.private.text=プライベートに変更した場合、リポジトリを許可されたメンバーのみが閲覧できるようにするだけでなく、フォーク、ウォッチャー、スターとの関係を解除する可能性もあります。
settings.visibility.private.bullet_title=プライベートに変更すると:
-settings.visibility.private.bullet_one=リポジトリを許可されたメンバーのみが閲覧できるようにします。
-settings.visibility.private.bullet_two=フォーク、ウォッチャー、スターとの関係を解除する可能性があります。
settings.visibility.public.button=公開する
settings.visibility.public.text=公開に変更すると、リポジトリを誰でも閲覧できるようにします。
settings.visibility.public.bullet_title=公開に変更すると:
@@ -2807,7 +2777,6 @@ team_permission_desc=権限
team_unit_desc=リポジトリのセクションへのアクセスを許可
team_unit_disabled=(無効)
-form.name_been_taken=組織名 "%s" は既に使用されています。
form.name_reserved=組織名 "%s" は予約されています。
form.name_pattern_not_allowed=`"%s" の形式は組織名に使用できません。`
form.create_org_not_allowed=組織を作成する権限がありません。
@@ -2849,7 +2818,6 @@ settings.delete_notices_2=この操作により、%sのすべ
settings.delete_notices_3=この操作により、%sのすべてのパッケージが恒久的に削除されます。
settings.delete_notices_4=この操作により、%sのすべてのプロジェクトが恒久的に削除されます。
settings.confirm_delete_account=削除を確認
-settings.delete_failed=内部エラーのため組織を削除できませんでした
settings.delete_successful=組織の%sの削除に成功しました。
settings.hooks_desc=この組織のすべてのリポジトリでトリガーされるWebhookを追加します。
@@ -2999,9 +2967,6 @@ dashboard.resync_all_sshprincipals='.ssh/authorized_principals' ファイルをG
dashboard.resync_all_hooks=すべてのリポジトリの pre-receive, update, post-receive フックを更新する。
dashboard.reinit_missing_repos=レコードが存在するが見当たらないすべてのGitリポジトリを再初期化する
dashboard.sync_external_users=外部ユーザーデータの同期
-dashboard.cleanup_hook_task_table=hook_taskテーブルのクリーンアップ
-dashboard.cleanup_packages=期限切れパッケージのクリーンアップ
-dashboard.cleanup_actions=期限切れのActionsリソースのクリーンアップ
dashboard.server_uptime=サーバーの稼働時間
dashboard.current_goroutine=現在のGoroutine数
dashboard.current_memory_usage=現在のメモリ使用量
@@ -3436,7 +3401,6 @@ monitor.start=開始日時
monitor.execute_time=実行時間
monitor.last_execution_result=結果
monitor.process.cancel=処理をキャンセル
-monitor.process.cancel_desc=処理をキャンセルするとデータが失われる可能性があります
monitor.process.children=子プロセス
monitor.queues=キュー
@@ -3708,7 +3672,6 @@ owner.settings.cargo.initialize.success=Cargoインデックスは正常に作
owner.settings.cargo.rebuild=インデックスを再構築
owner.settings.cargo.rebuild.description=インデックスが格納されているCargoパッケージと同期していない場合は、再構築すると良いでしょう。
owner.settings.cargo.rebuild.error=Cargoインデックスの再構築に失敗しました: %v
-owner.settings.cargo.rebuild.success=Cargoインデックスは正常に再構築されました。
owner.settings.cleanuprules.title=クリーンアップルールの管理
owner.settings.cleanuprules.add=クリーンアップルールを追加
owner.settings.cleanuprules.edit=クリーンアップルールを編集
@@ -3796,7 +3759,6 @@ runners.delete_runner=このランナーを削除
runners.delete_runner_success=ランナーを削除しました
runners.delete_runner_failed=ランナーの削除に失敗しました
runners.delete_runner_header=ランナー削除の確認
-runners.delete_runner_notice=このランナーでタスクが実行されている場合、タスクは停止され失敗扱いとなります。 それによりビルドワークフローが途中で終了することになるかもしれません。
runners.none=利用可能なランナーはありません
runners.status.unspecified=不明
runners.status.idle=アイドル
diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini
index 4d6156e93f2..5ce61b899bf 100644
--- a/options/locale/locale_ko-KR.ini
+++ b/options/locale/locale_ko-KR.ini
@@ -416,7 +416,6 @@ activated=활성화됨
primary_email=프라이머리로 만들기
delete_email=삭제
email_deletion=이메일 주소 삭제
-email_deletion_desc=계정의 이메일 주소와 관련된 정보가 삭제됩니다. 이메일 주소로 이미 커밋된 내용들은 바뀌지 않고 남아있게 됩니다. 계속 진행하시겠습니까?
email_deletion_success=이메일 주소가 삭제되었습니다.
theme_update_success=테마가 갱신되었습니다.
theme_update_error=선택한 테마가 존재하지 않습니다.
@@ -510,7 +509,6 @@ twofa_enrolled=당신의 계정에 2단계 인증이 설정되었습니다. 스
manage_account_links=연결된 계정 관리
manage_account_links_desc=Gitea 계정에 연결된 외부 계정입니다.
-account_links_not_available=현재 Gitea 계정에 연결된 외부 계정이 없습니다.
link_account=계정 연결
remove_account_link=연결된 계정 제거
remove_account_link_desc=해당 계정을 연결해제 하는 경우 Gitea 계정에 대한 접근 권한이 사라지게 됩니다. 계속하시겠습니까?
diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini
index 2e430ff3998..c9d34914c33 100644
--- a/options/locale/locale_lv-LV.ini
+++ b/options/locale/locale_lv-LV.ini
@@ -306,7 +306,6 @@ no_reply_address=Neatbildēt e-pasta adreses domēns
no_reply_address_helper=Domēns lietotāja e-pasta adresei git žurnālos, ja lietotājs izvēlas paturēt savu e-pasta adresi privātu. Piemēram, ja lietotājs ir 'janis' un domēns 'neatbildet.piemers.lv', tad e-pasta adrese būs 'janis@neatbildet.piemers.lv'.
password_algorithm=Paroles jaucējsummas algoritms
invalid_password_algorithm=Kļūdaina paroles jaucējfunkcija
-password_algorithm_helper=Norādiet paroles jaucējalgoritmu. Algoritmi atšķirās pēc prasībām pret resursiem un stipruma. Argon2 algoritms ir drošs, bet tam nepieciešams daudz operatīvās atmiņas, līdz ar ko tas var nebūt piemērots sistēmām ar maz pieejamajiem resursiem.
enable_update_checker=Iespējot jaunu versiju paziņojumus
enable_update_checker_helper=Periodiski pārbaudīt jaunu version pieejamību, izgūstot datus no gitea.io.
env_config_keys=Vides konfigurācija
@@ -407,7 +406,6 @@ email_domain_blacklisted=Nav atļauts reģistrēties ar šādu e-pasta adresi.
authorize_application=Autorizēt lietotni
authorize_redirect_notice=Jūs tiksiet nosūtīts uz %s, ja autorizēsiet šo lietotni.
authorize_application_created_by=Šo lietotni izveidoja %s.
-authorize_application_description=Ja piešķirsiet tiesības, tā varēs piekļūt un mainīt Jūsu konta informāciju, ieskaitot privātos repozitorijus un organizācijas.
authorize_title=Autorizēt "%s" piekļuvi jūsu kontam?
authorization_failed=Autorizācija neizdevās
authorization_failed_desc=Autentifikācija neizdevās, jo tika veikts kļūdains pieprasījums. Sazinieties ar lietojumprogrammas, ar kuru mēģinājāt autentificēties, uzturētāju.
@@ -430,8 +428,6 @@ activate_email.title=%s, apstipriniet savu e-pasta adresi
activate_email.text=Nospiediet uz saites, lai apstiprinātu savu e-pasta adresi lapā %s:
register_notify.title=%[1]s, esat reģistrējies %[2]s
-register_notify.text_1=šis ir reģistrācijas apstiprinājuma e-pasts lapai %s!
-register_notify.text_2=Tagad varat autorizēties ar lietotāja vārdu: %s.
register_notify.text_3=Ja šis konts Jums tika izveidots, tad obligāti nomainiet citu paroli.
reset_password=Atgūt kontu
@@ -625,7 +621,6 @@ uid=UID
public_profile=Publiskais profils
biography_placeholder=Pastāsti mums mazliet par sevi! (Var izmantot Markdown)
location_placeholder=Kopīgot savu aptuveno atrašanās vietu ar citiem
-profile_desc=Norādīt, kā profils tiek attēlots citiem lietotājiem. Primārā e-pasta adrese tiks izmantota paziņojumiem, paroles atjaunošanai un Git tīmekļa darbībām.
full_name=Pilns vārds
website=Mājas lapa
location=Atrašanās vieta
@@ -699,7 +694,6 @@ activations_pending=Gaida aktivizāciju
can_not_add_email_activations_pending=Ir nepabeigta aktivizācija. Pēc dažām minūtēm mēģiniet vēlreiz, ja ir vēlme pievienot jaunu e-pasta adresi.
delete_email=Noņemt
email_deletion=Dzēst e-pasta adresi
-email_deletion_desc=E-pasta adrese un ar to saistītā informācija tiks dzēsta no šī konta. Git revīzijas ar šo e-pasta adresi netiks mainītas. Vai turpināt?
email_deletion_success=E-pasta adrese ir veiksmīgi izdzēsta.
theme_update_success=Jūsu motīvs tika nomainīts.
theme_update_error=Izvēlētais motīvs neeksistē.
@@ -876,7 +870,6 @@ webauthn_alternative_tip=Ir vēlams uzstādīt papildu autentifikācijas veidu.
manage_account_links=Pārvaldīt saistītos kontus
manage_account_links_desc=Šādi ārējie konti ir piesaistīti Jūsu Gitea kontam.
-account_links_not_available=Pašlaik nav neviena ārējā konta piesaistīta šim kontam.
link_account=Sasaistīt kontu
remove_account_link=Noņemt saistīto kontu
remove_account_link_desc=Noņemot saistīto kontu, tam tiks liegta piekļuve Jūsu Gitea kontam. Vai turpināt?
@@ -931,7 +924,6 @@ fork_to_different_account=Atdalīt uz citu kontu
fork_visibility_helper=Atdalītam repozitorijam nav iespējams mainīt tā redzamību.
fork_branch=Atzars, ko klonēt atdalītajā repozitorijā
all_branches=Visi atzari
-fork_no_valid_owners=Šim repozitorijam nevar izveidot atdalītu repozitoriju, jo tam nav spēkā esošu īpašnieku.
use_template=Izmantot šo sagatavi
download_zip=Lejupielādēt ZIP
download_tar=Lejupielādēt TAR.GZ
@@ -967,7 +959,6 @@ mirror_interval_invalid=Nekorekts spoguļošanas intervāls.
mirror_sync_on_commit=Sinhronizēt, kad revīzijas tiek iesūtītas
mirror_address=Spoguļa adrese
mirror_address_desc=Pieslēgšanās rekvizītus norādiet autorizācijas sadaļā.
-mirror_address_url_invalid=Norādītais URL ir nederīgs. Visas URL daļas ir jānorāda pareizi.
mirror_address_protocol_invalid=Norādītais URL ir nederīgs. Var spoguļot tikai no http(s):// vai git:// adresēm.
mirror_lfs=Lielu failu glabātuve (LFS)
mirror_lfs_desc=Aktivizēt LFS datu spoguļošanu.
@@ -1021,8 +1012,6 @@ template.issue_labels=Problēmu iezīmes
template.one_item=Norādiet vismaz vienu sagataves vienumu
template.invalid=Norādiet sagataves repozitoriju
-archive.title=Šis repozitorijs ir arhivēts. Ir iespējams aplūkot tā failus un to konēt, bet nav iespējams iesūtīt izmaiņas, kā arī izveidot jaunas problēmas vai izmaiņu pieprasījumus.
-archive.title_date=Šis repozitorijs tika arhivēts %s. Ir iespējams aplūkot tā failus un to konēt, bet nav iespējams iesūtīt izmaiņas, kā arī izveidot jaunas problēmas vai izmaiņu pieprasījumus.
archive.issue.nocomment=Repozitorijs ir arhivēts. Problēmām nevar pievienot jaunus komentārus.
archive.pull.nocomment=Repozitorijs ir arhivēts. Izmaiņu pieprasījumiem nevar pievienot jaunus komentārus.
@@ -1051,7 +1040,6 @@ migrate_items_releases=Laidienus
migrate_repo=Migrēt repozitoriju
migrate.clone_address=Klonēšanas adrese
migrate.clone_address_desc=Tā var būt HTTP(S) adrese vai Git 'clone' URL eksistējošam repozitorijam
-migrate.github_token_desc=Ir iespējams izmantot vienu vai ar komantiem atdalītus vairākas pilnvaras, lai veiktu ātrāku migrāciju, ja tā tiek ierobežota ar GitHub API ierobežojumiem. BRĪDINĀJUMS: Šīs iespējas ļaunprātīga izmantošana, var tikt uzskatīta par lietošanas noteikumu pārkāpumu ar no tā izrietošām sekām.
migrate.clone_local_path=vai servera lokālais ceļš
migrate.permission_denied=Jums nav tiesību importēt lokālu repozitoriju.
migrate.permission_denied_blocked=Nav iespējams importēt no neatļautām adresēm, prasiet administratoram pārskatīt ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS iestatījumus.
@@ -1505,7 +1493,6 @@ issues.lock_no_reason=slēdza un ierobežoja komentāru pievienošanu tikai līd
issues.unlock_comment=atļāva komentēšanu %s
issues.lock_confirm=Slēgt
issues.unlock_confirm=Atļaut
-issues.lock.notice_1=- Citi lietotāji nevar pievienot jaunus komentārus šai problēmai.
issues.lock.notice_2=- Jums un citiem līdzstrādniekiem ar piekļuvi šim repozitorijam tiks saglabāta iespēja pievienot komentārus.
issues.lock.notice_3=- Jūs vienmēr varat atkal atļaut komentēšanu.
issues.unlock.notice_1=- Ikviens varēs atkal pievienot jaunus komentārus.
@@ -1543,7 +1530,6 @@ issues.due_date_form=dd.mm.yyyy
issues.due_date_form_add=Pievienot izpildes termiņu
issues.due_date_form_edit=Labot
issues.due_date_form_remove=Noņemt
-issues.due_date_not_writer=Ir nepieciešama rakstīšanas piekļuve šim repozitorijam, lai varētu mainīt problēmas plānoto izpildes datumu.
issues.due_date_not_set=Izpildes termiņš nav uzstādīts.
issues.due_date_added=pievienoja izpildes termiņu %s %s
issues.due_date_modified=mainīja termiņa datumu no %[2]s uz %[1]s %[3]s
@@ -1794,7 +1780,6 @@ milestones.filter_sort.most_issues=Visvairāk problēmu
milestones.filter_sort.least_issues=Vismazāk problēmu
signing.will_sign=Šī revīzija tiks parakstīta ar atslēgu "%s".
-signing.wont_sign.error=Notika kļūda pārbaudot vai revīzija var tikt parakstīta.
signing.wont_sign.nokey=Nav pieejamas atslēgas, ar ko parakstīt šo revīziju.
signing.wont_sign.never=Revīzijas nekad netiek parakstītas.
signing.wont_sign.always=Revīzijas vienmēr tiek parakstītas.
@@ -1881,7 +1866,6 @@ activity.title.releases_1=%d versiju
activity.title.releases_n=%d versijas
activity.title.releases_published_by=%s publicēja %s
activity.published_release_label=Publicēts
-activity.no_git_activity=Šajā laika periodā nav notikušas nekādas izmaiņas.
activity.git_stats_exclude_merges=Neskaitot sapludināšanas revīzijas,
activity.git_stats_author_1=%d autors
activity.git_stats_author_n=%d autori
@@ -2638,8 +2622,6 @@ dashboard.resync_all_sshprincipals=Atjaunot '.ssh/authorized_principals' failu a
dashboard.resync_all_hooks=Pārsinhronizēt pirms-saņemšanas, atjaunošanas un pēc-saņemšanas āķus visiem repozitorijiem.
dashboard.reinit_missing_repos=Atkārtoti inicializēt visus pazaudētos Git repozitorijus par kuriem eksistē ieraksti
dashboard.sync_external_users=Sinhronizēt ārējo lietotāju datus
-dashboard.cleanup_hook_task_table=Iztīrīt tīmekļa āķu vēsturi
-dashboard.cleanup_packages=Notīrīt novecojušās pakotnes
dashboard.server_uptime=Servera darbības laiks
dashboard.current_goroutine=Izmantotās Gorutīnas
dashboard.current_memory_usage=Pašreiz izmantotā atmiņa
@@ -3293,7 +3275,6 @@ owner.settings.cargo.initialize.success=Cargo indekss tika veiksmīgi inicializ
owner.settings.cargo.rebuild=Pārbūvēt indeksu
owner.settings.cargo.rebuild.description=Pārbūvēšana var būt noderīga, ja indekss nav sinhronizēts ar saglabātajām Cargo pakotnēm.
owner.settings.cargo.rebuild.error=Neizdevās pārbūvēt Cargo indeksu: %v
-owner.settings.cargo.rebuild.success=Cargo indekss tika veiksmīgi pārbūvēts.
owner.settings.cleanuprules.title=Pārvaldīt notīrīšanas noteikumus
owner.settings.cleanuprules.add=Pievienot notīrīšanas noteikumu
owner.settings.cleanuprules.edit=Labot notīrīšanas noteikumu
@@ -3376,7 +3357,6 @@ runners.delete_runner=Dzēst izpildītāju
runners.delete_runner_success=Izpildītājs veiksmīgi izdzēsts
runners.delete_runner_failed=Neizdevās izdzēst izpildītāju
runners.delete_runner_header=Apstiprināt izpildītāja izdzēšanu
-runners.delete_runner_notice=Ja šis izpildītājs veic kādus uzdevumus, tad tie tiks apturēti un atzīmēti kā neizdevušies. Tas var sabojāt būvēšanas darbaplūsmas.
runners.none=Nav pieejami izpildītāji
runners.status.unspecified=Nezināms
runners.status.idle=Dīkstāvē
diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini
index 01e279f91ae..7d4d0345c12 100644
--- a/options/locale/locale_nl-NL.ini
+++ b/options/locale/locale_nl-NL.ini
@@ -335,7 +335,6 @@ email_domain_blacklisted=Je kan je niet registreren met dit e-mailadres.
authorize_application=Autoriseer applicatie
authorize_redirect_notice=U wordt doorgestuurd naar %s als u deze toepassing toestaat.
authorize_application_created_by=Deze applicatie is gemaakt door %s.
-authorize_application_description=Als u toegang verleent, zal de applicatie toegang hebben tot en kunnen schrijven naar al uw accountgegevens, met inbegrip van privérepo's en -organisaties.
authorize_title=Autoriseer "%s" voor toegang tot uw account?
authorization_failed=Autorisatie mislukt
sspi_auth_failed=SSPI-authenticatie mislukt
@@ -355,8 +354,6 @@ activate_email=Verifieer uw e-mailadres
activate_email.text=Klik op de volgende link om je e-mailadres te bevestigen in %s:
register_notify.title=%[1]s, welkom bij %[2]s
-register_notify.text_1=dit is uw registratie bevestigingsemail voor %s!
-register_notify.text_2=U kunt nu inloggen via de gebruikersnaam: %s.
register_notify.text_3=Als dit account voor u is aangemaakt, kunt u eerst uw wachtwoord instellen.
reset_password=Account herstellen
@@ -580,7 +577,6 @@ activate_email=Stuur activatie
activations_pending=Activaties in behandeling
delete_email=Verwijder
email_deletion=Verwijder e-mailadres
-email_deletion_desc=Het e-mailadres en verwante informatie worden verwijderd uit je account. Git commits van dit e-mailadres blijven ongewijzigd. Wil je doorgaan?
email_deletion_success=Het e-mailadres is verwijderd.
theme_update_success=Je thema is bijgewerkt.
theme_update_error=Het geselecteerde thema bestaat niet.
@@ -723,7 +719,6 @@ webauthn_delete_key_desc=Als u een beveiligingssleutel verwijdert, kunt u er nie
manage_account_links=Gekoppelde accounts beheren
manage_account_links_desc=Deze externe accounts zijn gekoppeld aan je Gitea-account.
-account_links_not_available=Er zijn momenteel geen externe accounts aan je Gitea-account gelinkt.
link_account=Account koppelen
remove_account_link=Gekoppeld account verwijderen
remove_account_link_desc=Als je een gekoppeld account verwijdert, verliest dit account toegang tot je Gitea-account. Doorgaan?
@@ -874,7 +869,6 @@ migrate_items_releases=Releases
migrate_repo=Migreer repository
migrate.clone_address=Migreer / kloon van URL
migrate.clone_address_desc=De HTTP(s)- of 'git clone'-URL van een bestaande repository
-migrate.github_token_desc=Je kunt hier een of meerdere tokens met komma gescheiden plaatsen om sneller te migreren door de GitHub API limiet te beperken. WAARSCHUWING: Het misbruik van deze functie kan in strijd zijn met het beleid van de serviceprovider en leiden tot het blokkeren van rekeningen.
migrate.clone_local_path=of een lokaal pad
migrate.permission_denied=U bent niet gemachtigd om deze lokale repositories te importeren.
migrate.permission_denied_blocked=Je kunt niet importeren uit niet-toegestane hosts, vraag de beheerder om de instellingen ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS te controleren.
@@ -1239,7 +1233,6 @@ issues.lock_no_reason=vergrendelde en beperkte conversatie voor medewerkers %s
issues.unlock_comment=ontgrendelde deze conversatie %s
issues.lock_confirm=Vergrendel
issues.unlock_confirm=Ontgrendelen
-issues.lock.notice_1=- Andere gebruikers kunnen geen nieuwe reacties toevoegen aan dit probleem.
issues.lock.notice_2=- U en andere medewerkers die toegang hebben tot deze repository kunnen nog steeds reacties achterlaten die anderen kunnen zien.
issues.lock.notice_3=- U kunt dit probleem in de toekomst altijd weer ontgrendelen.
issues.unlock.notice_1=- Iedereen zou nog eens commentaar op dit probleem kunnen geven.
@@ -1550,7 +1543,6 @@ activity.title.releases_1=%d Release
activity.title.releases_n=%d Releases
activity.title.releases_published_by=%s gepubliceerd door %s
activity.published_release_label=Gepubliceerd
-activity.no_git_activity=Er is in deze periode geen sprake geweest van een commit activiteit.
activity.git_stats_exclude_merges=Exclusief merges,
activity.git_stats_author_1=%d auteur
activity.git_stats_author_n=%d auteurs
diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini
index cccbe47f9db..cbdef9a04d6 100644
--- a/options/locale/locale_pl-PL.ini
+++ b/options/locale/locale_pl-PL.ini
@@ -328,7 +328,6 @@ email_domain_blacklisted=Nie możesz zarejestrować się za pomocą tego adresu
authorize_application=Autoryzuj aplikację
authorize_redirect_notice=Zostaniesz przekierowany(-a) do %s, jeśli autoryzujesz tę aplikację.
authorize_application_created_by=Ta aplikacja została stworzona przez %s.
-authorize_application_description=Jeżeli udzielisz dostępu, aplikacja uzyska dostęp z zapisem do wszystkich informacji o Twoim koncie, wraz z prywatnymi repozytoriami i organizacjami.
authorize_title=Zezwolić "%s" na dostęp do Twojego konta?
authorization_failed=Autoryzacja nie powiodła się
sspi_auth_failed=Uwierzytelnianie SSPI nie powiodło się
@@ -348,8 +347,6 @@ activate_email=Potwierdź swój adres e-mail
activate_email.text=Aby zweryfikować swój adres e-mail, w ciągu następnych %s kliknij poniższy link:
register_notify.title=%[1]s, witaj w %[2]s
-register_notify.text_1=to jest Twój e-mail z potwierdzeniem rejestracji dla %s!
-register_notify.text_2=Możesz teraz zalogować się za pomocą nazwy użytkownika: %s.
register_notify.text_3=Jeśli to konto zostało utworzone dla Ciebie, ustaw swoje hasło.
reset_password=Odzyskaj swoje konto
@@ -547,7 +544,6 @@ activate_email=Wyślij aktywację
activations_pending=Aktywacje oczekujące
delete_email=Usuń
email_deletion=Usuń adres email
-email_deletion_desc=Adres e-mail i powiązane informacje zostaną usunięte z Twojego konta. Commity za pomocą tego adresu e-mail pozostaną niezmienione. Kontynuować?
email_deletion_success=Adres e-mail został usunięty.
theme_update_success=Twój motyw został zaktualizowany.
theme_update_error=Wybrany motyw nie istnieje.
@@ -682,7 +678,6 @@ webauthn_delete_key_desc=Jeżeli usuniesz klucz bezpieczeństwa, utracisz możli
manage_account_links=Zarządzaj powiązanymi kontami
manage_account_links_desc=Te konta zewnętrzne są powiązane z Twoim kontem Gitea.
-account_links_not_available=Obecnie nie ma żadnych zewnętrznych kont powiązanych z tym kontem Gitea.
link_account=Powiąż konto
remove_account_link=Usuń powiązane konto
remove_account_link_desc=Usunięcie powiązanego konta unieważni jego dostęp do Twojego konta Gitea. Kontynuować?
@@ -1141,7 +1136,6 @@ issues.lock_no_reason=zablokowano i ograniczono konwersację do współtwórców
issues.unlock_comment=odblokowano tę konwersację %s
issues.lock_confirm=Zablokuj
issues.unlock_confirm=Odblokuj
-issues.lock.notice_1=- Inni użytkownicy nie mogą dodawać nowych komentarzy do tego zagadnienia.
issues.lock.notice_2=- Ty i inni współtwórcy z dostępem do tego repozytorium możecie dalej pozostawiać komentarze dla innych.
issues.lock.notice_3=- Możesz zawsze odblokować to zagadnienie w przyszłości.
issues.unlock.notice_1=- Wszyscy będą mogli ponownie umieszczać komentarze w tym zagadnieniu.
@@ -1405,7 +1399,6 @@ activity.title.releases_1=%d Wydanie
activity.title.releases_n=%d Wydań
activity.title.releases_published_by=%s opublikowane przez %s
activity.published_release_label=Opublikowane
-activity.no_git_activity=Nie było żadnej aktywności w tym okresie czasu.
activity.git_stats_exclude_merges=Wykluczając scalenia,
activity.git_stats_author_1=%d autor
activity.git_stats_author_n=%d autorzy
@@ -1976,7 +1969,6 @@ dashboard.resync_all_sshprincipals=Zaktualizuj plik '.ssh/authorized_keys' z klu
dashboard.resync_all_hooks=Ponownie synchronizuj hooki pre-receive, update i post-receive we wszystkich repozytoriach.
dashboard.reinit_missing_repos=Ponownie zainicjalizuj wszystkie brakujące repozytoria Git, dla których istnieją rekordy
dashboard.sync_external_users=Synchronizuj zewnętrzne dane użytkownika
-dashboard.cleanup_hook_task_table=Oczyść tabelę hook_task
dashboard.server_uptime=Uptime serwera
dashboard.current_goroutine=Bieżące Goroutines
dashboard.current_memory_usage=Bieżące użycie pamięci
@@ -2298,7 +2290,6 @@ monitor.desc=Opis
monitor.start=Czas rozpoczęcia
monitor.execute_time=Czas wykonania
monitor.process.cancel=Anuluj proces
-monitor.process.cancel_desc=Anulowanie procesu może spowodować utratę danych
monitor.queues=Kolejki
monitor.queue=Kolejka: %s
diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini
index 3f7eb73a525..2626ede6fa0 100644
--- a/options/locale/locale_pt-BR.ini
+++ b/options/locale/locale_pt-BR.ini
@@ -123,7 +123,6 @@ pin=Fixar
unpin=Desfixar
artifacts=Artefatos
-confirm_delete_artifact=Tem certeza que deseja excluir o artefato '%s' ?
archived=Arquivado
@@ -303,7 +302,6 @@ no_reply_address=Domínio de e-mail oculto
no_reply_address_helper=Nome de domínio para usuários com um endereço de e-mail oculto. Por exemplo, o nome de usuário 'joe' será registrado no Git como 'joe@noreply.example.org' se o domínio de e-mail oculto estiver definido como 'noreply.example.org'.
password_algorithm=Algoritmo Hash de Senha
invalid_password_algorithm=Algoritmo de hash de senha inválido
-password_algorithm_helper=Escolha o algoritmo de hash para as senhas. Diferentes algoritmos têm requerimentos e forças diversos. O algoritmo argon2 é bastante seguro, mas usa muita memória e pode ser inapropriado para sistemas com menos recursos.
enable_update_checker=Habilitar Verificador de Atualizações
enable_update_checker_helper=Procura por novas versões periodicamente conectando-se ao gitea.io.
env_config_keys=Configuração do ambiente
@@ -404,7 +402,6 @@ email_domain_blacklisted=Você não pode se cadastrar com seu endereço de e-mai
authorize_application=Autorizar aplicativo
authorize_redirect_notice=Você será redirecionado para %s se você autorizar este aplicativo.
authorize_application_created_by=Este aplicativo foi criado por %s.
-authorize_application_description=Se você conceder o acesso, ele será capaz de acessar e escrever em todas as informações da sua conta, incluindo repositórios privados e organizações.
authorize_title=Autorizar "%s" para acessar sua conta?
authorization_failed=Autorização falhou
authorization_failed_desc=A autorização falhou porque detectamos uma solicitação inválida. Entre em contato com o responsável do aplicativo que você tentou autorizar.
@@ -428,8 +425,6 @@ activate_email.title=%s, por favor verifique o seu endereço de e-mail
activate_email.text=Por favor clique no link a seguir para verificar o seu endereço de e-mail em %s:
register_notify.title=%[1]s, bem-vindo(a) a %[2]s
-register_notify.text_1=este é o seu e-mail de confirmação de registro para %s!
-register_notify.text_2=Agora você pode entrar com o nome de usuário: %s.
register_notify.text_3=Se esta conta foi criada para você, defina sua senha primeiro.
reset_password=Recuperar sua conta
@@ -624,7 +619,6 @@ uid=UID
public_profile=Perfil público
biography_placeholder=Conte-nos um pouco sobre você! (Você pode usar Markdown)
location_placeholder=Compartilhe sua localização aproximada com outras pessoas
-profile_desc=Controle como o seu perfil é exibido para outros usuários. Seu endereço de e-mail principal será usado para notificações, recuperação de senha e operações do Git baseadas na Web.
full_name=Nome completo
website=Site
location=Localização
@@ -697,7 +691,6 @@ activations_pending=Ativações pendentes
can_not_add_email_activations_pending=Há uma ativação pendente, tente novamente em alguns minutos se quiser adicionar um novo e-mail.
delete_email=Remover
email_deletion=Remover endereço de e-mail
-email_deletion_desc=O endereço de e-mail e informações relacionadas serão removidos de sua conta. Commits aplicados por este endereço de e-mail permanecerão inalterados. Continuar?
email_deletion_success=O endereço de e-mail foi removido.
theme_update_success=Seu tema foi atualizado.
theme_update_error=O tema selecionado não existe.
@@ -871,7 +864,6 @@ webauthn_alternative_tip=Você pode querer configurar um método de autenticaç
manage_account_links=Gerenciar contas vinculadas
manage_account_links_desc=Estas contas externas estão vinculadas a sua conta de Gitea.
-account_links_not_available=Não existem contas externas atualmente vinculadas a esta conta.
link_account=Vincular Conta
remove_account_link=Remover conta vinculada
remove_account_link_desc=A exclusão da chave SSH revogará o acesso à sua conta. Continuar?
@@ -926,7 +918,6 @@ fork_to_different_account=Faça um fork para uma conta diferente
fork_visibility_helper=A visibilidade do fork de um repositório não pode ser alterada.
fork_branch=Branch a ser clonado para o fork
all_branches=Todos os branches
-fork_no_valid_owners=Não é possível fazer um fork desse repositório porque não há proprietários validos.
use_template=Usar este modelo
download_zip=Baixar ZIP
download_tar=Baixar TAR.GZ
@@ -963,7 +954,6 @@ mirror_sync=sincronizado
mirror_sync_on_commit=Sincronizar quando commits forem enviados
mirror_address=Clonar de URL
mirror_address_desc=Coloque todas as credenciais necessárias na seção de autorização.
-mirror_address_url_invalid=O URL fornecido é inválido. Você deve escapar todos os componentes do URL corretamente.
mirror_address_protocol_invalid=O URL fornecido é inválido. Somente locais http(s):// ou git:// podem ser usados para espelhamento.
mirror_lfs=Armazenamento de Arquivo Grande (LFS)
mirror_lfs_desc=Ativar espelhamento de dados LFS.
@@ -1015,8 +1005,6 @@ template.issue_labels=Etiquetas de issue
template.one_item=Deve-se selecionar pelo menos um item de modelo
template.invalid=Deve-se selecionar um repositório de modelo
-archive.title=Este repositório está arquivado. Você pode visualizar arquivos e cloná-lo, mas não pode fazer push, abrir issues ou pull requests.
-archive.title_date=Este repositório foi arquivado em %s. Você pode visualizar arquivos e cloná-lo, mas não pode fazer push, abrir issues ou pull requests.
archive.issue.nocomment=Este repositório está arquivado. Você não pode comentar nas issues.
archive.pull.nocomment=Este repositório está arquivado. Você não pode comentar nos pull requests.
@@ -1045,7 +1033,6 @@ migrate_items_releases=Versões
migrate_repo=Migrar repositório
migrate.clone_address=Migrar / Clonar de URL
migrate.clone_address_desc=URL HTTP (S) ou Git 'clone' de um repositório existente
-migrate.github_token_desc=Você pode colocar aqui um ou mais tokens separados por vírgulas para tornar a migração mais rápida para compensar o limite de taxa de API do GitHub. AVISO: abusar desse recurso pode violar a política do provedor de serviços e levar ao bloqueio da conta.
migrate.clone_local_path=ou um caminho de servidor local
migrate.permission_denied=Você não pode importar repositórios locais.
migrate.permission_denied_blocked=Você não pode importar dos hosts não permitidos, por favor peça ao administrador para verificar as configurações ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS.
@@ -1498,7 +1485,6 @@ issues.lock_no_reason=bloqueada e conversação limitada para colaboradores %s
issues.unlock_comment=desbloqueada esta conversação %s
issues.lock_confirm=Bloquear
issues.unlock_confirm=Desbloquear
-issues.lock.notice_1=- Outros usuários não poderão adicionar novos comentários nesta issue.
issues.lock.notice_2=- Você e outros colaboradores com acesso a este repositório ainda podem deixar comentários que outros podem ver.
issues.lock.notice_3=- Você pode sempre desbloquear esta issue novamente no futuro.
issues.unlock.notice_1=- Todos poderão comentar mais uma vez nesta issue.
@@ -1536,7 +1522,6 @@ issues.due_date_form=dd/mm/aaaa
issues.due_date_form_add=Adicionar data limite
issues.due_date_form_edit=Editar
issues.due_date_form_remove=Remover
-issues.due_date_not_writer=Você precisa de acesso de gravação a esse repositório para atualizar a data limite de uma issue.
issues.due_date_not_set=Data limite não informada.
issues.due_date_added=adicionou a data limite %s %s
issues.due_date_modified=modificou a data limite de %[2]s para %[1]s %[3]s
@@ -1786,7 +1771,6 @@ milestones.filter_sort.most_issues=Com mais issues
milestones.filter_sort.least_issues=Com menos issues
signing.will_sign=Esse commit será assinado com a chave "%s".
-signing.wont_sign.error=Ocorreu um erro ao verificar se o commit poderia ser assinado.
signing.wont_sign.nokey=Não há nenhuma chave disponível para assinar esse commit.
signing.wont_sign.never=Commits nunca são assinados.
signing.wont_sign.always=Commits são sempre assinados.
@@ -1874,7 +1858,6 @@ activity.title.releases_1=%d Versão
activity.title.releases_n=%d Versões
activity.title.releases_published_by=%s publicada(s) por %s
activity.published_release_label=Publicado
-activity.no_git_activity=Não houve nenhuma atividade de commit neste período.
activity.git_stats_exclude_merges=Excluindo merges,
activity.git_stats_author_1=%d autor
activity.git_stats_author_n=%d autores
@@ -2593,8 +2576,6 @@ dashboard.resync_all_sshprincipals=Atualizar o arquivo '.ssh/authorized_principa
dashboard.resync_all_hooks=Ressincronizar hooks pre-receive, update e post-receive de todos os repositórios.
dashboard.reinit_missing_repos=Reinicializar todos os repositórios Git perdidos cujos registros existem
dashboard.sync_external_users=Sincronizar dados de usuário externo
-dashboard.cleanup_hook_task_table=Limpar tabela hook_task
-dashboard.cleanup_packages=Limpar pacotes expirados
dashboard.server_uptime=Tempo de atividade do Servidor
dashboard.current_goroutine=Goroutines Atuais
dashboard.current_memory_usage=Uso de memória atual
@@ -3233,7 +3214,6 @@ owner.settings.cargo.initialize.error=Falha ao inicializar índice Cargo: %v
owner.settings.cargo.initialize.success=O índice Cargo foi criado com sucesso.
owner.settings.cargo.rebuild=Reconstruir Índice
owner.settings.cargo.rebuild.error=Falha ao reconstruir índice Cargo: %v
-owner.settings.cargo.rebuild.success=O índice Cargo foi reconstruído com sucesso.
owner.settings.cleanuprules.title=Gerenciar Regras de Limpeza
owner.settings.cleanuprules.add=Adicionar Regra de Limpeza
owner.settings.cleanuprules.edit=Editar Regra de Limpeza
@@ -3314,7 +3294,6 @@ runners.delete_runner=Deletar esse runner
runners.delete_runner_success=Runner excluído com sucesso
runners.delete_runner_failed=Falha ao excluir runner
runners.delete_runner_header=Confirme para excluir este runner
-runners.delete_runner_notice=Se uma tarefa estiver sendo executada neste runner, ela será encerrada e marcada como falha. Pode quebrar o workflow de construção.
runners.none=Nenhum runner disponível
runners.status.unspecified=Desconhecido
runners.status.idle=Inativo
diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini
index f10bef0687a..c5dd56e40a1 100644
--- a/options/locale/locale_pt-PT.ini
+++ b/options/locale/locale_pt-PT.ini
@@ -358,7 +358,7 @@ no_reply_address=Domínio dos emails ocultos
no_reply_address_helper=Nome de domínio para utilizadores com um endereço de email oculto. Por exemplo, o nome de utilizador 'silva' será registado no Git como 'silva@semresposta.exemplo.org' se o domínio de email oculto estiver definido como 'semresposta.exemplo.org'.
password_algorithm=Algoritmo de Hash da Senha
invalid_password_algorithm=Algoritmo de hash da senha inválido
-password_algorithm_helper=Definir o algoritmo de hash da senha. Os algoritmos têm requisitos e resistência distintos. `argon2` é bastante seguro, mas usa muita memória e pode ser inapropriado para sistemas pequenos.
+password_algorithm_helper=Definir o algoritmo de hash da senha. Os algoritmos têm requisitos e resistências distintos. `argon2` é bastante seguro, mas usa muita memória e pode ser inapropriado para sistemas pequenos.
enable_update_checker=Habilitar verificador de novidades
enable_update_checker_helper=Verifica, periodicamente, se foi lançada alguma versão nova, fazendo uma ligação ao gitea.io.
env_config_keys=Configuração do ambiente
@@ -477,7 +477,7 @@ email_domain_blacklisted=Não pode fazer um registo com o seu endereço de email
authorize_application=Autorizar aplicação
authorize_redirect_notice=Irá ser reencaminhado para %s se autorizar esta aplicação.
authorize_application_created_by=Esta aplicação foi criada por %s.
-authorize_application_description=Se conceder acesso, a aplicação terá privilégios para alterar toda a informação da conta, incluindo repositórios e organizações privados.
+authorize_application_description=Se conceder o acesso, a aplicação terá privilégios para alterar toda a informação da conta, incluindo repositórios e organizações privados.
authorize_application_with_scopes=Com âmbitos: %s
authorize_title=Autorizar o acesso de "%s" à sua conta?
authorization_failed=A autorização falhou
@@ -506,7 +506,7 @@ activate_email.text=Por favor clique na seguinte ligação para validar o seu en
register_notify=Bem-vindo(a) a %s
register_notify.title=%[1]s, bem-vindo(a) a %[2]s
-register_notify.text_1=este é o seu email de confirmação de registo para %s!
+register_notify.text_1=Este é o seu email de confirmação de registo para %s!
register_notify.text_2=Agora pode iniciar a sessão com o nome de utilizador: %s.
register_notify.text_3=Se esta conta foi criada para si, defina a sua senha primeiro.
@@ -689,7 +689,7 @@ form.name_chars_not_allowed=O nome de utilizador "%s" contém caracteres inváli
block.block=Bloquear
block.block.user=Bloquear utilizador
-block.block.org=Bloquear utilizador para a organização
+block.block.org=Bloquear utilizador da organização
block.block.failure=Falhou o bloqueio do utilizador: %s
block.unblock=Desbloquear
block.unblock.failure=Falhou o desbloqueio do utilizador: %s
@@ -812,7 +812,7 @@ activations_pending=Habilitações pendentes
can_not_add_email_activations_pending=Existe uma validação pendente. Tente de novo dentro de alguns minutos, se quiser adicionar um novo email.
delete_email=Remover
email_deletion=Remover endereço de email
-email_deletion_desc=O endereço de email e informações relacionadas serão removidos da sua conta. Os cometimentos feitos no Git com este endereço de email permanecerão inalterados. Quer continuar?
+email_deletion_desc=Este endereço de email e informações relacionadas serão removidos da sua conta. Os cometimentos feitos no Git com este endereço de email permanecerão inalterados. Quer continuar?
email_deletion_success=O endereço de email foi removido.
theme_update_success=O seu tema foi substituído.
theme_update_error=O tema escolhido não existe.
@@ -1021,6 +1021,8 @@ email_notifications.onmention=Enviar email somente quando mencionado(a)
email_notifications.disable=Desabilitar notificações por email
email_notifications.submit=Definir preferência do email
email_notifications.andyourown=e as suas próprias notificações
+email_notifications.actions.desc=Notificações para sequências de trabalho são executadas em repositórios configurados com Gitea Actions.
+email_notifications.actions.failure_only=Notificar apenas as execuções de sequências de trabalho falhadas
visibility=Visibilidade do utilizador
visibility.public=Pública
@@ -1102,7 +1104,7 @@ mirror_sync=sincronizado
mirror_sync_on_commit=Sincronizar quando forem enviados cometimentos
mirror_address=Clonar a partir do URL
mirror_address_desc=Coloque, na secção de autorização, as credenciais que, eventualmente, sejam necessárias.
-mirror_address_url_invalid=O URL fornecido é inválido. Tem que codificar adequadamente todos os componentes do URL.
+mirror_address_url_invalid=O URL fornecido é inválido. Certifique-se que codifica adequadamente todos os componentes do URL.
mirror_address_protocol_invalid=O URL fornecido é inválido. Só se pode replicar a partir de endereços http(s):// ou git://.
mirror_lfs=Armazenamento de Ficheiros Grandes (LFS)
mirror_lfs_desc=Habilitar a réplica de dados LFS.
@@ -1162,8 +1164,8 @@ template.issue_labels=Rótulos das questões
template.one_item=Tem que escolher pelo menos um item do modelo
template.invalid=Tem que escolher um repositório modelo
-archive.title=Este repositório está arquivado. Pode ver os seus ficheiros e cloná-lo, mas não pode fazer envios para o repositório nem lançar questões ou fazer pedidos de integração.
-archive.title_date=Este repositório foi arquivado em %s. Pode ver os ficheiros e cloná-lo, mas não pode fazer envios ou abrir questões ou pedidos de integração.
+archive.title=Este repositório está arquivado. Pode ver os seus ficheiros e cloná-lo. Não pode lançar questões, fazer pedidos de integração nem fazer envios.
+archive.title_date=Este repositório foi arquivado em %s. Pode ver os ficheiros e cloná-lo. Não pode abrir questões, fazer pedidos de integração nem enviar cometimentos.
archive.issue.nocomment=Este repositório está arquivado. Não pode comentar nas questões.
archive.pull.nocomment=Este repositório está arquivado. Não pode comentar nos pedidos de integração.
@@ -1192,7 +1194,7 @@ migrate_items_releases=Lançamentos
migrate_repo=Migrar o repositório
migrate.clone_address=Migrar / clonar a partir do URL
migrate.clone_address_desc=O URL de clonagem HTTP(S) ou Git de um repositório existente
-migrate.github_token_desc=Pode colocar aqui um ou mais códigos separados por vírgulas para tornar mais rápida a migração, para compensar a limitação de velocidade da API do GitHub. AVISO: O abuso desta funcionalidade poderá violar a política do seu fornecedor de serviço e levar ao bloqueio da conta.
+migrate.github_token_desc=Pode colocar aqui um ou mais códigos separados por vírgulas para tornar mais rápida a migração, para compensar a limitação de velocidade da API do GitHub. AVISO: O abuso desta funcionalidade poderá violar a política do seu fornecedor de serviço e levar ao bloqueio da(s) sua(a) conta(s).
migrate.clone_local_path=ou uma localização no servidor local
migrate.permission_denied=Não está autorizado a importar repositórios locais.
migrate.permission_denied_blocked=Não pode importar de servidores não permitidos, por favor peça ao administrador para verificar as configurações ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS.
@@ -1700,7 +1702,7 @@ issues.lock_no_reason=bloqueou o diálogo e restringiu-o aos colaboradores %s
issues.unlock_comment=desbloqueou este diálogo %s
issues.lock_confirm=Bloquear
issues.unlock_confirm=Desbloquear
-issues.lock.notice_1=- Os outros utilizadores deixarão de poder adicionar novos comentários a esta questão.
+issues.lock.notice_1=- Os outros utilizadores não podem adicionar novos comentários a esta questão.
issues.lock.notice_2=- Você e outros colaboradores com acesso a este repositório ainda poderão deixar comentários que outros possam ver.
issues.lock.notice_3=- Poderá sempre voltar a desbloquear esta questão no futuro.
issues.unlock.notice_1=- Toda gente poderá voltar a comentar nesta questão.
@@ -1869,7 +1871,7 @@ pulls.select_commit_hold_shift_for_range=Escolha o comentimento. Mantenha premid
pulls.review_only_possible_for_full_diff=A revisão só é possível ao visualizar o diff completo
pulls.filter_changes_by_commit=Filtrar por cometimento
pulls.nothing_to_compare=Estes ramos são iguais. Não há necessidade de criar um pedido de integração.
-pulls.nothing_to_compare_have_tag=O ramo/etiqueta escolhidos são iguais.
+pulls.nothing_to_compare_have_tag=Os ramos/etiquetas escolhidos são iguais.
pulls.nothing_to_compare_and_allow_empty_pr=Estes ramos são iguais. Este pedido de integração ficará vazio.
pulls.has_pull_request=`Já existe um pedido de integração entre estes ramos: %[2]s#%[3]d`
pulls.create=Criar um pedido de integração
@@ -2334,6 +2336,8 @@ settings.hooks_desc=Os automatismos web fazem pedidos HTTP POST automaticamente
settings.webhook_deletion=Remover automatismo web
settings.webhook_deletion_desc=Remover um automatismo web elimina as configurações e o histórico de entrega desse automatismo. Quer continuar?
settings.webhook_deletion_success=O automatismo web foi removido.
+settings.webhook.test_delivery=Testar o envio
+settings.webhook.test_delivery_desc=Testar este automatismo web com um evento de envio falso.
settings.webhook.test_delivery_desc_disabled=Para testar este automatismo web com um evento falso, habilite-o.
settings.webhook.request=Pedido
settings.webhook.response=Resposta
@@ -2539,7 +2543,7 @@ settings.block_on_official_review_requests_desc=A integração não será possí
settings.block_outdated_branch=Bloquear integração se o pedido de integração for obsoleto
settings.block_outdated_branch_desc=A integração não será possível quando o ramo de topo estiver abaixo do ramo base.
settings.block_admin_merge_override=Os administradores têm de cumprir as regras de salvaguarda dos ramos
-settings.block_admin_merge_override_desc=Os administradores têm de cumprir as regras de salvaguarda e não as podem contornar.
+settings.block_admin_merge_override_desc=Os administradores têm de cumprir as regras de salvaguarda do ramo e não as podem contornar.
settings.default_branch_desc=Escolha um ramo do repositório como sendo o predefinido para pedidos de integração e cometimentos:
settings.merge_style_desc=Estilos de integração
settings.default_merge_style_desc=Tipo de integração predefinido
@@ -2566,10 +2570,10 @@ settings.matrix.homeserver_url=URL do servidor caseiro
settings.matrix.room_id=ID da sala
settings.matrix.message_type=Tipo de mensagem
settings.visibility.private.button=Tornar privado
-settings.visibility.private.text=Mudar a visibilidade para privado não só irá tornar o repositório visível somente para membros autorizados como também poderá remover a relação entre o repositório e derivações, vigilâncias e favoritos.
+settings.visibility.private.text=Mudar a visibilidade para privado irá tornar o repositório visível somente para membros autorizados e poderá remover a relação entre o repositório e derivações existentes, vigilâncias e favoritos.
settings.visibility.private.bullet_title=Mudar a visibilidade para privado irá:
settings.visibility.private.bullet_one=Tornar o repositório visível somente para membros autorizados.
-settings.visibility.private.bullet_two=Possivelmente remover a relação entre o repositório e derivações, vigilâncias e favoritos.
+settings.visibility.private.bullet_two=Poderá remover a relação entre o repositório e derivações, vigilâncias e favoritos.
settings.visibility.public.button=Tornar público
settings.visibility.public.text=Mudar a visibilidade para público irá tornar o repositório visível para qualquer pessoa.
settings.visibility.public.bullet_title=Mudar a visibilidade para público irá:
@@ -3016,7 +3020,7 @@ dashboard.resync_all_sshprincipals=Modificar o ficheiro '.ssh/authorized_princip
dashboard.resync_all_hooks=Voltar a sincronizar automatismos de pré-acolhimento, modificação e pós-acolhimento de todos os repositórios.
dashboard.reinit_missing_repos=Reinicializar todos os repositórios Git em falta para os quais existam registos
dashboard.sync_external_users=Sincronizar dados externos do utilizador
-dashboard.cleanup_hook_task_table=Limpar tabela hook_task
+dashboard.cleanup_hook_task_table=Limpar a tabela hook_task
dashboard.cleanup_packages=Limpar pacotes expirados
dashboard.cleanup_actions=Limpar recursos das operações expirados
dashboard.server_uptime=Tempo em funcionamento contínuo do servidor
@@ -3249,6 +3253,8 @@ auths.oauth2_required_claim_name_helper=Defina este nome para restringir o iníc
auths.oauth2_required_claim_value=Valor de Reivindicação obrigatório
auths.oauth2_required_claim_value_helper=Defina este valor para restringir o início de sessão desta fonte a utilizadores que tenham uma reivindicação com este nome e este valor
auths.oauth2_group_claim_name=Reivindicar nome que fornece nomes de grupo para esta fonte. (Opcional)
+auths.oauth2_full_name_claim_name=Nome completo reivindicado (opcional; se for definido, o nome completo do utilizador será sempre sincronizado com este reivindicado).
+auths.oauth2_ssh_public_key_claim_name=Nome reivindicado da chave pública SSH
auths.oauth2_admin_group=Valor da Reivindicação de Grupo para utilizadores administradores. (Opcional - exige a reivindicação de nome acima)
auths.oauth2_restricted_group=Valor da Reivindicação de Grupo para utilizadores restritos. (Opcional - exige a reivindicação de nome acima)
auths.oauth2_map_group_to_team=Mapear grupos reclamados em equipas da organização (opcional — requer nome de reclamação acima).
diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini
index bfaf7143bd8..d74aeb109cb 100644
--- a/options/locale/locale_ru-RU.ini
+++ b/options/locale/locale_ru-RU.ini
@@ -301,7 +301,6 @@ no_reply_address=Скрытый почтовый домен
no_reply_address_helper=Доменное имя для пользователей со скрытым адресом электронной почты. Например, имя пользователя 'joe' будет зарегистрировано в Git как 'joe@noreply.example.org' если скрытый домен электронной почты установлен как 'noreply.example.org'.
password_algorithm=Алгоритм хеширования пароля
invalid_password_algorithm=Некорректный алгоритм хеширования пароля
-password_algorithm_helper=Задайте алгоритм хеширования паролей. Алгоритмы имеют различные требования и стойкость. Алгоритм argon2 довольно безопасен, но он использует много памяти и может не подходить для слабых систем.
enable_update_checker=Включить проверку обновлений
enable_update_checker_helper=Периодически проверяет наличие новых версий, подключаясь к gitea.io.
env_config_keys=Настройка окружения
@@ -402,7 +401,6 @@ email_domain_blacklisted=С данным адресом электронной
authorize_application=Авторизация приложения
authorize_redirect_notice=Вы будете перенаправлены на %s, если вы авторизуете это приложение.
authorize_application_created_by=Это приложение было создано %s.
-authorize_application_description=Если вы предоставите доступ, оно сможет получить доступ и редактировать любую информацию о вашей учётной записи, включая содержимое частных репозиториев и организаций.
authorize_title=Разрешить «%s» доступ к вашей учётной записи?
authorization_failed=Ошибка авторизации
authorization_failed_desc=Ошибка авторизации, обнаружен неверный запрос. Пожалуйста, свяжитесь с автором приложения, которое вы пытались авторизовать.
@@ -425,8 +423,6 @@ activate_email.title=%s, пожалуйста, подтвердите ваш а
activate_email.text=Пожалуйста, перейдите по ссылке, чтобы подтвердить ваш адрес электронной почты в течение %s:
register_notify.title=%[1]s, добро пожаловать в %[2]s
-register_notify.text_1=это письмо с вашим подтверждением регистрации в %s!
-register_notify.text_2=Теперь вы можете войти через логин: %s.
register_notify.text_3=Если эта учётная запись была создана для вас, пожалуйста, сначала установите пароль.
reset_password=Восстановить учётную запись
@@ -620,7 +616,6 @@ uid=UID
public_profile=Открытый профиль
biography_placeholder=Расскажите немного о себе! (Можно использовать Markdown)
location_placeholder=Поделитесь своим приблизительным местоположением с другими
-profile_desc=Контролируйте, как ваш профиль будет отображаться другим пользователям. Ваш основной адрес электронной почты будет использоваться для уведомлений, восстановления пароля и веб-операций Git.
full_name=Имя и фамилия
website=Веб-сайт
location=Местоположение
@@ -693,7 +688,6 @@ activations_pending=Ожидает активации
can_not_add_email_activations_pending=Ожидается активация. Если хотите добавить новый почтовый ящик, попробуйте еще раз через несколько минут.
delete_email=Удалить
email_deletion=Удалить адрес электронной почты
-email_deletion_desc=Адрес электронной почты и вся связанная с ним информация будет удалена из вашего аккаунта. Коммиты, сделанные от имени этого адреса электронной почты, не будут изменены. Продолжить?
email_deletion_success=Ваш адрес электронной почты был удалён.
theme_update_success=Тема была изменена.
theme_update_error=Выбранная тема не существует.
@@ -864,7 +858,6 @@ webauthn_key_loss_warning=В случае утраты ключей безопа
manage_account_links=Управление привязанными аккаунтами
manage_account_links_desc=Эти внешние аккаунты привязаны к вашему аккаунту Gitea.
-account_links_not_available=В настоящее время нет внешних аккаунтов, привязанных к вашему аккаунту Gitea.
link_account=Привязать аккаунт
remove_account_link=Удалить привязанный аккаунт
remove_account_link_desc=Удаление привязанной учётной записи отменит её доступ к вашей учётной записи Gitea. Продолжить?
@@ -1026,7 +1019,6 @@ migrate_items_releases=Релизы
migrate_repo=Перенос репозитория
migrate.clone_address=Перенос / Клонирование по URL
migrate.clone_address_desc=Это может быть HTTP/HTTPS/GIT адрес или локальный путь существующего репозитория на сервере.
-migrate.github_token_desc=Вы можете поместить один или несколько токенов, разделенных запятыми, чтобы сделать миграцию быстрее из-за ограничения скорости GitHub API. ПРЕДУПРЕЖДЕНИЕ: Злоупотребление этой функцией может нарушить политику поставщика услуг и привести к блокировке аккаунта.
migrate.clone_local_path=или локальный путь на сервере
migrate.permission_denied=У вас нет прав на импорт локальных репозиториев.
migrate.permission_denied_blocked=Вы не можете импортировать с запрещённых хостов, пожалуйста, попросите администратора проверить настройки ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS.
@@ -1476,7 +1468,6 @@ issues.lock_no_reason=ограничил(а) обсуждение задачи
issues.unlock_comment=снял(а) ограничение %s
issues.lock_confirm=Ограничить
issues.unlock_confirm=Снять
-issues.lock.notice_1=- Другие пользователи не могут добавлять новые комментарии к этой задаче.
issues.lock.notice_2=- Вы и другие соавторы с доступом к этому репозиторию могут оставлять комментарии, которые могут видеть другие.
issues.lock.notice_3=- Вы всегда можете снять ограничение с обсуждения этой задачи.
issues.unlock.notice_1=- Все снова смогут принять участие в обсуждении данной задачи.
@@ -1836,7 +1827,6 @@ activity.title.releases_1=%d релиз
activity.title.releases_n=%d релизов
activity.title.releases_published_by=%s опубликованы %s
activity.published_release_label=Опубликовано
-activity.no_git_activity=В этот период не было новых коммитов.
activity.git_stats_exclude_merges=За исключением слияний,
activity.git_stats_author_1=%d автор
activity.git_stats_author_n=%d автора(ов)
@@ -2581,8 +2571,6 @@ dashboard.resync_all_sshprincipals=Обновите файл '.ssh/authorized_pr
dashboard.resync_all_hooks=Повторная синхронизация hook'ов pre-receive, update и post-receive во всех репозиториях.
dashboard.reinit_missing_repos=Переинициализировать все отсутствующие Git репозитории, для которых существуют записи
dashboard.sync_external_users=Синхронизировать данные внешних пользователей
-dashboard.cleanup_hook_task_table=Очистить таблицу hook_task
-dashboard.cleanup_packages=Очистка устаревших пакетов
dashboard.server_uptime=Время непрерывной работы сервера
dashboard.current_goroutine=Текущее количество Goroutines
dashboard.current_memory_usage=Текущее использование памяти
@@ -3229,7 +3217,6 @@ owner.settings.cargo.initialize.error=Не удалось инициализир
owner.settings.cargo.initialize.success=Индекс Cargo успешно создан.
owner.settings.cargo.rebuild=Перестроить индекс
owner.settings.cargo.rebuild.error=Не удалось перестроить индекс Cargo: %v
-owner.settings.cargo.rebuild.success=Индекс Cargo успешно перестроен.
owner.settings.cleanuprules.title=Управление правилами очистки
owner.settings.cleanuprules.add=Добавить правило очистки
owner.settings.cleanuprules.edit=Изменить правило очистки
@@ -3310,7 +3297,6 @@ runners.delete_runner=Удалить этот раннер
runners.delete_runner_success=Раннер успешно удалён
runners.delete_runner_failed=Не удалось удалить раннер
runners.delete_runner_header=Подтвердите удаление раннера
-runners.delete_runner_notice=Если на этом раннере выполняется задание, оно будет завершено и помечено как неудачное. Это может нарушить рабочий поток сборки.
runners.none=Нет доступных раннеров
runners.status.unspecified=Неизвестно
runners.status.idle=Простаивает
diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini
index 6a15dae3f22..d76ced91062 100644
--- a/options/locale/locale_si-LK.ini
+++ b/options/locale/locale_si-LK.ini
@@ -302,7 +302,6 @@ email_domain_blacklisted=ඔබට ඔබගේ විද්යුත් තැ
authorize_application=අයදුම්පත සඳහා බලය පැවරීම
authorize_redirect_notice=ඔබ මෙම යෙදුමට බලය පවරන්නේ නම් ඔබව %s වෙත හරවා යවනු ලැබේ.
authorize_application_created_by=මෙම යෙදුම %sවිසින් නිර්මාණය කරන ලදී.
-authorize_application_description=ඔබ ප්රවේශය ලබා දෙන්නේ නම්, පුද්ගලික රිපෝස් සහ සංවිධාන ඇතුළු ඔබගේ ගිණුම් තොරතුරු වෙත ප්රවේශ වීමට සහ ලිවීමට හැකි වනු ඇත.
authorize_title=ඔබගේ ගිණුමට ප්රවේශ වීමට "%s" බලය පවරන්නද?
authorization_failed=බලය පැවරීම අසාර්ථකයි
sspi_auth_failed=SSPI සත්යාපන අසමත් විය
@@ -322,8 +321,6 @@ activate_email=ඔබගේ විද්යුත් තැපැල් ලි
activate_email.text=තුළ ඔබගේ විද්යුත් තැපැල් ලිපිනය සත්යාපනය කිරීමට පහත සබැඳිය ක්ලික් කරන්න %s:
register_notify.title=%[1]s, %[2]s වෙත සාදරයෙන් පිළිගනිමු
-register_notify.text_1=මෙය %sසඳහා ඔබගේ ලියාපදිංචි තහවුරු කිරීමේ විද්යුත් තැපෑලයි!
-register_notify.text_2=ඔබට දැන් පරිශීලක නාමය හරහා පිවිසිය හැකිය: %s.
register_notify.text_3=මෙම ගිණුම ඔබ වෙනුවෙන් නිර්මාණය කර තිබේ නම්, කරුණාකර ඔබගේ මුරපදය පළමු සකසන්න.
reset_password=ඔබගේ ගිණුම ප්රතිසාධනය
@@ -530,7 +527,6 @@ activate_email=සක්රිය යවන්න
activations_pending=අවශ්ය ක්රියාකාරකම්
delete_email=ඉවත් කරන්න
email_deletion=වි-තැපෑල ඉවත් කරන්න
-email_deletion_desc=විද්යුත් තැපැල් ලිපිනය සහ අදාළ තොරතුරු ඔබගේ ගිණුමෙන් ඉවත් කරනු ලැබේ. මෙම විද්යුත් තැපැල් ලිපිනය මගින් Git විවරණය නොවෙනස්ව පවතිනු ඇත. දිගටම?
email_deletion_success=විද්යුත් තැපැල් ලිපිනය ඉවත් කර ඇත.
theme_update_success=ඔබගේ තේමාව යාවත්කාල කෙරිණි.
theme_update_error=තෝරාගත් තේමාව නොපවතී.
@@ -664,7 +660,6 @@ twofa_failed_get_secret=රහස්ය වීමට අසමත් විය.
manage_account_links=සම්බන්ධිත ගිණුම් කළමනාකරණය කරන්න
manage_account_links_desc=මෙම බාහිර ගිණුම් ඔබගේ Gitea ගිණුමට සම්බන්ධ කර ඇත.
-account_links_not_available=දැනට ඔබගේ Gitea ගිණුමට සම්බන්ධ බාහිර ගිණුම් නොමැත.
link_account=ගිණුම සබැඳින්න
remove_account_link=සම්බන්ධිත ගිණුම ඉවත් කරන්න
remove_account_link_desc=සම්බන්ධිත ගිණුමක් ඉවත් කිරීම ඔබගේ Gitea ගිණුමට එහි ප්රවේශය අවලංගු කරනු ඇත. දිගටම?
@@ -1117,7 +1112,6 @@ issues.lock_no_reason=සහයෝගීතාකරුවන්ට අගුළ
issues.unlock_comment=මෙම සංවාදය අගුළු දැමීය %s
issues.lock_confirm=අගුළු ලන්න
issues.unlock_confirm=අගුළු හරින්න
-issues.lock.notice_1=- වෙනත් පරිශීලකයින්ට මෙම ගැටළුව සඳහා නව අදහස් එකතු කළ නොහැක.
issues.lock.notice_2=- මෙම ගබඩාවට ප්රවේශය ඇති ඔබට සහ වෙනත් සහයෝගීකයින්ට තවමත් අන් අයට දැකිය හැකි අදහස් දැක්විය හැකිය.
issues.lock.notice_3=- අනාගතයේදී ඔබට මෙම ගැටළුව නැවත විවෘත කළ හැකිය.
issues.unlock.notice_1=- සෑම කෙනෙකුටම මෙම ගැටලුව ගැන අදහස් දැක්වීමට හැකි වනු ඇත.
@@ -1401,7 +1395,6 @@ activity.title.releases_1=නිකුතු %d
activity.title.releases_n=නිකුතු %d
activity.title.releases_published_by=%s විසින් ප්රකාශයට පත් කර %s
activity.published_release_label=ප්රකාශයට පත්
-activity.no_git_activity=මෙම කාලය තුළ කිසිදු කැපවීමක් සිදු වී නොමැත.
activity.git_stats_exclude_merges=ඒකාබද්ධ කිරීම හැර,
activity.git_stats_author_1=%d කර්තෘ
activity.git_stats_author_n=%d කතුවරුන්
@@ -1998,7 +1991,6 @@ dashboard.resync_all_sshprincipals=Gitea SSH විදුහල්පතිව
dashboard.resync_all_hooks=පෙර ලැබීමට, යාවත්කාලීන කිරීමට සහ සියලු ගබඩාවන් නැවත ලබා ගැනීමට කොකු නැවත සකස් කරන්න.
dashboard.reinit_missing_repos=අතුරුදහන් වූ සියලුම ගිට් නිධි නැවත ආරම්භ කිරීම
dashboard.sync_external_users=බාහිර පරිශීලක දත්ත සමමුහූර්තනය
-dashboard.cleanup_hook_task_table=පිරිසිදු hook_task වගුව
dashboard.server_uptime=සේවාදායකය යාවත්කාලීන කිරීම
dashboard.current_goroutine=වත්මන් ගෝර්අවුට්ලයින්
dashboard.current_memory_usage=වත්මන් මතක භාවිතය
diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini
index 61afb9546f7..03139b8eabf 100644
--- a/options/locale/locale_sk-SK.ini
+++ b/options/locale/locale_sk-SK.ini
@@ -298,7 +298,6 @@ no_reply_address=Skrytá e-mailová doména
no_reply_address_helper=Doménové meno pre používateľov so skrytou e-mailovou adresou. Napríklad, používateľ s menom 'joe' bude zalogovaný v Git-e ako 'joe@noreply.example.org' ak je skrytá e-mailová doména nastavená na 'noreply.example.org'.
password_algorithm=Hašovací algoritmus hesla
invalid_password_algorithm=Neplatný hash algoritmus hesla
-password_algorithm_helper=Nastavte algoritmus hashovania hesla. Algoritmy majú rôzne požiadavky a silu. Algoritmus argon2 je pomerne bezpečný, ale využíva veľa pamäte a môže byť nevhodný pre malé systémy.
enable_update_checker=Povoliť kontrolu aktualizácií
enable_update_checker_helper=Pravidelne kontroluje nové verzie pripojením k gitea.io.
@@ -390,7 +389,6 @@ email_domain_blacklisted=Nemôžete sa zaregistrovať s vašou e-mailovou adreso
authorize_application=Autorizovať aplikáciu
authorize_redirect_notice=Ak autorizujete túto aplikáciu, budete presmerovaní na %s.
authorize_application_created_by=Túto aplikáciu vytvoril %s.
-authorize_application_description=Ak udelíte prístup, bude možné pristupovať a zapisovať do všetkých vašich informácií o účte, vrátane súkromných repozitárov a organizácií.
authorize_title=Autorizovať „%s“ pre prístup k vášmu účtu?
authorization_failed=Autorizácia zlyhala
sspi_auth_failed=SSPI overenie zlyhalo
@@ -411,8 +409,6 @@ activate_email=Overte svoju e-mailovú adresu
activate_email.text=Pre overenie vašej e-mailovej adresy kliknite, prosím, na nasledovný odkaz do %s:
register_notify.title=%[1]s, vitajte v %[2]s
-register_notify.text_1=toto je e-mail potvrdzujúci vašu registráciu pre %s!
-register_notify.text_2=Teraz sa môžete prihlásiť s používateľským menom: %s.
register_notify.text_3=Ak bol tento účet vytvorený pre vás, nastavte prosím najskôr svoje heslo.
reset_password=Obnoviť váš účet
@@ -645,7 +641,6 @@ activate_email=Poslať aktiváciu
activations_pending=Čakajúca aktivácia
delete_email=Odstrániť
email_deletion=Vymazať e-mailovú adresu
-email_deletion_desc=E-mailová adresa a pridružené informácie budú z vášho účtu odstránené. Commity Gitu s touto e-mailovou adresou zostanú nezmenené. Pokračovať?
email_deletion_success=E-mailová adresa bola odstránená.
theme_update_success=Vaša téma bola aktualizovaná.
theme_update_error=Vybraná téma vzhľadu neexistuje.
@@ -788,7 +783,6 @@ webauthn_delete_key_desc=Ak odstránite bezpečnostný kľúč, už sa s ním ne
manage_account_links=Spravovať prepojené kontá
manage_account_links_desc=Tieto externé účty sú prepojené s vaším účtom Gitea.
-account_links_not_available=V súčasnosti nie sú s vaším účtom Gitea prepojené žiadne externé účty.
link_account=Pripojiť účet
remove_account_link=Odstrániť prepojený účet
remove_account_link_desc=Odstránenie prepojeného účtu zruší jeho prístup k vášmu účtu Gitea. Pokračovať?
@@ -916,7 +910,6 @@ migrate_items_labels=Štítky
migrate_items_pullrequests=Pull requesty
migrate_repo=Migrovať repozitár
migrate.clone_address_desc=HTTP(S) alebo Git 'clone' URL pre klonovanie existujúceho repozitára
-migrate.github_token_desc=Sem môžete vložiť jeden alebo viac tokenov oddelených čiarkami, aby sa migrácia zrýchlila z dôvodu limitu rýchlosti rozhrania GitHub API. UPOZORNENIE: Zneužitie tejto funkcie môže porušiť zásady poskytovateľa služieb a viesť k zablokovaniu účtu.
migrate.clone_local_path=alebo cestu k lokálnemu serveru
migrate.permission_denied=Nemáte povolené importovať miestne repozitáre.
migrate.invalid_lfs_endpoint=Koncový bod LFS nie je platný.
diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini
index da4b1ba6fd8..d4be527a82a 100644
--- a/options/locale/locale_sv-SE.ini
+++ b/options/locale/locale_sv-SE.ini
@@ -287,7 +287,6 @@ email_domain_blacklisted=Du kan inte registrera dig med din e-postadress.
authorize_application=Godkänn applikation
authorize_redirect_notice=Du kommer att omdirigeras till %s om du auktoriserar denna applikation.
authorize_application_created_by=Denna applikation skapades av %s.
-authorize_application_description=Om du beviljar åtkomst kommer den att kunna läsa och skriva information om ditt konto, inklusive privata förråd och organisationer.
authorize_title=Ge "%s" tillgång till ditt konto?
authorization_failed=Auktorisering misslyckades
sspi_auth_failed=SSPI-autentisering misslyckades
@@ -464,7 +463,6 @@ activate_email=Skicka aktivering
activations_pending=Väntar på aktivering
delete_email=Ta Bort
email_deletion=Ta Bort mejladress
-email_deletion_desc=Mejladressen och relaterad information kommer tas bort från ditt konto. Git-commits med denna mejladress förblir oförändrade. Vill du fortsätta?
email_deletion_success=Mejladressen har tagits bort.
theme_update_success=Ditt tema ändrades.
theme_update_error=Det valda temat finns inte.
@@ -573,7 +571,6 @@ passcode_invalid=Koden är ogiltig. Försök igen.
manage_account_links=Hantera Länkade Konton
manage_account_links_desc=Dessa externa konton är länkade till ditt Gitea-konto.
-account_links_not_available=Det finns för närvarande inga externa konton länkade till ditt Gitea-konto.
link_account=Länka konto
remove_account_link=Ta Bort Länkat Konto
remove_account_link_desc=Borttagning av länkade konton kommer häva dess åtkomst till ditt Gitea-konto. Vill du fortsätta?
@@ -961,7 +958,6 @@ issues.lock_no_reason=låst och begränsat konversation till kollaboratörer %s
issues.unlock_comment=lås upp denna konversation %s
issues.lock_confirm=Lås
issues.unlock_confirm=Lås upp
-issues.lock.notice_1=- Andra användare kan inte kommentera detta ärende.
issues.lock.notice_2=- Du och andra kollaboratörer med tillgång till denna utvecklingskatalog kan fortfarande skriva kommentarer som andra kan se.
issues.lock.notice_3=- Du kan alltid låsa upp detta ärende senare.
issues.unlock.notice_1=- Alla kommer kunna kommentera detta ärende en gång till.
@@ -1182,7 +1178,6 @@ activity.title.releases_1=%d release
activity.title.releases_n=%d releaser
activity.title.releases_published_by=%s publicerad av %s
activity.published_release_label=Publicerad
-activity.no_git_activity=Det har inte gjorts några commit under den här perioden.
activity.git_stats_exclude_merges=Exkludera merger,
activity.git_stats_author_1=%d författare
activity.git_stats_author_n=%d författare
diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini
index 25773f43c7e..eebf0061442 100644
--- a/options/locale/locale_tr-TR.ini
+++ b/options/locale/locale_tr-TR.ini
@@ -117,7 +117,6 @@ files=Dosyalar
error=Hata
error404=Ulaşmaya çalıştığınız sayfa mevcut değil veya görüntüleme yetkiniz yok.
-error503=Sunucu isteğinizi gerçekleştiremedi. Lütfen daha sonra tekrar deneyin.
go_back=Geri Git
invalid_data=Geçersiz veri: %v
@@ -131,7 +130,6 @@ unpin=Sabitlemeyi kaldır
artifacts=Yapılar
expired=Süresi doldu
-confirm_delete_artifact=%s yapısını silmek istediğinizden emin misiniz?
archived=Arşivlenmiş
@@ -171,7 +169,6 @@ internal_error_skipped=Dahili bir hata oluştu ama atlandı: %s
search=Ara...
type_tooltip=Arama türü
fuzzy=Bulanık
-fuzzy_tooltip=Arama terimine benzeyen sonuçları da içer
words=Kelimeler
words_tooltip=Sadece arama terimi kelimeleriyle eşleşen sonuçları içer
regexp=Regexp
@@ -358,7 +355,6 @@ no_reply_address=Gizlenecek E-Posta Alan Adı
no_reply_address_helper=Gizlenmiş e-posta adresine sahip kullanıcılar için alan adı. Örneğin 'ali' kullanıcı adı, gizlenmiş e-postalar için alan adı 'yanityok.ornek.org' olarak ayarlandığında Git günlüğüne 'ali@yanityok.ornek.org' olarak kaydedilecektir.
password_algorithm=Parola Hash Algoritması
invalid_password_algorithm=Hatalı parola hash algoritması
-password_algorithm_helper=Parola hash algoritmasını ayarlayın. Algoritmalar değişen gereksinimlere ve güce sahiptirler. argon2 algoritması iyi özelliklere sahip olmasına rağmen fazla miktarda bellek kullanır ve küçük sistemler için uygun olmayabilir.
enable_update_checker=Güncelleme Denetleyicisini Etkinleştir
enable_update_checker_helper=Düzenli olarak gitea.io'ya bağlanarak yeni yayınlanan sürümleri denetler.
env_config_keys=Ortam Yapılandırma
@@ -452,7 +448,6 @@ use_scratch_code=Bir çizgi kodu kullanınız
twofa_scratch_used=Geçici kodunuzu kullandınız. İki aşamalı ayarlar sayfasına yönlendirildiniz, burada aygıt kaydınızı kaldırabilir veya yeni bir geçici kod oluşturabilirsiniz.
twofa_passcode_incorrect=Şifreniz yanlış. Aygıtınızı yanlış yerleştirdiyseniz, oturum açmak için çizgi kodunuzu kullanın.
twofa_scratch_token_incorrect=Çizgi kodunuz doğru değildir.
-twofa_required=Depolara erişmek için iki aşama doğrulama kullanmanız veya tekrar oturum açmayı denemeniz gereklidir.
login_userpass=Oturum Aç
login_openid=Açık Kimlik
oauth_signup_tab=Yeni Hesap Oluştur
@@ -464,7 +459,6 @@ oauth_signin_submit=Hesabı Bağla
oauth.signin.error.general=Yetkilendirme isteğini işlerken bir hata oluştu: %s. Eğer hata devam ederse lütfen site yöneticisiyle bağlantıya geçin.
oauth.signin.error.access_denied=Yetkilendirme isteği reddedildi.
oauth.signin.error.temporarily_unavailable=Yetkilendirme sunucusu geçici olarak erişilemez olduğu için yetkilendirme başarısız oldu. Lütfen daha sonra tekrar deneyin.
-oauth_callback_unable_auto_reg=Otomatik kayıt etkin ancak OAuth2 Sağlayıcı %[1] eksik sahalar döndürdü: %[2]s, otomatik olarak hesap oluşturulamıyor, lütfen bir hesap oluşturun veya bağlantı verin, veya site yöneticisiyle iletişim kurun.
openid_connect_submit=Bağlan
openid_connect_title=Mevcut olan bir hesaba bağlan
openid_connect_desc=Seçilen OpenID URI'si bilinmiyor. Burada yeni bir hesapla ilişkilendir.
@@ -477,7 +471,6 @@ email_domain_blacklisted=Bu e-posta adresinizle kayıt olamazsınız.
authorize_application=Uygulamayı Yetkilendir
authorize_redirect_notice=Bu uygulamayı yetkilendirirseniz %s adresine yönlendirileceksiniz.
authorize_application_created_by=Bu uygulama %s tarafından oluşturuldu.
-authorize_application_description=Erişime izin verirseniz, özel depolar ve organizasyonlar da dahil olmak üzere tüm hesap bilgilerinize erişebilir ve yazabilir.
authorize_application_with_scopes=Kapsamlar: %s
authorize_title=Hesabınıza erişmesi için "%s" yetkilendirilsin mi?
authorization_failed=Yetkilendirme başarısız oldu
@@ -506,8 +499,6 @@ activate_email.text=E posta adresinizi doğrulamak için lütfen %s için
register_notify=%s'ya Hoş Geldiniz
register_notify.title=%[1]s, %[2]s e hoşgeldiniz
-register_notify.text_1=bu %s için kayıt onay e postanızdır!
-register_notify.text_2=Artık %s kullanıcı adı ile oturum açabilirsiniz.
register_notify.text_3=Eğer bu hesap sizin için oluşturulduysa, lütfen önce şifrenizi ayarlayın.
reset_password=Hesabınızı kurtarın
@@ -689,7 +680,6 @@ form.name_chars_not_allowed=`"%s" kullanıcı adı geçersiz karakterler içeriy
block.block=Engelle
block.block.user=Kullanıcıyı engelle
-block.block.org=Kullanıcıyı organizasyonda engelle
block.block.failure=Kullanıcı engellenemedi: %s
block.unblock=Engeli kaldır
block.unblock.failure=Kullanıcının engeli kaldırılamadı: %s
@@ -733,7 +723,6 @@ webauthn=İki-Aşamalı Kimlik Doğrulama (Güvenlik Anahtarları)
public_profile=Herkese Açık Profil
biography_placeholder=Bize kendiniz hakkında birşeyler söyleyin! (Markdown kullanabilirsiniz)
location_placeholder=Yaklaşık konumunuzu başkalarıyla paylaşın
-profile_desc=Profilinizin başkalarına nasıl gösterildiğini yönetin. Ana e-posta adresiniz bildirimler, parola kurtarma ve web tabanlı Git işlemleri için kullanılacaktır.
password_username_disabled=Yerel olmayan kullanıcılara kullanıcı adlarını değiştirme izni verilmemiştir. Daha fazla bilgi edinmek için lütfen site yöneticisi ile iletişime geçiniz.
password_full_name_disabled=Tam adınızı değiştirme izniniz yoktur. Daha fazla bilgi edinmek için lütfen site yöneticisi ile iletişime geçiniz.
full_name=Ad Soyad
@@ -812,7 +801,6 @@ activations_pending=Bekleyen Etkinleştirmeler
can_not_add_email_activations_pending=Bekleyen etkinleştirme var, yeni bir e-posta adresi eklemek istiyorsanız birkaç dakika içinde tekrar deneyin.
delete_email=Kaldır
email_deletion=E-posta Adresini Kaldır
-email_deletion_desc=E-posta adresi ve ilgili bilgiler hesabınızdan kaldırılacak. Bu e-posta adresi tarafından yapılan işlemeler değişmeden kalacaktır. Devam edilsin mi?
email_deletion_success=E-posta adresi kaldırıldı.
theme_update_success=Temanız güncellendi.
theme_update_error=Seçilen tema mevcut değil.
@@ -998,7 +986,6 @@ webauthn_alternative_tip=Ek bir kimlik doğrulama yöntemi ayarlamak isteyebilir
manage_account_links=Bağlı Hesapları Yönet
manage_account_links_desc=Bu harici hesaplar Gitea hesabınızla bağlantılı.
-account_links_not_available=Şu anda Gitea hesabınıza bağlı harici bir hesap yok.
link_account=Hesap Bağla
remove_account_link=Bağlantılı Hesabı Kaldır
remove_account_link_desc=Bağlantılı bir hesabı kaldırmak, onunla Gitea hesabınıza erişimi iptal edecektir. Devam edilsin mi?
@@ -1035,8 +1022,6 @@ new_repo_helper=Bir depo, sürüm geçmişi dahil tüm proje dosyalarını içer
owner=Sahibi
owner_helper=Bazı organizasyonlar, en çok depo sayısı sınırı nedeniyle açılır menüde görünmeyebilir.
repo_name=Depo İsmi
-repo_name_profile_public_hint=.profile herkese açık organizasyonunuzun profiline herkesin görüntüleyebileceği bir README.md dosyası eklemek için kullanabileceğiniz özel bir depodur. Başlamak için herkese açık olduğundan ve profile dizininde README ile başladığınızdan emin olun.
-repo_name_profile_private_hint=.profile-private organizasyonunuzun üye profiline sadece organizasyon üyelerinin görüntüleyebileceği bir README.md eklemek için kullanabileceğiniz özel bir depodur. Başlamak için özel olduğundan ve profil dizininde README ile başladığınızdan emin olun.
repo_name_helper=İyi depo isimleri kısa, akılda kalıcı ve benzersiz anahtar kelimeler kullanır. “.profile” veya ‘.profile-private’ adlı bir depo, kullanıcı/kuruluş profili için bir README.md eklemek için kullanılabilir.
repo_size=Depo Boyutu
template=Şablon
@@ -1058,7 +1043,6 @@ fork_branch=Çatala klonlanacak dal
all_branches=Tüm dallar
view_all_branches=Tüm dalları görüntüle
view_all_tags=Tüm etiketleri görüntüle
-fork_no_valid_owners=Geçerli bir sahibi olmadığı için bu depo çatallanamaz.
fork.blocked_user=Depo çatallanamıyor, depo sahibi tarafından engellenmişsiniz.
use_template=Bu şablonu kullan
open_with_editor=%s ile aç
@@ -1102,7 +1086,6 @@ mirror_sync=eşitlendi
mirror_sync_on_commit=İşlemeler gönderildiğinde senkronize et
mirror_address=URL'den Klonla
mirror_address_desc=Yetkilendirme bölümüne gerekli tüm kimlik bilgilerini girin.
-mirror_address_url_invalid=Sağlanan URL geçersiz. URL'nin tüm bileşenleri doğru olarak girilmelidir.
mirror_address_protocol_invalid=Sağlanan URL geçersiz. Yalnızca http(s):// veya git:// konumları yansı olabilir.
mirror_lfs=Büyük Dosya Depolama (LFS)
mirror_lfs_desc=LFS verisinin yansılamasını etkinleştir.
@@ -1162,8 +1145,6 @@ template.issue_labels=Konu Etiketleri
template.one_item=En az bir şablon öğesi seçmelisiniz
template.invalid=Bir şablon deposu seçmelisiniz
-archive.title=Bu depo arşivlendi. Dosyaları görüntüleyebilir ve klonlayabilirsiniz ama işleme gönderemez veya konu veya değişiklik isteği açamazsınız.
-archive.title_date=Bu depo %s tarihinde arşivlendi. Dosyaları görüntüleyebilir ve klonlayabilirsiniz ama işleme gönderemez veya konu veya değişiklik isteği açamazsınız.
archive.issue.nocomment=Bu depo arşivlendi. Konular bölümünde yorum yapamazsınız.
archive.pull.nocomment=Bu depo arşivlendi. Değişiklik istekleri bölümünde yorum yapamazsınız.
@@ -1192,7 +1173,6 @@ migrate_items_releases=Sürümler
migrate_repo=Depoyu Göç Ettir
migrate.clone_address=URL'den Taşı / Klonla
migrate.clone_address_desc=Varolan bir deponun HTTP(S) veya Git 'klonlama' URL'si
-migrate.github_token_desc=GitHub API hız sınırı nedeniyle göçü hızlandırmak için buraya virgülle ayrılmış bir veya daha fazla erişm anahtarı koyabilirsiniz. UYARI: Bu özelliğin kötüye kullanılması, hizmet sağlayıcının politikasını ihlal edebilir ve hesabın engellenmesine yol açabilir.
migrate.clone_local_path=veya bir yerel sunucu yolu
migrate.permission_denied=Yerel depoları içeri aktarma izniniz yok.
migrate.permission_denied_blocked=İzin verilmeyen sunuculardan içe aktaramazsınız, lütfen yöneticiden ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS ayarlarını kontrol etmesini isteyin.
@@ -1254,7 +1234,6 @@ create_new_repo_command=Komut satırında yeni bir depo oluşturuluyor
push_exist_repo=Komut satırından mevcut bir depo itiliyor
empty_message=Bu depoda herhangi bir içerik yok.
broken_message=Bu deponun altındaki Git verisi okunamıyor. Bu sunucunun yöneticisiyle bağlantıya geçin veya bu depoyu silin.
-no_branch=Bu deponun hiç bir dalı yok.
code=Kod
code.desc=Kaynak koda, dosyalara, işlemelere ve dallara eriş.
@@ -1399,8 +1378,6 @@ editor.failed_to_commit=Değişikliklerin işlenmesi başarısız oldu.
editor.failed_to_commit_summary=Hata Mesajı:
editor.fork_create=Değişiklikler Önermek için Depoyu Çatallayın
-editor.fork_create_description=Bu depoyu doğrudan düzenleyemezsiniz. Bunun yerine bir çatal oluşturabilir, düzenlemeler yapabilir ve bir değişiklik isteği oluşturabilirsiniz.
-editor.fork_edit_description=Bu depoyu doğrudan düzenleyemezsiniz. Değişiklikler %s çatalınıza yazılacak, böylece bir değişiklik isteği oluşturabilirsiniz.
editor.fork_not_editable=Bu deponun çatalını oluşturdunuz ancak çatalınız düzenlenemez durumda.
editor.fork_failed_to_push_branch=%s dalını deponuza gönderme başarısız oldu.
editor.fork_branch_exists=`"%s" dalı çatalınızda zaten mevcut, lütfen yeni bir dal adı seçin.`
@@ -1697,7 +1674,6 @@ issues.lock_no_reason=konuşma kilitlendi ve katkıcılar için sınırlandırı
issues.unlock_comment=bu konuşmanın kilidini açtı %s
issues.lock_confirm=Kilitle
issues.unlock_confirm=Kilidi Aç
-issues.lock.notice_1=- Diğer kullanıcılar bu konuya yeni yorum ekleyemez.
issues.lock.notice_2=- Siz ve bu depoya erişimi olan diğer katkıcılar, başkalarının görebileceği yorumlar bırakabilir.
issues.lock.notice_3=- Her zaman bu konunun kilidini açabilirsiniz.
issues.unlock.notice_1=- Herkes bu konuda bir kez daha yorum yapabilir.
@@ -1748,7 +1724,6 @@ issues.due_date_form=yyyy-aa-gg
issues.due_date_form_add=Bitiş tarihi ekle
issues.due_date_form_edit=Düzenle
issues.due_date_form_remove=Kaldır
-issues.due_date_not_writer=Bir konunun bitiş tarihini güncellemek için bu depoda yazma iznine ihtiyacınız var.
issues.due_date_not_set=Bitiş tarihi atanmadı.
issues.due_date_added=bitiş tarihini %s olarak %s ekledi
issues.due_date_modified=bitiş tarihini %[2]s iken %[1]s olarak %[3]s değiştirdi
@@ -1862,7 +1837,6 @@ pulls.select_commit_hold_shift_for_range=İşleme seç. Bir aralık seçmek içi
pulls.review_only_possible_for_full_diff=İnceleme sadece tam fark görüntülemede mümkündür
pulls.filter_changes_by_commit=İşleme ile süz
pulls.nothing_to_compare=Bu dallar eşit. Değişiklik isteği oluşturmaya gerek yok.
-pulls.nothing_to_compare_have_tag=Seçili dal/etiket aynı.
pulls.nothing_to_compare_and_allow_empty_pr=Bu dallar eşittir. Bu Dİ boş olacak.
pulls.has_pull_request=`Bu dallar arasında zaten bir değişiklik isteği var: %[2]s#%[3]d`
pulls.create=Değişiklik İsteği Oluştur
@@ -2016,7 +1990,6 @@ milestones.filter_sort.most_issues=En çok konu
milestones.filter_sort.least_issues=En az konu
signing.will_sign=Bu işleme "%s" anahtarıyla imzalanacak.
-signing.wont_sign.error=İşlemenin imzalanıp imzalanamayacağını kontrol ederken bir hata oluştu.
signing.wont_sign.nokey=Bu işlemeyi imzalamak için anahtar yok.
signing.wont_sign.never=İşlemeler asla imzalanmaz.
signing.wont_sign.always=İşlemeler her zaman imzalanır.
@@ -2107,7 +2080,6 @@ activity.title.releases_1=%d Sürüm
activity.title.releases_n=%d Sürüm
activity.title.releases_published_by=%s %s tarafından yayınlandı
activity.published_release_label=Yayınlandı
-activity.no_git_activity=Bu dönemde herhangi bir işleme yapılmamıştır.
activity.git_stats_exclude_merges=Birleştirmeler hariç,
activity.git_stats_author_1=%d yazar
activity.git_stats_author_n=%d yazar
@@ -2914,9 +2886,6 @@ dashboard.resync_all_sshprincipals='.ssh/authorized_principals' dosyasını Gite
dashboard.resync_all_hooks=Tüm depoların alma öncesi, güncelleme ve alma sonrası kancalarını yeniden senkronize edin.
dashboard.reinit_missing_repos=Kayıtları bulunanlar için tüm eksik Git depolarını yeniden başlat
dashboard.sync_external_users=Harici kullanıcı verisini senkronize et
-dashboard.cleanup_hook_task_table=Hook_task tablosunu temizleme
-dashboard.cleanup_packages=Süresi dolmuş paketleri temizleme
-dashboard.cleanup_actions=Eylemlerin süresi geçmiş günlük ve yapılarını temizle
dashboard.server_uptime=Sunucunun Ayakta Kalma Süresi
dashboard.current_goroutine=Güncel Goroutine'ler
dashboard.current_memory_usage=Güncel Bellek Kullanımı
@@ -3600,7 +3569,6 @@ owner.settings.cargo.initialize.success=Cargo dizini başarıyla oluşturuldu.
owner.settings.cargo.rebuild=Dizini yeniden oluştur
owner.settings.cargo.rebuild.description=İndeks, depolanmış Cargo paketleriyle eşzamanlanmamışsa yeniden oluşturma yararlı olabilir.
owner.settings.cargo.rebuild.error=Cargo dizinini yeniden oluşturma başarısız oldu: %v
-owner.settings.cargo.rebuild.success=Cargo dizini başarıyla yeniden oluşturuldu.
owner.settings.cleanuprules.title=Temizleme Kurallarını Yönet
owner.settings.cleanuprules.add=Temizleme Kuralı Ekle
owner.settings.cleanuprules.edit=Temizleme Kuralı Düzenle
@@ -3683,7 +3651,6 @@ runners.delete_runner=Bu çalıştırıcıyı sil
runners.delete_runner_success=Çalıştırıcı başarıyla silindi
runners.delete_runner_failed=Çalıştırıcı silinemedi
runners.delete_runner_header=Çalıştırıcıyı silmeyi onaylayın
-runners.delete_runner_notice=Eğer bu çalıştırıcıda bir görev çalışıyorsa, sonlandırılacak ve başarısız olarak işaretlenecek. Yapım iş akışını bozabilir.
runners.none=Hiç çalıştırıcı yok
runners.status.unspecified=Bilinmiyor
runners.status.idle=Boşta
diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini
index 6d7721537bb..b51ed93f92a 100644
--- a/options/locale/locale_uk-UA.ini
+++ b/options/locale/locale_uk-UA.ini
@@ -116,7 +116,6 @@ files=Файли
error=Помилка
error404=Сторінка, яку ви намагаєтеся відкрити, не існує або ви не маєте права на її перегляд.
-error503=Сервер не зміг виконати ваш запит. Будь ласка, спробуйте пізніше.
go_back=Назад
invalid_data=Недійсні дані: %v
@@ -130,7 +129,6 @@ unpin=Відкріпити
artifacts=Артефакти
expired=Прострочено
-confirm_delete_artifact=Справді видалити артефакт '%s' ?
archived=Архівовано
@@ -168,7 +166,6 @@ internal_error_skipped=Трапилась внутрішня помилка, а
search=Пошук...
type_tooltip=Тип пошуку
fuzzy=Неточний
-fuzzy_tooltip=Включити результати, які також близько відповідають пошуковому запиту
words=Слова
words_tooltip=Включати тільки результати, які відповідають пошуковим словам
regexp=Регулярний вираз
@@ -352,7 +349,6 @@ no_reply_address=Прихований поштовий домен
no_reply_address_helper=Доменне ім'я для користувачів із прихованою електронною адресою. Наприклад, ім'я користувача 'Joe' буде зображатися в Git як 'joe@noreply.example.org', якщо прихований домен електронної пошти встановлено 'noreply.example.org'.
password_algorithm=Алгоритм хешування пароля
invalid_password_algorithm=Недійсний хеш-алгоритм пароля
-password_algorithm_helper=Встановіть алгоритм хешування пароля. Алгоритми мають різні вимоги та стійкість. Алгоритм argon2 є досить безпечним, але використовує багато пам'яті і може бути недоречним для малих систем.
enable_update_checker=Увімкнути перевірку оновлень
enable_update_checker_helper=Періодично перевіряти наявність нових версій, підключаючись до gitea.io.
env_config_keys=Конфігурація середовища
@@ -469,7 +465,6 @@ email_domain_blacklisted=Ви не можете зареєструватися
authorize_application=Авторизувати програму
authorize_redirect_notice=Вас буде переадресовано до %s, якщо ви авторизуєте цю програму.
authorize_application_created_by=Ця програма створена %s.
-authorize_application_description=Якщо ви авторизуєте цю програму, їй буде надано дозвіл на редагування або читання всієї інформації вашого облікового запису, включно з приватними сховищами та організаціями.
authorize_title=Авторизувати "%s" для доступу до вашого облікового запису?
authorization_failed=Помилка авторизації
authorization_failed_desc=Авторизація не вдалася, оскільки ми виявили недійсний запит. Зверніться до розробника програми, яку ви намагалися авторизувати.
@@ -497,8 +492,6 @@ activate_email.text=Будь ласка, перейдіть за наступн
register_notify=Ласкаво просимо до %s
register_notify.title=%[1]s, ласкаво просимо до %[2]s
-register_notify.text_1=це лист з підтвердженням реєстрації на %s!
-register_notify.text_2=Тепер ви можете увійти як: %s.
register_notify.text_3=Якщо цей обліковий запис створено для вас, будь ласка, спершу встановіть пароль.
reset_password=Відновити обліковий запис
@@ -678,7 +671,6 @@ form.name_chars_not_allowed=Ім’я користувача "%s" містить
block.block=Заблокувати
block.block.user=Заблокувати користувача
-block.block.org=Заблокувати користувача для організації
block.block.failure=Не вдалося заблокувати користувача: %s
block.unblock=Розблокувати
block.unblock.failure=Не вдалося розблокувати користувача: %s
@@ -719,7 +711,6 @@ webauthn=Двофакторна автентифікація (ключі без
public_profile=Загальнодоступний профіль
biography_placeholder=Розкажіть нам трохи про себе! (Ви можете використовувати Markdown)
location_placeholder=Ділитися своїм приблизним географічним положенням з іншими
-profile_desc=Керуйте тим, як ваш профіль буде показано іншим користувачам. Ваша основна адреса електронної пошти використовуватиметься для сповіщень, відновлення пароля та веб-операцій Git.
password_username_disabled=Вам не дозволено змінювати ім'я користувача. Будь ласка, зв'яжіться з адміністратором сайту для отримання більш докладної інформації.
password_full_name_disabled=Вам не дозволено змінювати ваше ім'я. Будь ласка, зв'яжіться з адміністратором сайту для більш докладної інформації.
full_name=Повне ім'я
@@ -798,7 +789,6 @@ activations_pending=Очікування активації
can_not_add_email_activations_pending=Відбувається активація, спробуйте ще раз через кілька хвилин, якщо хочете додати нову адресу електронної пошти.
delete_email=Видалити
email_deletion=Видалити адресу електронної пошти
-email_deletion_desc=Адреса електронної пошти та пов'язана з нею інформація буде видалена з вашого облікового запису. Коміти Git, здійснені через цю адресу електронну пошту, залишиться без змін. Продовжити?
email_deletion_success=Адресу електронної пошти видалено.
theme_update_success=Тему оновлено.
theme_update_error=Обрана тема не існує.
@@ -980,7 +970,6 @@ webauthn_alternative_tip=Ви можете налаштувати додатко
manage_account_links=Керування прив'язаними обліковими записами
manage_account_links_desc=Ці зовнішні облікові записи прив'язані до вашого облікового запису Gitea.
-account_links_not_available=Наразі немає зовнішніх облікових записів, пов'язаних із вашим обліковим записом Gitea.
link_account=Прив'язати обліковий запис
remove_account_link=Видалити обліковий запис
remove_account_link_desc=Видалення пов'язаного облікового запису відкликає його доступ до вашого облікового запису Gitea. Продовжити?
@@ -1016,7 +1005,6 @@ new_repo_helper=Сховище містить усі файли проєкту,
owner=Власник
owner_helper=Деякі організації можуть не відображатися у списку через обмеження на максимальну кількість сховищ.
repo_name=Назва сховища
-repo_name_profile_public_hint=.profile - це спеціальне сховище, за допомогою якого ви можете додати README.md до профілю вашої публічної організації, який буде видимим для всіх. Переконайтеся, що він є публічним, та ініціалізуйте його за допомогою README у каталозі профілю.
repo_name_helper=У хороших назвах сховищ використовуються короткі ключові слова, які легко запам'ятовуються та є унікальними. Сховище з назвою «.profile» або «.profile-private» можна використовувати для додавання README.md для профілю користувача/організації.
repo_size=Розмір сховища
template=Шаблон
@@ -1077,7 +1065,6 @@ mirror_sync=синхронізовано
mirror_sync_on_commit=Синхронізувати, коли надсилаються коміти
mirror_address=Клонувати з URL-адреси
mirror_address_desc=Введіть необхідні облікові дані в розділі Авторизація.
-mirror_address_url_invalid=URL-адреса недійсна. Необхідно правильно екранувати всі компоненти URL-адреси.
mirror_address_protocol_invalid=URL-адреса недійсна. Допустимі лише адреси http(s):// або git://.
mirror_lfs=Сховище великих файлів (LFS)
mirror_lfs_desc=Активувати дзеркалювання даних LFS.
@@ -1136,8 +1123,6 @@ template.issue_labels=Мітки задачі
template.one_item=Слід обрати хоча б один елемент шаблону
template.invalid=Слід обрати шаблонне сховище
-archive.title=Це архівне сховище. Ви можете переглядати й клонувати файли, але не можете завантажувати свої зміни або відкривати задачі чи запити на злиття.
-archive.title_date=Це архівне сховище на %s. Ви можете переглядати файли й клонувати його, але не можете завантажувати свої зміни або відкривати задачі чи запити на злиття.
archive.issue.nocomment=Це сховище архівовано. Ви не можете коментувати задачі.
archive.pull.nocomment=Це сховище архівовано. Ви не можете коментувати запити на злиття.
@@ -1165,7 +1150,6 @@ migrate_items_releases=Релізи
migrate_repo=Перенести репозиторій
migrate.clone_address=Міграція / клонувати з URL-адреси
migrate.clone_address_desc=URL-адреса HTTP(S) або Git "clone" існуючого сховища
-migrate.github_token_desc=Ви можете додати один або декілька токенів через кому, щоб пришвидшити міграцію через обмеження швидкості API GitHub. ПОПЕРЕДЖЕННЯ: Зловживання цією функцією може порушити політику постачальника послуг і призвести до блокування облікового запису.
migrate.clone_local_path=або шлях до локального серверу
migrate.permission_denied=Вам не дозволено імпортувати локальні репозиторії.
migrate.permission_denied_blocked=Ви не можете імпортувати з заборонених вузлів, будь ласка, попросіть адміністратора перевірити налаштування ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS.
@@ -1226,7 +1210,6 @@ create_new_repo_command=Створити новий репозиторій з к
push_exist_repo=Опублікувати існуючий репозиторій з командного рядка
empty_message=Це сховище порожнє.
broken_message=Неможливо прочитати дані Git, що лежать в основі цього сховища. Зверніться до адміністратора сервера або видаліть сховище.
-no_branch=Це сховище не має гілок.
code=Код
code.desc=Доступ до коду, файлів, комітів та гілок.
@@ -1357,7 +1340,6 @@ editor.revert=Повернути %s до:
editor.failed_to_commit=Не вдалося зафіксувати зміни.
editor.failed_to_commit_summary=Помилка:
-editor.fork_edit_description=Ви не можете редагувати це сховище безпосередньо. Зміни буде записано до вашого форку %s, тож ви зможете створити запит на злиття.
commits.desc=Переглянути історію зміни коду.
commits.commits=Коміти
@@ -1638,7 +1620,6 @@ issues.lock_no_reason=заблоковано та обмежене обгово
issues.unlock_comment=розблокував(ла) обговорення %s
issues.lock_confirm=Заблокувати
issues.unlock_confirm=Розблокувати
-issues.lock.notice_1=- Інші користувачі не можуть додавати нові коментарі до цієї задачі.
issues.lock.notice_2=- Ви та інші співавтори, які мають доступ до цього сховища, все ще можете залишати коментарі, які можуть бачити інші.
issues.lock.notice_3=- Ви завжди зможете розблокувати цю задачу в майбутньому.
issues.unlock.notice_1=- Кожен зможе прокоментувати цю задачу ще раз.
@@ -1690,7 +1671,6 @@ issues.due_date_form=рррр-мм-дд
issues.due_date_form_add=Додати дату завершення
issues.due_date_form_edit=Редагувати
issues.due_date_form_remove=Видалити
-issues.due_date_not_writer=Вам потрібен доступ на запис до цього сховища, щоб оновити дату виконання задачі.
issues.due_date_not_set=Термін виконання не встановлений.
issues.due_date_added=додав(ла) дату завершення %s %s
issues.due_date_modified=змінив(-ла) термін виконання з %[2]s на %[1]s %[3]s
@@ -1801,7 +1781,6 @@ pulls.showing_specified_commit_range=Відображаються лише зм
pulls.select_commit_hold_shift_for_range=Виберіть коміт. Натисніть клавішу Shift + клацніть, щоб виділити діапазон
pulls.filter_changes_by_commit=Фільтр за комітом
pulls.nothing_to_compare=Ці гілки однакові. Немає необхідності створювати запитів на злиття.
-pulls.nothing_to_compare_have_tag=Виділена гілка або мітка ідентичні.
pulls.nothing_to_compare_and_allow_empty_pr=Одинакові гілки. Цей PR буде порожнім.
pulls.has_pull_request=`Запит злиття для цих гілок вже існує: %[2]s#%[3]d`
pulls.create=Створити запит на злиття
@@ -1933,7 +1912,6 @@ milestones.filter_sort.most_issues=Найбільше задач
milestones.filter_sort.least_issues=Найменше задач
signing.will_sign=Цей коміт буде підписано ключем "%s".
-signing.wont_sign.error=Виникла помилка під час перевірки можливості підписання коміту.
signing.wont_sign.nokey=Немає ключа для підписання цього коміту.
signing.wont_sign.never=Коміти ніколи не підписуються.
signing.wont_sign.always=Коміти завжди підписуються.
@@ -2024,7 +2002,6 @@ activity.title.releases_1=%d Реліз
activity.title.releases_n=%d Релізів
activity.title.releases_published_by=%s опубліковано %s
activity.published_release_label=Опубліковано
-activity.no_git_activity=За цей період не було жодної активності комітів.
activity.git_stats_exclude_merges=Не враховуючи об'єднання,
activity.git_stats_author_1=%d автор
activity.git_stats_author_n=%d автори
@@ -2362,7 +2339,6 @@ settings.block_on_official_review_requests_desc=Об’єднання немож
settings.block_outdated_branch=Блокувати об'єднання, якщо запит на злиття застарів
settings.block_outdated_branch_desc=Об'єднання буде неможливим, якщо головна гілка позаду основної.
settings.block_admin_merge_override=Адміністратори повинні дотримуватися правил захисту гілки
-settings.block_admin_merge_override_desc=Адміністратори повинні дотримуватися правил захисту гілки і не можуть їх обійти.
settings.default_branch_desc=Обрати типову гілку сховища для запитів на злиття і комітів:
settings.merge_style_desc=Стилі об'єднання
settings.default_merge_style_desc=Типовий стиль об'єднання
@@ -2617,7 +2593,6 @@ team_permission_desc=Права доступу
team_unit_desc=Дозволити доступ до розділів репозиторію
team_unit_disabled=(Вимкнено)
-form.name_been_taken=Назва організації "%s" вже зайнята.
form.name_reserved=Назву організації "%s" зарезервовано.
form.name_pattern_not_allowed=Шаблон "%s" не допускається в назві організації.
form.create_org_not_allowed=Вам не дозволено створювати організації.
@@ -2659,7 +2634,6 @@ settings.delete_notices_2=Ця операція назавжди видалит
settings.delete_notices_3=Ця операція назавжди видалить всі пакети%s.
settings.delete_notices_4=Ця операція назавжди видалить всі проєкти%s.
settings.confirm_delete_account=Підтвердити видалення
-settings.delete_failed=Не вдалося видалити організацію через внутрішню помилку
settings.delete_successful=Організацію %s успішно видалено.
settings.hooks_desc=Додайте веб-хуки, які спрацьовуватимуть для всіх сховищ у цій організації.
@@ -2806,9 +2780,6 @@ dashboard.resync_all_sshprincipals=Оновіть файл '.ssh/authorized_prin
dashboard.resync_all_hooks=Заново синхронізувати хуки попереднього отримання, оновлення та пост-отримання всіх сховищ.
dashboard.reinit_missing_repos=Заново ініціалізувати всі відсутні сховища Git'а, для яких існують записи
dashboard.sync_external_users=Синхронізувати дані зовнішніх користувачів
-dashboard.cleanup_hook_task_table=Очистити таблицю hook_task
-dashboard.cleanup_packages=Очистити застарілі пакети
-dashboard.cleanup_actions=Очищення ресурсів прострочених дій
dashboard.server_uptime=Час роботи сервера
dashboard.current_goroutine=Поточна кількість Goroutines
dashboard.current_memory_usage=Поточне використання пам'яті
@@ -3219,7 +3190,6 @@ monitor.start=Час початку
monitor.execute_time=Час виконання
monitor.last_execution_result=Результат
monitor.process.cancel=Зупинити процес
-monitor.process.cancel_desc=Скасування процесу може призвести до втрати даних
monitor.process.children=Дочірні процеси
monitor.queues=Черги
@@ -3480,7 +3450,6 @@ owner.settings.cargo.initialize.success=Індекс Cargo успішно ств
owner.settings.cargo.rebuild=Перебудувати індекс
owner.settings.cargo.rebuild.description=Повторна збірка може бути корисною, якщо індекс не синхронізовано зі збереженими пакетами Cargo.
owner.settings.cargo.rebuild.error=Не вдалося перебудувати індекс Cargo: %v
-owner.settings.cargo.rebuild.success=Індекс Cargo успішно перебудовано.
owner.settings.cleanuprules.title=Керувати правилами очищення
owner.settings.cleanuprules.add=Додати правило очищення
owner.settings.cleanuprules.edit=Редагувати правило очищення
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index f2a3d29becf..a47083b45e5 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -117,7 +117,6 @@ files=文件
error=错误
error404=您正尝试访问的页面 不存在 或 您尚未被授权 查看该页面。
-error503=服务器无法完成您的请求,请稍后重试。
go_back=返回
invalid_data=无效数据: %v
@@ -131,7 +130,6 @@ unpin=取消置顶
artifacts=产物
expired=已过期
-confirm_delete_artifact=您确定要删除产物「%s」吗?
archived=已归档
@@ -171,7 +169,6 @@ internal_error_skipped=发生内部错误,但已跳过: %s
search=搜索...
type_tooltip=搜索类型
fuzzy=模糊
-fuzzy_tooltip=包含近似匹配搜索词的结果
words=词
words_tooltip=仅包含匹配搜索词的结果
regexp=正则表达式
@@ -358,7 +355,6 @@ no_reply_address=隐藏邮件域
no_reply_address_helper=具有隐藏邮箱地址的用户的域名。例如,如果隐藏邮箱域名设置为「noreply.example.org」,那么用户名「joe」在 Git 中将显示为「joe@noreply.example.org」。
password_algorithm=密码哈希算法
invalid_password_algorithm=无效的密码哈希算法
-password_algorithm_helper=设置密码散列算法。算法有不同的要求和强度。 argon2 算法相当安全,但使用大量内存,因此可能不适合小型系统。
enable_update_checker=启用更新检查
enable_update_checker_helper=通过连接到 gitea.io 定期检查新版本发布。
env_config_keys=环境配置
@@ -452,7 +448,6 @@ use_scratch_code=使用验证口令
twofa_scratch_used=您已经使用了您的验证口令。您将会转到两步验证设置页面以便移除您的注册设备或者重新生成新的验证口令。
twofa_passcode_incorrect=您的验证码不正确。如果您丢失了您的设备,请使用您的验证口令。
twofa_scratch_token_incorrect=您的验证口令不正确。
-twofa_required=您必须设置两步验证来访问仓库,或者尝试重新登录。
login_userpass=登录
login_openid=OpenID
oauth_signup_tab=注册帐号
@@ -464,7 +459,6 @@ oauth_signin_submit=绑定账号
oauth.signin.error.general=处理授权请求时出错:%s。如果此错误仍然存在,请与站点管理员联系。
oauth.signin.error.access_denied=授权请求被拒绝。
oauth.signin.error.temporarily_unavailable=授权失败,因为认证服务器暂时不可用。请稍后再试。
-oauth_callback_unable_auto_reg=自动注册已启用,但 OAuth2 提供商 %[1]s 返回缺失的字段:%[2]s,无法自动创建帐户,请创建或链接到一个帐户,或联系站点管理员。
openid_connect_submit=连接
openid_connect_title=连接到现有的帐户
openid_connect_desc=所选的 OpenID URI 未知。在这里关联一个新帐户。
@@ -477,7 +471,6 @@ email_domain_blacklisted=您不能使用您的邮箱地址注册。
authorize_application=应用授权
authorize_redirect_notice=如果您授权此应用,您将会被重定向到 %s。
authorize_application_created_by=此应用由 %s 创建。
-authorize_application_description=如果您允许,它将能够读取和修改您的所有帐户信息,包括私人仓库和组织。
authorize_application_with_scopes=范围:%s
authorize_title=授权 %s 访问您的帐户?
authorization_failed=授权失败
@@ -506,8 +499,6 @@ activate_email.text=请在 %s 时间内,点击以下链接,以验证
register_notify=欢迎来到 %s
register_notify.title=%[1]s,欢迎来到 %[2]s
-register_notify.text_1=这是您的 %s 注册确认邮件 !
-register_notify.text_2=您现在可以以用户名 %s 登录。
register_notify.text_3=如果此账户已为您创建,请先 设置您的密码。
reset_password=恢复您的账户
@@ -689,7 +680,6 @@ form.name_chars_not_allowed=用户名「%s」包含无效字符。
block.block=屏蔽
block.block.user=屏蔽用户
-block.block.org=屏蔽用户访问组织
block.block.failure=屏蔽用户失败:%s
block.unblock=取消屏蔽
block.unblock.failure=取消屏蔽用户失败:%s
@@ -733,7 +723,6 @@ webauthn=两步验证(安全密钥)
public_profile=公开信息
biography_placeholder=告诉我们一点您自己! (您可以使用 Markdown)
location_placeholder=与他人分享您的大概位置
-profile_desc=控制您的个人资料对其他用户的显示方式。您的主邮箱地址将用于通知、密码恢复和基于网页的 Git 操作。
password_username_disabled=您不被允许更改您的用户名。更多详情请联系您的系统管理员。
password_full_name_disabled=您不被允许更改您的全名。请联系您的站点管理员了解更多详情。
full_name=自定义名称
@@ -812,7 +801,6 @@ activations_pending=等待激活
can_not_add_email_activations_pending=有一个待处理的激活请求,请稍等几分钟后再尝试添加新的邮箱地址。
delete_email=移除
email_deletion=移除邮箱地址
-email_deletion_desc=邮箱地址和相关信息将会被删除。使用此邮箱地址发送的Git提交将会保留,继续?
email_deletion_success=您的邮箱地址已移除。
theme_update_success=您的主题已更新。
theme_update_error=所选主题不存在。
@@ -998,7 +986,6 @@ webauthn_alternative_tip=您可能想要配置额外的身份验证方法。
manage_account_links=管理绑定过的账号
manage_account_links_desc=这些外部帐户已经绑定到您的 Gitea 帐户。
-account_links_not_available=当前没有与您的 Gitea 帐户绑定的外部帐户。
link_account=链接账户
remove_account_link=删除已绑定的账号
remove_account_link_desc=删除已绑定帐户将吊销其对您的 Gitea 帐户的访问权限。继续?
@@ -1035,8 +1022,6 @@ new_repo_helper=代码仓库包含了所有的项目文件,包括版本历史
owner=拥有者
owner_helper=由于最大仓库数量限制,一些组织可能不会显示在下拉列表中。
repo_name=仓库名称
-repo_name_profile_public_hint=.profile 是一个特殊的仓库,您可以使用它将 README.md 添加到您的公共组织资料中,任何人都可以看到。请确保它是公开的,并使用个人资料目录中的 README 对其进行初始化以开始使用。
-repo_name_profile_private_hint=.profile-private 是一个特殊的仓库,您可以使用它向您的组织成员个人资料添加 README.md,仅对组织成员可见。请确保它是私有的,并使用个人资料目录中的 README 对其进行初始化以开始使用。
repo_name_helper=理想的仓库名称应由简短、有意义和独特的关键词组成。「.profile」和「.profile-private」可用于为用户/组织添加 README.md。
repo_size=仓库大小
template=模板
@@ -1058,7 +1043,6 @@ fork_branch=要克隆为派生的分支
all_branches=所有分支
view_all_branches=查看所有分支
view_all_tags=查看所有标签
-fork_no_valid_owners=这个代码仓库无法被派生,因为没有有效的所有者。
fork.blocked_user=无法克隆仓库,因为您被仓库所有者屏蔽。
use_template=使用此模板
open_with_editor=用 %s 打开
@@ -1103,7 +1087,6 @@ mirror_sync=已同步
mirror_sync_on_commit=推送提交时同步
mirror_address=从 URL 克隆
mirror_address_desc=在授权框中输入必要的凭据。
-mirror_address_url_invalid=URL无效。请检查您所输入的URL是否正确。
mirror_address_protocol_invalid=提供的URL无效。只能使用http(s)://或git://地址进行镜像操作。
mirror_lfs=大文件存储 (LFS)
mirror_lfs_desc=镜像 LFS 数据。
@@ -1163,8 +1146,6 @@ template.issue_labels=工单标签
template.one_item=必须至少选择一个模板项
template.invalid=必须选择一个模板仓库
-archive.title=该仓库已被归档。您可以查看文件和克隆它,但不能推送、创建工单或合并请求。
-archive.title_date=该仓库已于 %s 归档。您可以查看文件或克隆它,但不能推送、创建工单或合并请求。
archive.issue.nocomment=此仓库已存档,您不能在此工单添加评论。
archive.pull.nocomment=此仓库已存档,您不能在此合并请求添加评论。
@@ -1193,7 +1174,6 @@ migrate_items_releases=发布
migrate_repo=迁移仓库
migrate.clone_address=从 URL 迁移/克隆
migrate.clone_address_desc=现有仓库的 HTTP(s) 或 Git "clone" URL
-migrate.github_token_desc=由于 GitHub API 速率限制,您可以在此处放置一个或多个以逗号分隔的令牌,以加快迁移速度。 警告:滥用此功能可能会违反服务提供商的政策并导致帐户被封。
migrate.clone_local_path=或服务器本地路径
migrate.permission_denied=您没有获得导入本地仓库的权限。
migrate.permission_denied_blocked=您不能从不允许的主机导入,请询问管理员以检查 ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS 设置。
@@ -1255,7 +1235,6 @@ create_new_repo_command=从命令行创建一个新的仓库
push_exist_repo=从命令行推送已经创建的仓库
empty_message=这个家伙很懒,什么都没有推送。
broken_message=无法读取此仓库下的 Git 数据。 联系此实例的管理员或删除此仓库。
-no_branch=该仓库没有任何分支。
code=代码
code.desc=查看源码、文件、提交和分支。
@@ -1401,8 +1380,6 @@ editor.failed_to_commit=提交更改失败。
editor.failed_to_commit_summary=错误信息:
editor.fork_create=派生仓库以请求变更
-editor.fork_create_description=您不能直接编辑此仓库。您可以派生此仓库,进行编辑并创建一个合并请求。
-editor.fork_edit_description=您不能直接编辑此仓库。 更改将写入您的派生仓库 %s,以便您可以创建一个合并请求。
editor.fork_not_editable=您已经派生了此仓库,但您的派生是不可编辑的。
editor.fork_failed_to_push_branch=推送分支 %s 到仓库失败。
editor.fork_branch_exists=分支「%s」已存在于您的派生仓库中,请选择一个新的分支名称。
@@ -1701,7 +1678,6 @@ issues.lock_no_reason=锁定并限制仅协作者 %s
issues.unlock_comment=解锁此对话 %s
issues.lock_confirm=锁定
issues.unlock_confirm=解锁
-issues.lock.notice_1=- 其他用户不能对这个工单添加新的评论。
issues.lock.notice_2=- 您和仓库其他协作者仍可评论并可见。
issues.lock.notice_3=- 您可以在未来再次解锁这个工单。
issues.unlock.notice_1=- 每个人都可以再次就这一工单发表评论。
@@ -1756,7 +1732,6 @@ issues.due_date_form=yyyy年mm月dd日
issues.due_date_form_add=设置到期时间
issues.due_date_form_edit=编辑
issues.due_date_form_remove=删除
-issues.due_date_not_writer=您需要该仓库的写权限才能更新工单的到期日期。
issues.due_date_not_set=未设置到期时间。
issues.due_date_added=于 %[2]s 设置到期时间为 %[1]s
issues.due_date_modified=将到期日从 %[2]s 修改为 %[1]s %[3]s
@@ -1865,12 +1840,11 @@ pulls.filter_branch=过滤分支
pulls.show_all_commits=显示所有提交
pulls.show_changes_since_your_last_review=显示自您上次审核以来的更改
pulls.showing_only_single_commit=仅显示提交 %[1]s 的更改
-pulls.showing_specified_commit_range=仅显示 %[1]s...%[2]s 之间的更改
+pulls.showing_specified_commit_range=仅显示 %[1]s..%[2]s 之间的更改
pulls.select_commit_hold_shift_for_range=选择提交。按住 Shift + 单击选择一个范围
pulls.review_only_possible_for_full_diff=只有在查看全部差异时才能进行审核
pulls.filter_changes_by_commit=按提交筛选
pulls.nothing_to_compare=分支内容相同,无需创建合并请求。
-pulls.nothing_to_compare_have_tag=所选分支/标签相同。
pulls.nothing_to_compare_and_allow_empty_pr=这些分支是相等的,此合并请求将为空。
pulls.has_pull_request=这些分支之间的合并请求已存在: %[2]s#%[3]d
pulls.create=创建合并请求
@@ -2033,7 +2007,6 @@ milestones.filter_sort.most_issues=工单从多到少
milestones.filter_sort.least_issues=工单从少到多
signing.will_sign=这个提交将用密钥「%s」签名。
-signing.wont_sign.error=在检查提交是否可以被签名时出错。
signing.wont_sign.nokey=没有可用的密钥来签署这个提交。
signing.wont_sign.never=提交从未签名。
signing.wont_sign.always=提交总是签名。
@@ -2124,7 +2097,6 @@ activity.title.releases_1=%d 个发布
activity.title.releases_n=%d 个发布
activity.title.releases_published_by=%[2]s 发布了 %[1]s
activity.published_release_label=已发布
-activity.no_git_activity=在此期间没有任何提交活动。
activity.git_stats_exclude_merges=排除合并后,
activity.git_stats_author_1=%d 位作者
activity.git_stats_author_n=%d 位作者
@@ -2542,7 +2514,6 @@ settings.block_on_official_review_requests_desc=处于评审状态时,即使
settings.block_outdated_branch=如果合并请求已经过时,阻止合并
settings.block_outdated_branch_desc=当头部分支落后基础分支时,不能合并。
settings.block_admin_merge_override=管理员须遵守分支保护规则
-settings.block_admin_merge_override_desc=管理员须遵守分支保护规则,不能规避该规则。
settings.default_branch_desc=请选择一个默认的分支用于合并请求和提交:
settings.merge_style_desc=合并方式
settings.default_merge_style_desc=默认合并风格
@@ -2569,10 +2540,7 @@ settings.matrix.homeserver_url=主服务器网址
settings.matrix.room_id=房间ID
settings.matrix.message_type=消息类型
settings.visibility.private.button=设为私有
-settings.visibility.private.text=将可见性更改为私有不仅会使仓库仅对允许的成员可见,而且可能会消除它与派生仓库、关注者和点赞之间的关系。
settings.visibility.private.bullet_title=将可见性改为私有将会:
-settings.visibility.private.bullet_one=使仓库只对允许的成员可见。
-settings.visibility.private.bullet_two=可能会删除它与 派生仓库、 关注者和 点赞 之间的关系。
settings.visibility.public.button=设为公开
settings.visibility.public.text=将可见性更改为公开会使任何人都可见。
settings.visibility.public.bullet_title=将可见性改为公开将会:
@@ -2827,7 +2795,6 @@ team_permission_desc=权限
team_unit_desc=允许访问仓库单元
team_unit_disabled=(已禁用)
-form.name_been_taken=组织名称「%s」已经被占用。
form.name_reserved=组织名称「%s」是保留的。
form.name_pattern_not_allowed=组织名中不允许使用「%s」格式。
form.create_org_not_allowed=此账号禁止创建组织
@@ -2869,7 +2836,6 @@ settings.delete_notices_2=此操作将永久删除 %s 的所有
settings.delete_notices_3=此操作将永久删除 %s 的所有 软件包。
settings.delete_notices_4=此操作将永久删除 %s 的所有 项目。
settings.confirm_delete_account=确认删除组织
-settings.delete_failed=由于内部错误,删除组织失败
settings.delete_successful=组织 %s 已成功删除。
settings.hooks_desc=在此处添加的 Web 钩子将会应用到该组织下的 所有仓库。
@@ -3019,9 +2985,6 @@ dashboard.resync_all_sshprincipals=使用 Gitea 的 SSH 规则更新「.ssh/auth
dashboard.resync_all_hooks=重新同步所有仓库的 pre-receive、update 和 post-receive 钩子
dashboard.reinit_missing_repos=重新初始化所有丢失的 Git 仓库存在的记录
dashboard.sync_external_users=同步外部用户数据
-dashboard.cleanup_hook_task_table=清理 hook_task 表
-dashboard.cleanup_packages=清理过期的软件包
-dashboard.cleanup_actions=清理过期的工作流资源
dashboard.server_uptime=服务运行时间
dashboard.current_goroutine=当前 Goroutines 数量
dashboard.current_memory_usage=当前内存使用量
@@ -3456,7 +3419,6 @@ monitor.start=开始时间
monitor.execute_time=执行时长
monitor.last_execution_result=结果
monitor.process.cancel=中止进程
-monitor.process.cancel_desc=中止一个进程可能导致数据丢失
monitor.process.children=子进程
monitor.queues=队列
@@ -3728,7 +3690,6 @@ owner.settings.cargo.initialize.success=Cargo 索引已经成功创建。
owner.settings.cargo.rebuild=重建索引
owner.settings.cargo.rebuild.description=如果索引与存储的 Cargo 包不同步,重建可能会有用。
owner.settings.cargo.rebuild.error=无法重建 Cargo 索引: %v
-owner.settings.cargo.rebuild.success=Cargo 索引已成功重建。
owner.settings.cleanuprules.title=管理清理规则
owner.settings.cleanuprules.add=添加清理规则
owner.settings.cleanuprules.edit=编辑清理规则
@@ -3816,7 +3777,6 @@ runners.delete_runner=删除此运行器
runners.delete_runner_success=运行器删除成功
runners.delete_runner_failed=运行器删除失败
runners.delete_runner_header=确认要删除此运行器
-runners.delete_runner_notice=如果一个任务正在运行在此运行器上,它将被终止并标记为失败。它可能会打断正在构建的工作流。
runners.none=无可用运行器
runners.status.unspecified=未知
runners.status.idle=空闲
diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini
index de0a4ed8a83..e383f623e9e 100644
--- a/options/locale/locale_zh-TW.ini
+++ b/options/locale/locale_zh-TW.ini
@@ -128,7 +128,6 @@ pin=固定
unpin=取消固定
artifacts=檔案或工件
-confirm_delete_artifact=你確定要刪除這個檔案 '%s' 嗎?
archived=已封存
@@ -167,7 +166,6 @@ internal_error_skipped=已略過內部錯誤:%s
search=搜尋…
type_tooltip=搜尋類型
fuzzy=模糊
-fuzzy_tooltip=包含與搜尋詞接近的結果
exact=精確
exact_tooltip=只包含完全符合關鍵字的結果
repo_kind=搜尋儲存庫…
@@ -349,7 +347,6 @@ no_reply_address=隱藏電子信箱域名
no_reply_address_helper=作為隱藏電子信箱使用者的域名。例如,如果隱藏的電子信箱域名設定為「noreply.example.org」,帳號「joe」將以「joe@noreply.example.org」的身分登錄到 Git 中。
password_algorithm=密碼雜湊演算法
invalid_password_algorithm=無效的密碼雜湊演算法
-password_algorithm_helper=設定密碼雜湊演算法。演算法有不同的需求與強度。argon2 演算法雖然較安全但會使用大量記憶體,可能不適用於小型系統。
enable_update_checker=啟用更新檢查器
enable_update_checker_helper=定期連線到 gitea.io 檢查更新。
env_config_keys=環境組態設定
@@ -446,7 +443,6 @@ oauth_signin_title=登入以授權連結帳戶
oauth_signin_submit=連結帳戶
oauth.signin.error.access_denied=授權請求被拒絕。
oauth.signin.error.temporarily_unavailable=授權失敗,因為認證伺服器暫時無法使用。請稍後再試。
-oauth_callback_unable_auto_reg=自助註冊已啟用,但是 OAuth2 提供者 %[1]s 回傳的結果缺少欄位:%[2]s,導致無法自動建立帳號。請建立新帳號或是連結至既存的帳號,或是聯絡網站管理者。
openid_connect_submit=連接
openid_connect_title=連接到現有帳戶
openid_connect_desc=所選的 OpenID URI 未知。在這裡連結一個新帳戶。
@@ -459,7 +455,6 @@ email_domain_blacklisted=您無法使用您的電子信箱註冊帳號。
authorize_application=授權應用程式
authorize_redirect_notice=如果您授權此應用程式,您將會被重新導向至 %s。
authorize_application_created_by=此應用程式是由 %s 建立的。
-authorize_application_description=如果您允許,它將能夠讀取和修改您的所有帳戶資訊,包括私有儲存庫和組織。
authorize_title=授權「%s」存取您的帳戶?
authorization_failed=授權失效
authorization_failed_desc=授權失敗,因為我們偵測到無效的請求。請聯絡您欲授權之應用程式的維護人員。
@@ -487,8 +482,6 @@ activate_email.text=請在 %s內點擊下列連結以驗證您的電子
register_notify=歡迎來到 Gitea
register_notify.title=%[1]s,歡迎來到 %[2]s
-register_notify.text_1=這是您在 %s 的註冊確認信!
-register_notify.text_2=您現在可以用帳號 %s 登入。
register_notify.text_3=如果這是由管理員為您建立的帳戶,請先設定您的密碼。
reset_password=救援您的帳戶
@@ -670,7 +663,6 @@ form.name_chars_not_allowed=帳號「%s」包含無效字元。
block.block=封鎖
block.block.user=封鎖使用者
-block.block.org=為組織阻擋使用者
block.block.failure=無法封鎖使用者: %s
block.unblock=解除封鎖
block.unblock.failure=無法解除封鎖使用者: %s
@@ -713,7 +705,6 @@ webauthn=安全金鑰
public_profile=公開的個人資料
biography_placeholder=告訴我們一些關於您的事情吧! (您可以使用 Markdown)
location_placeholder=與其他人分享您的大概位置
-profile_desc=控制您的個人檔案會如何呈現給其她使用者。您的主要電子郵件地址會被用於通知、密碼救援以及網頁上的 Git 操作。
full_name=全名
website=個人網站
location=所在地區
@@ -790,7 +781,6 @@ activations_pending=等待啟用中
can_not_add_email_activations_pending=有一個待處理的啟用,若要新增電子信箱,請幾分鐘後再試。
delete_email=移除
email_deletion=移除電子信箱
-email_deletion_desc=電子信箱和相關資訊將從您的帳戶中刪除,由此電子信箱所提交的 Git 將保持不變,是否繼續?
email_deletion_success=該電子信箱已被刪除
theme_update_success=已更新佈景主題。
theme_update_error=選取的佈景主題不存在。
@@ -973,7 +963,6 @@ webauthn_alternative_tip=您可能需要設定其他的驗證方法。
manage_account_links=管理已連結的帳戶
manage_account_links_desc=這些外部帳戶已連結到您的 Gitea 帳戶。
-account_links_not_available=目前沒有連結到您的 Gitea 帳戶的外部帳戶
link_account=連結帳戶
remove_account_link=刪除已連結的帳戶
remove_account_link_desc=刪除連結帳戶將撤銷其對 Gitea 帳戶的存取權限。是否繼續?
@@ -1030,7 +1019,6 @@ fork_branch=要克隆到 fork 的分支
all_branches=所有分支
view_all_branches=查看所有分支
view_all_tags=查看所有標籤
-fork_no_valid_owners=此儲存庫無法 fork,因為沒有有效的擁有者。
fork.blocked_user=無法 fork 儲存庫,因為您被儲存庫擁有者封鎖。
use_template=使用此範本
open_with_editor=以 %s 開啟
@@ -1074,7 +1062,6 @@ mirror_sync=已同步
mirror_sync_on_commit=推送提交後進行同步
mirror_address=從 URL Clone
mirror_address_desc=在授權資訊中填入必要的資料。
-mirror_address_url_invalid=提供的 URL 無效。您必須正確轉義 URL 的所有組件。
mirror_address_protocol_invalid=提供的 URL 無效。僅可使用 http(s):// 或 git:// 位置進行鏡像。
mirror_lfs=大型檔案存儲 (LFS)
mirror_lfs_desc=啟動 LFS 檔案的鏡像功能。
@@ -1131,8 +1118,6 @@ template.issue_labels=問題標籤
template.one_item=至少須選擇一個範本項目
template.invalid=必須選擇一個儲存庫範本
-archive.title=此儲存庫已封存。您可以查看檔案並進行 Clone,但無法推送或開啟問題或合併請求。
-archive.title_date=此儲存庫已於 %s 封存。您可以查看檔案並進行 Clone,但無法推送或開啟問題或合併請求。
archive.issue.nocomment=此儲存庫已封存,您不能在問題上留言。
archive.pull.nocomment=此儲存庫已封存,您不能在合併請求上留言。
@@ -1161,7 +1146,6 @@ migrate_items_releases=版本發布
migrate_repo=遷移儲存庫
migrate.clone_address=從 URL 遷移 / Clone
migrate.clone_address_desc=現有存儲庫的 HTTP(S) 或 Git Clone URL
-migrate.github_token_desc=由於 GitHub API 的速率限制,您可在此輸入一個或多個由半形逗號「,」分隔的 Token 來加快遷移速度。警告:濫用此功能可能會違反該服務提供者的政策並導致帳戶被封鎖。
migrate.clone_local_path=或者是本地端伺服器路徑
migrate.permission_denied=您並沒有導入本地儲存庫的權限。
migrate.permission_denied_blocked=您無法從未允許的主機匯入,請聯絡管理員檢查以下設定值 ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS
@@ -1642,7 +1626,6 @@ issues.lock_no_reason=鎖定並將對話設為協作者限定 %s
issues.unlock_comment=解鎖這個對話 %s
issues.lock_confirm=鎖定
issues.unlock_confirm=解除鎖定
-issues.lock.notice_1=- 其他使用者不能在這個問題上新增留言。
issues.lock.notice_2=- 你和此儲存庫的協作者依然可留言,其他人也能看到。
issues.lock.notice_3=- 你以後可以隨時再解鎖這個問題。
issues.unlock.notice_1=- 所有人將可對此問題再次發表留言。
@@ -1690,7 +1673,6 @@ issues.due_date_form=yyyy年mm月dd日
issues.due_date_form_add=新增截止日期
issues.due_date_form_edit=編輯
issues.due_date_form_remove=移除
-issues.due_date_not_writer=您需要對此儲存庫的寫入權限才能更新問題的截止日期。
issues.due_date_not_set=未設定截止日期。
issues.due_date_added=新增了截止日期 %s %s
issues.due_date_modified=將截止日期從 %[2]s 修改為 %[1]s %[3]s
@@ -1804,7 +1786,6 @@ pulls.select_commit_hold_shift_for_range=選擇提交。按住 Shift 並點擊
pulls.review_only_possible_for_full_diff=僅在查看完整差異時才能進行審核
pulls.filter_changes_by_commit=按提交篩選變更
pulls.nothing_to_compare=這些分支的內容相同,無需建立合併請求。
-pulls.nothing_to_compare_have_tag=所選的分支/標籤相同。
pulls.nothing_to_compare_and_allow_empty_pr=這些分支的內容相同,此合併請求將會是空白的。
pulls.has_pull_request=`已有介於這些分支間的合併請求:%[2]s#%[3]d`
pulls.create=建立合併請求
@@ -1960,7 +1941,6 @@ milestones.filter_sort.most_issues=問題由多到少
milestones.filter_sort.least_issues=問題由少到多
signing.will_sign=此提交將使用金鑰「%s」簽署。
-signing.wont_sign.error=檢查提交是否可以簽署時發生錯誤。
signing.wont_sign.nokey=沒有可用的金鑰來簽署此提交。
signing.wont_sign.never=提交從不簽署。
signing.wont_sign.always=提交總是簽署。
@@ -2051,7 +2031,6 @@ activity.title.releases_1=%d 個版本
activity.title.releases_n=%d 個版本
activity.title.releases_published_by=%[2]s發布了 %[1]s
activity.published_release_label=已發布
-activity.no_git_activity=期間內沒有任何提交動態
activity.git_stats_exclude_merges=不計合併,
activity.git_stats_author_1=%d 位作者
activity.git_stats_author_n=%d 位作者
@@ -2450,7 +2429,6 @@ settings.block_on_official_review_requests_desc=如果有官方的審核請求
settings.block_outdated_branch=如果合併請求已經過時則阻擋合併
settings.block_outdated_branch_desc=當 head 分支落後於基礎分支時不得合併。
settings.block_admin_merge_override=管理員必須遵守分支保護規則
-settings.block_admin_merge_override_desc=管理員必須遵守分支保護規則,不能繞過它。
settings.default_branch_desc=請選擇用來提交程式碼和合併請求的預設分支。
settings.merge_style_desc=合併方式
settings.default_merge_style_desc=預設合併方式
@@ -2477,10 +2455,7 @@ settings.matrix.homeserver_url=主伺服器網址
settings.matrix.room_id=聊天室 ID
settings.matrix.message_type=訊息類型
settings.visibility.private.button=設為私人
-settings.visibility.private.text=將可見性更改為私人不僅會使儲存庫僅對允許的成員可見,還可能會移除它與 fork、關注者和星標之間的關係。
settings.visibility.private.bullet_title=更改可見性為私人將:
-settings.visibility.private.bullet_one=使儲存庫僅對允許的成員可見。
-settings.visibility.private.bullet_two=可能會移除它與 fork、關注者 和 星標 之間的關係。
settings.visibility.public.button=設為公開
settings.visibility.public.text=將可見性更改為公開將使儲存庫對任何人可見。
settings.visibility.public.bullet_title=更改可見性為公開將:
@@ -2891,9 +2866,6 @@ dashboard.resync_all_sshprincipals=使用 Gitea 的 SSH 主體更新「.ssh/auth
dashboard.resync_all_hooks=重新同步所有儲存庫的 pre-receive、update 和 post-receive Hook。
dashboard.reinit_missing_repos=重新初始化所有記錄存在但遺失的 Git 儲存庫
dashboard.sync_external_users=同步外部使用者資料
-dashboard.cleanup_hook_task_table=清理 hook_task 資料表
-dashboard.cleanup_packages=清理已過期的套件
-dashboard.cleanup_actions=清理過期的操作資源
dashboard.server_uptime=服務執行時間
dashboard.current_goroutine=目前的 Goroutines 數量
dashboard.current_memory_usage=目前記憶體使用量
@@ -3326,7 +3298,6 @@ monitor.start=開始時間
monitor.execute_time=已執行時間
monitor.last_execution_result=結果
monitor.process.cancel=結束處理程序
-monitor.process.cancel_desc=結束處理程序可能造成資料遺失
monitor.process.children=子程序
monitor.queues=佇列
@@ -3595,7 +3566,6 @@ owner.settings.cargo.initialize.success=成功建立了 Cargo 索引。
owner.settings.cargo.rebuild=重建索引
owner.settings.cargo.rebuild.description=如果索引與儲存的 Cargo 套件不同步,重建索引可能會有幫助。
owner.settings.cargo.rebuild.error=重建 Cargo 索引失敗: %v
-owner.settings.cargo.rebuild.success=成功重建了 Cargo 索引。
owner.settings.cleanuprules.title=管理清理規則
owner.settings.cleanuprules.add=加入清理規則
owner.settings.cleanuprules.edit=編輯清理規則
@@ -3678,7 +3648,6 @@ runners.delete_runner=刪除此 Runner
runners.delete_runner_success=刪除 Runner 成功
runners.delete_runner_failed=刪除 Runner 失敗
runners.delete_runner_header=確認刪除此 Runner
-runners.delete_runner_notice=如果有任務正在此 Runner 上執行,它可能會被中止並標記為失敗,這可能會打斷建置工作流程。
runners.none=沒有可用的 Runner
runners.status.unspecified=未知
runners.status.idle=閒置
diff --git a/poetry.lock b/poetry.lock
deleted file mode 100644
index 7c3f6901756..00000000000
--- a/poetry.lock
+++ /dev/null
@@ -1,426 +0,0 @@
-# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
-
-[[package]]
-name = "click"
-version = "8.1.8"
-description = "Composable command line interface toolkit"
-optional = false
-python-versions = ">=3.7"
-groups = ["dev"]
-files = [
- {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
- {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
-]
-
-[package.dependencies]
-colorama = {version = "*", markers = "platform_system == \"Windows\""}
-
-[[package]]
-name = "colorama"
-version = "0.4.6"
-description = "Cross-platform colored terminal text."
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
-groups = ["dev"]
-files = [
- {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
- {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
-]
-
-[[package]]
-name = "cssbeautifier"
-version = "1.15.4"
-description = "CSS unobfuscator and beautifier."
-optional = false
-python-versions = "*"
-groups = ["dev"]
-files = [
- {file = "cssbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:78c84d5e5378df7d08622bbd0477a1abdbd209680e95480bf22f12d5701efc98"},
- {file = "cssbeautifier-1.15.4.tar.gz", hash = "sha256:9bb08dc3f64c101a01677f128acf01905914cf406baf87434dcde05b74c0acf5"},
-]
-
-[package.dependencies]
-editorconfig = ">=0.12.2"
-jsbeautifier = "*"
-six = ">=1.13.0"
-
-[[package]]
-name = "djlint"
-version = "1.36.4"
-description = "HTML Template Linter and Formatter"
-optional = false
-python-versions = ">=3.9"
-groups = ["dev"]
-files = [
- {file = "djlint-1.36.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a2dfb60883ceb92465201bfd392291a7597c6752baede6fbb6f1980cac8d6c5c"},
- {file = "djlint-1.36.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4bc6a1320c0030244b530ac200642f883d3daa451a115920ef3d56d08b644292"},
- {file = "djlint-1.36.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3164a048c7bb0baf042387b1e33f9bbbf99d90d1337bb4c3d66eb0f96f5400a1"},
- {file = "djlint-1.36.4-cp310-cp310-win_amd64.whl", hash = "sha256:3196d5277da5934962d67ad6c33a948ba77a7b6eadf064648bef6ee5f216b03c"},
- {file = "djlint-1.36.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d68da0ed10ee9ca1e32e225cbb8e9b98bf7e6f8b48a8e4836117b6605b88cc7"},
- {file = "djlint-1.36.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c0478d5392247f1e6ee29220bbdbf7fb4e1bc0e7e83d291fda6fb926c1787ba7"},
- {file = "djlint-1.36.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:962f7b83aee166e499eff916d631c6dde7f1447d7610785a60ed2a75a5763483"},
- {file = "djlint-1.36.4-cp311-cp311-win_amd64.whl", hash = "sha256:53cbc450aa425c832f09bc453b8a94a039d147b096740df54a3547fada77ed08"},
- {file = "djlint-1.36.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff9faffd7d43ac20467493fa71d5355b5b330a00ade1c4d1e859022f4195223b"},
- {file = "djlint-1.36.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:79489e262b5ac23a8dfb7ca37f1eea979674cfc2d2644f7061d95bea12c38f7e"},
- {file = "djlint-1.36.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e58c5fa8c6477144a0be0a87273706a059e6dd0d6efae01146ae8c29cdfca675"},
- {file = "djlint-1.36.4-cp312-cp312-win_amd64.whl", hash = "sha256:bb6903777bf3124f5efedcddf1f4716aef097a7ec4223fc0fa54b865829a6e08"},
- {file = "djlint-1.36.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ead475013bcac46095b1bbc8cf97ed2f06e83422335734363f8a76b4ba7e47c2"},
- {file = "djlint-1.36.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6c601dfa68ea253311deb4a29a7362b7a64933bdfcfb5a06618f3e70ad1fa835"},
- {file = "djlint-1.36.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bda5014f295002363381969864addeb2db13955f1b26e772657c3b273ed7809f"},
- {file = "djlint-1.36.4-cp313-cp313-win_amd64.whl", hash = "sha256:16ce37e085afe5a30953b2bd87cbe34c37843d94c701fc68a2dda06c1e428ff4"},
- {file = "djlint-1.36.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:89678661888c03d7bc6cadd75af69db29962b5ecbf93a81518262f5c48329f04"},
- {file = "djlint-1.36.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b01a98df3e1ab89a552793590875bc6e954cad661a9304057db75363d519fa0"},
- {file = "djlint-1.36.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dabbb4f7b93223d471d09ae34ed515fef98b2233cbca2449ad117416c44b1351"},
- {file = "djlint-1.36.4-cp39-cp39-win_amd64.whl", hash = "sha256:7a483390d17e44df5bc23dcea29bdf6b63f3ed8b4731d844773a4829af4f5e0b"},
- {file = "djlint-1.36.4-py3-none-any.whl", hash = "sha256:e9699b8ac3057a6ed04fb90835b89bee954ed1959c01541ce4f8f729c938afdd"},
- {file = "djlint-1.36.4.tar.gz", hash = "sha256:17254f218b46fe5a714b224c85074c099bcb74e3b2e1f15c2ddc2cf415a408a1"},
-]
-
-[package.dependencies]
-click = ">=8.0.1"
-colorama = ">=0.4.4"
-cssbeautifier = ">=1.14.4"
-jsbeautifier = ">=1.14.4"
-json5 = ">=0.9.11"
-pathspec = ">=0.12"
-pyyaml = ">=6"
-regex = ">=2023"
-tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
-tqdm = ">=4.62.2"
-typing-extensions = {version = ">=3.6.6", markers = "python_version < \"3.11\""}
-
-[[package]]
-name = "editorconfig"
-version = "0.17.0"
-description = "EditorConfig File Locator and Interpreter for Python"
-optional = false
-python-versions = "*"
-groups = ["dev"]
-files = [
- {file = "EditorConfig-0.17.0-py3-none-any.whl", hash = "sha256:fe491719c5f65959ec00b167d07740e7ffec9a3f362038c72b289330b9991dfc"},
- {file = "editorconfig-0.17.0.tar.gz", hash = "sha256:8739052279699840065d3a9f5c125d7d5a98daeefe53b0e5274261d77cb49aa2"},
-]
-
-[[package]]
-name = "jsbeautifier"
-version = "1.15.4"
-description = "JavaScript unobfuscator and beautifier."
-optional = false
-python-versions = "*"
-groups = ["dev"]
-files = [
- {file = "jsbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:72f65de312a3f10900d7685557f84cb61a9733c50dcc27271a39f5b0051bf528"},
- {file = "jsbeautifier-1.15.4.tar.gz", hash = "sha256:5bb18d9efb9331d825735fbc5360ee8f1aac5e52780042803943aa7f854f7592"},
-]
-
-[package.dependencies]
-editorconfig = ">=0.12.2"
-six = ">=1.13.0"
-
-[[package]]
-name = "json5"
-version = "0.12.0"
-description = "A Python implementation of the JSON5 data format."
-optional = false
-python-versions = ">=3.8.0"
-groups = ["dev"]
-files = [
- {file = "json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db"},
- {file = "json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a"},
-]
-
-[package.extras]
-dev = ["build (==1.2.2.post1)", "coverage (==7.5.4) ; python_version < \"3.9\"", "coverage (==7.8.0) ; python_version >= \"3.9\"", "mypy (==1.14.1) ; python_version < \"3.9\"", "mypy (==1.15.0) ; python_version >= \"3.9\"", "pip (==25.0.1)", "pylint (==3.2.7) ; python_version < \"3.9\"", "pylint (==3.3.6) ; python_version >= \"3.9\"", "ruff (==0.11.2)", "twine (==6.1.0)", "uv (==0.6.11)"]
-
-[[package]]
-name = "pathspec"
-version = "0.12.1"
-description = "Utility library for gitignore style pattern matching of file paths."
-optional = false
-python-versions = ">=3.8"
-groups = ["dev"]
-files = [
- {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
- {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
-]
-
-[[package]]
-name = "pyyaml"
-version = "6.0.2"
-description = "YAML parser and emitter for Python"
-optional = false
-python-versions = ">=3.8"
-groups = ["dev"]
-files = [
- {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
- {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
- {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"},
- {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"},
- {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"},
- {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"},
- {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"},
- {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"},
- {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"},
- {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"},
- {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"},
- {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"},
- {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"},
- {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"},
- {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"},
- {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"},
- {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"},
- {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"},
- {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"},
- {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"},
- {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"},
- {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"},
- {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"},
- {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"},
- {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"},
- {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"},
- {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"},
- {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"},
- {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"},
- {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"},
- {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"},
- {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"},
- {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"},
- {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"},
- {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"},
- {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"},
- {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"},
- {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"},
- {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"},
- {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"},
- {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"},
- {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"},
- {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"},
- {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"},
- {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"},
- {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"},
- {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"},
- {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"},
- {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"},
- {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"},
- {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"},
- {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"},
- {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
-]
-
-[[package]]
-name = "regex"
-version = "2024.11.6"
-description = "Alternative regular expression module, to replace re."
-optional = false
-python-versions = ">=3.8"
-groups = ["dev"]
-files = [
- {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"},
- {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"},
- {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"},
- {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"},
- {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"},
- {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"},
- {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"},
- {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"},
- {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"},
- {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"},
- {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"},
- {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"},
- {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"},
- {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"},
- {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"},
- {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"},
- {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"},
- {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"},
- {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"},
- {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"},
- {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"},
- {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"},
- {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"},
- {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"},
- {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"},
- {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"},
- {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"},
- {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"},
- {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"},
- {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"},
- {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"},
- {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"},
- {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"},
- {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"},
- {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"},
- {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"},
- {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"},
- {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"},
- {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"},
- {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"},
- {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"},
- {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"},
- {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"},
- {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"},
- {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"},
- {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"},
- {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"},
- {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"},
- {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"},
- {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"},
- {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"},
- {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"},
- {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"},
- {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"},
- {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"},
- {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"},
- {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"},
- {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"},
- {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"},
- {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"},
- {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"},
- {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"},
- {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"},
- {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"},
- {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"},
- {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"},
- {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"},
- {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"},
- {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"},
- {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"},
- {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"},
- {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"},
- {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"},
- {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"},
- {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"},
- {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"},
- {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"},
- {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"},
- {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"},
- {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"},
- {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"},
- {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"},
- {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"},
- {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"},
- {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"},
- {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"},
- {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"},
- {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"},
- {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"},
- {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"},
- {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"},
- {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"},
- {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"},
- {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"},
-]
-
-[[package]]
-name = "six"
-version = "1.17.0"
-description = "Python 2 and 3 compatibility utilities"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
-groups = ["dev"]
-files = [
- {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
- {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
-]
-
-[[package]]
-name = "tomli"
-version = "2.2.1"
-description = "A lil' TOML parser"
-optional = false
-python-versions = ">=3.8"
-groups = ["dev"]
-markers = "python_version == \"3.10\""
-files = [
- {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
- {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
- {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
- {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
- {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
- {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
- {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
- {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
- {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
- {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
- {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
- {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
- {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
- {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
- {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
- {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
- {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
- {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
- {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
- {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
- {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
- {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
- {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
- {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
- {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
- {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
- {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
- {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
- {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
- {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
- {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
- {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
-]
-
-[[package]]
-name = "tqdm"
-version = "4.67.1"
-description = "Fast, Extensible Progress Meter"
-optional = false
-python-versions = ">=3.7"
-groups = ["dev"]
-files = [
- {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"},
- {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"},
-]
-
-[package.dependencies]
-colorama = {version = "*", markers = "platform_system == \"Windows\""}
-
-[package.extras]
-dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"]
-discord = ["requests"]
-notebook = ["ipywidgets (>=6)"]
-slack = ["slack-sdk"]
-telegram = ["requests"]
-
-[[package]]
-name = "typing-extensions"
-version = "4.13.2"
-description = "Backported and Experimental Type Hints for Python 3.8+"
-optional = false
-python-versions = ">=3.8"
-groups = ["dev"]
-markers = "python_version == \"3.10\""
-files = [
- {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"},
- {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"},
-]
-
-[[package]]
-name = "yamllint"
-version = "1.37.1"
-description = "A linter for YAML files."
-optional = false
-python-versions = ">=3.9"
-groups = ["dev"]
-files = [
- {file = "yamllint-1.37.1-py3-none-any.whl", hash = "sha256:364f0d79e81409f591e323725e6a9f4504c8699ddf2d7263d8d2b539cd66a583"},
- {file = "yamllint-1.37.1.tar.gz", hash = "sha256:81f7c0c5559becc8049470d86046b36e96113637bcbe4753ecef06977c00245d"},
-]
-
-[package.dependencies]
-pathspec = ">=0.5.3"
-pyyaml = "*"
-
-[package.extras]
-dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"]
-
-[metadata]
-lock-version = "2.1"
-python-versions = "^3.10"
-content-hash = "ec65cbc253ccb822e50bb7bdb9a3185a5ab781024175a4d5a339055a06207af6"
diff --git a/pyproject.toml b/pyproject.toml
index 439b9a6fbd5..3657feb2ce3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,12 +1,13 @@
-[tool.poetry]
-package-mode = false
+[project]
+name = "gitea"
+version = "0.0.0"
+requires-python = ">=3.10"
-[tool.poetry.dependencies]
-python = "^3.10"
-
-[tool.poetry.group.dev.dependencies]
-djlint = "1.36.4"
-yamllint = "1.37.1"
+[dependency-groups]
+dev = [
+ "djlint==1.36.4",
+ "yamllint==1.37.1",
+]
[tool.djlint]
profile="golang"
diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go
index 6473659e5cb..d71a6f487cb 100644
--- a/routers/api/actions/artifacts.go
+++ b/routers/api/actions/artifacts.go
@@ -428,7 +428,7 @@ func (ar artifactRoutes) getDownloadArtifactURL(ctx *ArtifactContext) {
for _, artifact := range artifacts {
var downloadURL string
if setting.Actions.ArtifactStorage.ServeDirect() {
- u, err := ar.fs.URL(artifact.StoragePath, artifact.ArtifactName, nil)
+ u, err := ar.fs.URL(artifact.StoragePath, artifact.ArtifactName, ctx.Req.Method, nil)
if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
log.Error("Error getting serve direct url: %v", err)
}
diff --git a/routers/api/actions/artifactsv4.go b/routers/api/actions/artifactsv4.go
index e9e9fc63934..6d274796285 100644
--- a/routers/api/actions/artifactsv4.go
+++ b/routers/api/actions/artifactsv4.go
@@ -517,7 +517,7 @@ func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) {
respData := GetSignedArtifactURLResponse{}
if setting.Actions.ArtifactStorage.ServeDirect() {
- u, err := storage.ActionsArtifacts.URL(artifact.StoragePath, artifact.ArtifactPath, nil)
+ u, err := storage.ActionsArtifacts.URL(artifact.StoragePath, artifact.ArtifactPath, ctx.Req.Method, nil)
if u != nil && err == nil {
respData.SignedUrl = u.String()
}
diff --git a/routers/api/packages/alpine/alpine.go b/routers/api/packages/alpine/alpine.go
index ba4a4f23ce2..f250a1a5494 100644
--- a/routers/api/packages/alpine/alpine.go
+++ b/routers/api/packages/alpine/alpine.go
@@ -25,9 +25,8 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.PlainText(status, message)
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.PlainText(status, message)
}
func GetRepositoryKey(ctx *context.Context) {
@@ -75,6 +74,7 @@ func GetRepositoryFile(ctx *context.Context) {
Filename: alpine_service.IndexArchiveFilename,
CompositeKey: fmt.Sprintf("%s|%s|%s", ctx.PathParam("branch"), ctx.PathParam("repository"), ctx.PathParam("architecture")),
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
@@ -216,7 +216,7 @@ func DownloadPackageFile(ctx *context.Context) {
}
}
- s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0])
+ s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
apiError(ctx, http.StatusNotFound, err)
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go
index 878e0f99452..f6ee5958b5b 100644
--- a/routers/api/packages/api.go
+++ b/routers/api/packages/api.go
@@ -99,7 +99,7 @@ func verifyAuth(r *web.Router, authMethods []auth.Method) {
ctx.Doer, err = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
if err != nil {
log.Error("Failed to verify user: %v", err)
- ctx.HTTPError(http.StatusUnauthorized, "authGroup.Verify")
+ ctx.HTTPError(http.StatusUnauthorized, "Failed to authenticate user")
return
}
ctx.IsSigned = ctx.Doer != nil
@@ -339,7 +339,7 @@ func CommonRoutes() *web.Router {
r.Group("/{packagename}/{packageversion}", func() {
r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage)
r.Group("/{filename}", func() {
- r.Get("", generic.DownloadPackageFile)
+ r.Methods("HEAD,GET", "", generic.DownloadPackageFile)
r.Group("", func() {
r.Put("", generic.UploadPackage)
r.Delete("", generic.DeletePackageFile)
diff --git a/routers/api/packages/arch/arch.go b/routers/api/packages/arch/arch.go
index bf9cc3f1b84..061484785da 100644
--- a/routers/api/packages/arch/arch.go
+++ b/routers/api/packages/arch/arch.go
@@ -24,9 +24,8 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.PlainText(status, message)
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.PlainText(status, message)
}
func GetRepositoryKey(ctx *context.Context) {
@@ -239,7 +238,7 @@ func GetPackageOrRepositoryFile(ctx *context.Context) {
return
}
- s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0])
+ s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
apiError(ctx, http.StatusNotFound, err)
diff --git a/routers/api/packages/cargo/cargo.go b/routers/api/packages/cargo/cargo.go
index cfcf79244f5..a7f00ee1cbe 100644
--- a/routers/api/packages/cargo/cargo.go
+++ b/routers/api/packages/cargo/cargo.go
@@ -37,15 +37,14 @@ type StatusMessage struct {
}
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.JSON(status, StatusResponse{
- OK: false,
- Errors: []StatusMessage{
- {
- Message: message,
- },
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.JSON(status, StatusResponse{
+ OK: false,
+ Errors: []StatusMessage{
+ {
+ Message: message,
},
- })
+ },
})
}
@@ -176,6 +175,7 @@ func DownloadPackageFile(ctx *context.Context) {
&packages_service.PackageFileInfo{
Filename: strings.ToLower(fmt.Sprintf("%s-%s.crate", ctx.PathParam("package"), ctx.PathParam("version"))),
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
diff --git a/routers/api/packages/chef/chef.go b/routers/api/packages/chef/chef.go
index 1f11afe5486..50011ab0b17 100644
--- a/routers/api/packages/chef/chef.go
+++ b/routers/api/packages/chef/chef.go
@@ -30,10 +30,9 @@ func apiError(ctx *context.Context, status int, obj any) {
ErrorMessages []string `json:"error_messages"`
}
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.JSON(status, Error{
- ErrorMessages: []string{message},
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.JSON(status, Error{
+ ErrorMessages: []string{message},
})
}
@@ -343,7 +342,7 @@ func DownloadPackage(ctx *context.Context) {
pf := pd.Files[0].File
- s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
+ s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go
index 9daf0ffeff7..df04f49d2d5 100644
--- a/routers/api/packages/composer/composer.go
+++ b/routers/api/packages/composer/composer.go
@@ -28,18 +28,17 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- type Error struct {
- Status int `json:"status"`
- Message string `json:"message"`
- }
- ctx.JSON(status, struct {
- Errors []Error `json:"errors"`
- }{
- Errors: []Error{
- {Status: status, Message: message},
- },
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ type Error struct {
+ Status int `json:"status"`
+ Message string `json:"message"`
+ }
+ ctx.JSON(status, struct {
+ Errors []Error `json:"errors"`
+ }{
+ Errors: []Error{
+ {Status: status, Message: message},
+ },
})
}
@@ -171,6 +170,7 @@ func DownloadPackageFile(ctx *context.Context) {
&packages_service.PackageFileInfo{
Filename: ctx.PathParam("filename"),
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
diff --git a/routers/api/packages/conan/auth.go b/routers/api/packages/conan/auth.go
index 9c03d01391f..bce3235a2ea 100644
--- a/routers/api/packages/conan/auth.go
+++ b/routers/api/packages/conan/auth.go
@@ -34,7 +34,6 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS
u, err := user_model.GetUserByID(req.Context(), packageMeta.UserID)
if err != nil {
- log.Error("GetUserByID: %v", err)
return nil, err
}
if packageMeta.Scope != "" {
diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go
index fe70e02cd6f..126b1593cde 100644
--- a/routers/api/packages/conan/conan.go
+++ b/routers/api/packages/conan/conan.go
@@ -55,16 +55,13 @@ func jsonResponse(ctx *context.Context, status int, obj any) {
// https://github.com/conan-io/conan/issues/6613
ctx.Resp.Header().Set("Content-Type", "application/json")
ctx.Status(status)
- if err := json.NewEncoder(ctx.Resp).Encode(obj); err != nil {
- log.Error("JSON encode: %v", err)
- }
+ _ = json.NewEncoder(ctx.Resp).Encode(obj)
}
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- jsonResponse(ctx, status, map[string]string{
- "message": message,
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ jsonResponse(ctx, status, map[string]string{
+ "message": message,
})
}
@@ -393,7 +390,6 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey
if isConanfileFile {
metadata, err := conan_module.ParseConanfile(buf)
if err != nil {
- log.Error("Error parsing package metadata: %v", err)
apiError(ctx, http.StatusInternalServerError, err)
return
}
@@ -419,7 +415,6 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey
} else {
info, err := conan_module.ParseConaninfo(buf)
if err != nil {
- log.Error("Error parsing conan info: %v", err)
apiError(ctx, http.StatusInternalServerError, err)
return
}
@@ -492,6 +487,7 @@ func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKe
Filename: filename,
CompositeKey: fileKey,
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
diff --git a/routers/api/packages/conda/conda.go b/routers/api/packages/conda/conda.go
index e8c97503c85..f496002bb5a 100644
--- a/routers/api/packages/conda/conda.go
+++ b/routers/api/packages/conda/conda.go
@@ -13,7 +13,6 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
conda_model "code.gitea.io/gitea/models/packages/conda"
"code.gitea.io/gitea/modules/json"
- "code.gitea.io/gitea/modules/log"
packages_module "code.gitea.io/gitea/modules/packages"
conda_module "code.gitea.io/gitea/modules/packages/conda"
"code.gitea.io/gitea/modules/util"
@@ -25,14 +24,13 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.JSON(status, struct {
- Reason string `json:"reason"`
- Message string `json:"message"`
- }{
- Reason: http.StatusText(status),
- Message: message,
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.JSON(status, struct {
+ Reason string `json:"reason"`
+ Message string `json:"message"`
+ }{
+ Reason: http.StatusText(status),
+ Message: message,
})
}
@@ -185,10 +183,7 @@ func EnumeratePackages(ctx *context.Context) {
}
resp.WriteHeader(http.StatusOK)
-
- if err := json.NewEncoder(w).Encode(repoData); err != nil {
- log.Error("JSON encode: %v", err)
- }
+ _ = json.NewEncoder(w).Encode(repoData)
}
func UploadPackageFile(ctx *context.Context) {
@@ -317,7 +312,7 @@ func DownloadPackageFile(ctx *context.Context) {
pf := pfs[0]
- s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
+ s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
diff --git a/routers/api/packages/container/auth.go b/routers/api/packages/container/auth.go
index 1e1b87eb799..19a931c4057 100644
--- a/routers/api/packages/container/auth.go
+++ b/routers/api/packages/container/auth.go
@@ -35,7 +35,6 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS
u, err := user_model.GetPossibleUserByID(req.Context(), packageMeta.UserID)
if err != nil {
- log.Error("GetPossibleUserByID: %v", err)
return nil, err
}
diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go
index d532f698adf..db81dd13c28 100644
--- a/routers/api/packages/container/container.go
+++ b/routers/api/packages/container/container.go
@@ -93,10 +93,9 @@ func jsonResponse(ctx *context.Context, status int, obj any) {
}
func apiError(ctx *context.Context, status int, err error) {
- helper.LogAndProcessError(ctx, status, err, func(message string) {
- setResponseHeaders(ctx.Resp, &containerHeaders{
- Status: status,
- })
+ _ = helper.ProcessErrorForUser(ctx, status, err)
+ setResponseHeaders(ctx.Resp, &containerHeaders{
+ Status: status,
})
}
@@ -449,9 +448,9 @@ func PutBlobsUpload(ctx *context.Context) {
return
}
- // There was a strange bug: the "Close" fails with error "close .../tmp/package-upload/....: file already closed"
- // AFAIK there should be no other "Close" call to the uploader between NewBlobUploader and this line.
- // At least it's safe to call Close twice, so ignore the error.
+ // Some SDK (e.g.: minio) will close the Reader if it is also a Closer after "uploading".
+ // And we don't need to wrap the reader to anything else because the SDK will benefit from other interfaces like Seeker.
+ // It's safe to call Close twice, so ignore the error.
_ = uploader.Close()
if err := container_service.RemoveBlobUploadByID(ctx, uploader.ID); err != nil {
@@ -710,7 +709,7 @@ func DeleteManifest(ctx *context.Context) {
func serveBlob(ctx *context.Context, pfd *packages_model.PackageFileDescriptor) {
serveDirectReqParams := make(url.Values)
serveDirectReqParams.Set("response-content-type", pfd.Properties.GetByName(container_module.PropertyMediaType))
- s, u, _, err := packages_service.OpenBlobForDownload(ctx, pfd.File, pfd.Blob, serveDirectReqParams)
+ s, u, _, err := packages_service.OpenBlobForDownload(ctx, pfd.File, pfd.Blob, ctx.Req.Method, serveDirectReqParams)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
@@ -734,9 +733,7 @@ func serveBlob(ctx *context.Context, pfd *packages_model.PackageFileDescriptor)
defer s.Close()
setResponseHeaders(ctx.Resp, headers)
- if _, err := io.Copy(ctx.Resp, s); err != nil {
- log.Error("Error whilst copying content to response: %v", err)
- }
+ _, _ = io.Copy(ctx.Resp, s)
}
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#content-discovery
diff --git a/routers/api/packages/cran/cran.go b/routers/api/packages/cran/cran.go
index 732acd215f6..323690fd52d 100644
--- a/routers/api/packages/cran/cran.go
+++ b/routers/api/packages/cran/cran.go
@@ -22,9 +22,8 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.PlainText(status, message)
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.PlainText(status, message)
}
func EnumerateSourcePackages(ctx *context.Context) {
@@ -250,7 +249,7 @@ func downloadPackageFile(ctx *context.Context, opts *cran_model.SearchOptions) {
return
}
- s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
+ s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
apiError(ctx, http.StatusNotFound, err)
diff --git a/routers/api/packages/debian/debian.go b/routers/api/packages/debian/debian.go
index 346f71fa5d4..82c7952bdbb 100644
--- a/routers/api/packages/debian/debian.go
+++ b/routers/api/packages/debian/debian.go
@@ -24,9 +24,8 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.PlainText(status, message)
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.PlainText(status, message)
}
func GetRepositoryKey(ctx *context.Context) {
@@ -66,6 +65,7 @@ func GetRepositoryFile(ctx *context.Context) {
Filename: ctx.PathParam("filename"),
CompositeKey: key,
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
@@ -106,7 +106,7 @@ func GetRepositoryFileByHash(ctx *context.Context) {
return
}
- s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0])
+ s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
apiError(ctx, http.StatusNotFound, err)
@@ -222,6 +222,7 @@ func DownloadPackageFile(ctx *context.Context) {
Filename: fmt.Sprintf("%s_%s_%s.deb", name, version, ctx.PathParam("architecture")),
CompositeKey: fmt.Sprintf("%s|%s", ctx.PathParam("distribution"), ctx.PathParam("component")),
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go
index db7aeace50c..5eb189e6d9c 100644
--- a/routers/api/packages/generic/generic.go
+++ b/routers/api/packages/generic/generic.go
@@ -11,7 +11,6 @@ import (
"unicode"
packages_model "code.gitea.io/gitea/models/packages"
- "code.gitea.io/gitea/modules/log"
packages_module "code.gitea.io/gitea/modules/packages"
"code.gitea.io/gitea/routers/api/packages/helper"
"code.gitea.io/gitea/services/context"
@@ -24,9 +23,8 @@ var (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.PlainText(status, message)
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.PlainText(status, message)
}
// DownloadPackageFile serves the specific generic package.
@@ -42,6 +40,7 @@ func DownloadPackageFile(ctx *context.Context) {
&packages_service.PackageFileInfo{
Filename: ctx.PathParam("filename"),
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
@@ -101,7 +100,6 @@ func UploadPackage(ctx *context.Context) {
buf, err := packages_module.CreateHashedBufferFromReader(upload)
if err != nil {
- log.Error("Error creating hashed buffer: %v", err)
apiError(ctx, http.StatusInternalServerError, err)
return
}
diff --git a/routers/api/packages/goproxy/goproxy.go b/routers/api/packages/goproxy/goproxy.go
index 89ec86bce95..951f50053c3 100644
--- a/routers/api/packages/goproxy/goproxy.go
+++ b/routers/api/packages/goproxy/goproxy.go
@@ -22,9 +22,8 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.PlainText(status, message)
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.PlainText(status, message)
}
func EnumeratePackageVersions(ctx *context.Context) {
@@ -106,7 +105,7 @@ func DownloadPackageFile(ctx *context.Context) {
return
}
- s, u, _, err := packages_service.OpenFileForDownload(ctx, pfs[0])
+ s, u, _, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
apiError(ctx, http.StatusNotFound, err)
diff --git a/routers/api/packages/helm/helm.go b/routers/api/packages/helm/helm.go
index 39c34f4da4e..4c1b72d5c01 100644
--- a/routers/api/packages/helm/helm.go
+++ b/routers/api/packages/helm/helm.go
@@ -14,7 +14,6 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/json"
- "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
helm_module "code.gitea.io/gitea/modules/packages/helm"
@@ -28,13 +27,12 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- type Error struct {
- Error string `json:"error"`
- }
- ctx.JSON(status, Error{
- Error: message,
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ type Error struct {
+ Error string `json:"error"`
+ }
+ ctx.JSON(status, Error{
+ Error: message,
})
}
@@ -87,16 +85,14 @@ func Index(ctx *context.Context) {
}
ctx.Resp.WriteHeader(http.StatusOK)
- if err := yaml.NewEncoder(ctx.Resp).Encode(&Index{
+ _ = yaml.NewEncoder(ctx.Resp).Encode(&Index{
APIVersion: "v1",
Entries: entries,
Generated: time.Now(),
ServerInfo: &ServerInfo{
ContextPath: setting.AppSubURL + "/api/packages/" + url.PathEscape(ctx.Package.Owner.Name) + "/helm",
},
- }); err != nil {
- log.Error("YAML encode failed: %v", err)
- }
+ })
}
// DownloadPackageFile serves the content of a package
@@ -128,6 +124,7 @@ func DownloadPackageFile(ctx *context.Context) {
&packages_service.PackageFileInfo{
Filename: filename,
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
diff --git a/routers/api/packages/helper/helper.go b/routers/api/packages/helper/helper.go
index cdb64109ade..27d4e6ffdc6 100644
--- a/routers/api/packages/helper/helper.go
+++ b/routers/api/packages/helper/helper.go
@@ -15,31 +15,29 @@ import (
"code.gitea.io/gitea/services/context"
)
-// LogAndProcessError logs an error and calls a custom callback with the processed error message.
-// If the error is an InternalServerError the message is stripped if the user is not an admin.
-func LogAndProcessError(ctx *context.Context, status int, obj any, cb func(string)) {
+// ProcessErrorForUser logs the error and returns a user-error message for the end user.
+// If the status is http.StatusInternalServerError, the message is stripped for non-admin users in production.
+func ProcessErrorForUser(ctx *context.Context, status int, errObj any) string {
var message string
- if err, ok := obj.(error); ok {
+ if err, ok := errObj.(error); ok {
message = err.Error()
- } else if obj != nil {
- message = fmt.Sprintf("%s", obj)
+ } else if errObj != nil {
+ message = fmt.Sprint(errObj)
}
+
if status == http.StatusInternalServerError {
- log.ErrorWithSkip(1, message)
-
+ log.Log(2, log.ERROR, "Package registry API internal error: %d %s", status, message)
if setting.IsProd && (ctx.Doer == nil || !ctx.Doer.IsAdmin) {
- message = ""
+ message = "internal server error"
}
- } else {
- log.Debug(message)
+ return message
}
- if cb != nil {
- cb(message)
- }
+ log.Log(2, log.DEBUG, "Package registry API user error: %d %s", status, message)
+ return message
}
-// Serves the content of the package file
+// ServePackageFile the content of the package file
// If the url is set it will redirect the request, otherwise the content is copied to the response.
func ServePackageFile(ctx *context.Context, s io.ReadSeekCloser, u *url.URL, pf *packages_model.PackageFile, forceOpts ...*context.ServeHeaderOptions) {
if u != nil {
diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go
index 40a8ff82421..6c2916908b6 100644
--- a/routers/api/packages/maven/maven.go
+++ b/routers/api/packages/maven/maven.go
@@ -22,7 +22,6 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/json"
- "code.gitea.io/gitea/modules/log"
packages_module "code.gitea.io/gitea/modules/packages"
maven_module "code.gitea.io/gitea/modules/packages/maven"
"code.gitea.io/gitea/modules/util"
@@ -49,14 +48,9 @@ var (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- // The maven client does not present the error message to the user. Log it for users with access to server logs.
- if status == http.StatusBadRequest || status == http.StatusInternalServerError {
- log.Error(message)
- }
-
- ctx.PlainText(status, message)
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ // Maven client doesn't present the error message to end users; site admin can check the server logs that outputted by ProcessErrorForUser
+ ctx.PlainText(status, message)
}
// DownloadPackageFile serves the content of a package
@@ -223,7 +217,7 @@ func servePackageFile(ctx *context.Context, params parameters, serveContent bool
return
}
- s, u, _, err := packages_service.OpenBlobForDownload(ctx, pf, pb, nil)
+ s, u, _, err := packages_service.OpenBlobForDownload(ctx, pf, pb, ctx.Req.Method, nil)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go
index 1f09816d325..cc2aff8ea01 100644
--- a/routers/api/packages/npm/npm.go
+++ b/routers/api/packages/npm/npm.go
@@ -33,10 +33,9 @@ import (
var errInvalidTagName = errors.New("The tag name is invalid")
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.JSON(status, map[string]string{
- "error": message,
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.JSON(status, map[string]string{
+ "error": message,
})
}
@@ -96,6 +95,7 @@ func DownloadPackageFile(ctx *context.Context) {
&packages_service.PackageFileInfo{
Filename: filename,
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
@@ -138,6 +138,7 @@ func DownloadPackageFileByName(ctx *context.Context) {
&packages_service.PackageFileInfo{
Filename: filename,
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
diff --git a/routers/api/packages/nuget/auth.go b/routers/api/packages/nuget/auth.go
index e81ad01b2b3..ce7df0ce0a0 100644
--- a/routers/api/packages/nuget/auth.go
+++ b/routers/api/packages/nuget/auth.go
@@ -26,7 +26,6 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS
token, err := auth_model.GetAccessTokenBySHA(req.Context(), req.Header.Get("X-NuGet-ApiKey"))
if err != nil {
if !(auth_model.IsErrAccessTokenNotExist(err) || auth_model.IsErrAccessTokenEmpty(err)) {
- log.Error("GetAccessTokenBySHA: %v", err)
return nil, err
}
return nil, nil
@@ -34,7 +33,6 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS
u, err := user_model.GetUserByID(req.Context(), token.UID)
if err != nil {
- log.Error("GetUserByID: %v", err)
return nil, err
}
diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go
index 92d62d90b1f..c42fdd7db53 100644
--- a/routers/api/packages/nuget/nuget.go
+++ b/routers/api/packages/nuget/nuget.go
@@ -17,7 +17,6 @@ import (
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
nuget_model "code.gitea.io/gitea/models/packages/nuget"
- "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
@@ -29,22 +28,17 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.JSON(status, map[string]string{
- "Message": message,
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.JSON(status, map[string]string{
+ "Message": message,
})
}
func xmlResponse(ctx *context.Context, status int, obj any) { //nolint:unparam // status is always StatusOK
ctx.Resp.Header().Set("Content-Type", "application/atom+xml; charset=utf-8")
ctx.Resp.WriteHeader(status)
- if _, err := ctx.Resp.Write([]byte(xml.Header)); err != nil {
- log.Error("Write failed: %v", err)
- }
- if err := xml.NewEncoder(ctx.Resp).Encode(obj); err != nil {
- log.Error("XML encode failed: %v", err)
- }
+ _, _ = ctx.Resp.Write([]byte(xml.Header))
+ _ = xml.NewEncoder(ctx.Resp).Encode(obj)
}
// https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Protocol/LegacyFeed/V2FeedQueryBuilder.cs
@@ -416,6 +410,7 @@ func DownloadPackageFile(ctx *context.Context) {
&packages_service.PackageFileInfo{
Filename: filename,
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
@@ -669,7 +664,7 @@ func DownloadSymbolFile(ctx *context.Context) {
return
}
- s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0])
+ s, u, pf, err := packages_service.OpenFileForDownload(ctx, pfs[0], ctx.Req.Method)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
apiError(ctx, http.StatusNotFound, err)
diff --git a/routers/api/packages/pub/pub.go b/routers/api/packages/pub/pub.go
index 4bd36e94b64..7564e14d0e8 100644
--- a/routers/api/packages/pub/pub.go
+++ b/routers/api/packages/pub/pub.go
@@ -15,7 +15,6 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/json"
- "code.gitea.io/gitea/modules/log"
packages_module "code.gitea.io/gitea/modules/packages"
pub_module "code.gitea.io/gitea/modules/packages/pub"
"code.gitea.io/gitea/modules/setting"
@@ -29,9 +28,7 @@ func jsonResponse(ctx *context.Context, status int, obj any) {
resp := ctx.Resp
resp.Header().Set("Content-Type", "application/vnd.pub.v2+json")
resp.WriteHeader(status)
- if err := json.NewEncoder(resp).Encode(obj); err != nil {
- log.Error("JSON encode: %v", err)
- }
+ _ = json.NewEncoder(resp).Encode(obj)
}
func apiError(ctx *context.Context, status int, obj any) {
@@ -43,13 +40,12 @@ func apiError(ctx *context.Context, status int, obj any) {
Error Error `json:"error"`
}
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- jsonResponse(ctx, status, ErrorWrapper{
- Error: Error{
- Code: http.StatusText(status),
- Message: message,
- },
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ jsonResponse(ctx, status, ErrorWrapper{
+ Error: Error{
+ Code: http.StatusText(status),
+ Message: message,
+ },
})
}
@@ -274,7 +270,7 @@ func DownloadPackageFile(ctx *context.Context) {
pf := pd.Files[0].File
- s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
+ s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go
index 9b5ae6c89d4..1b8f4bea34a 100644
--- a/routers/api/packages/pypi/pypi.go
+++ b/routers/api/packages/pypi/pypi.go
@@ -40,9 +40,8 @@ var versionMatcher = regexp.MustCompile(`\Av?` +
`\z`)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.PlainText(status, message)
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.PlainText(status, message)
}
// PackageMetadata returns the metadata for a single package
@@ -93,6 +92,7 @@ func DownloadPackageFile(ctx *context.Context) {
&packages_service.PackageFileInfo{
Filename: filename,
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go
index 938c35341d0..5abbb0c8ae6 100644
--- a/routers/api/packages/rpm/rpm.go
+++ b/routers/api/packages/rpm/rpm.go
@@ -26,9 +26,8 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.PlainText(status, message)
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.PlainText(status, message)
}
// https://dnf.readthedocs.io/en/latest/conf_ref.html
@@ -103,6 +102,7 @@ func GetRepositoryFile(ctx *context.Context) {
Filename: ctx.PathParam("filename"),
CompositeKey: ctx.PathParam("group"),
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
@@ -232,6 +232,7 @@ func DownloadPackageFile(ctx *context.Context) {
Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.PathParam("architecture")),
CompositeKey: ctx.PathParam("group"),
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go
index 774d5520fda..1ecf93592e1 100644
--- a/routers/api/packages/rubygems/rubygems.go
+++ b/routers/api/packages/rubygems/rubygems.go
@@ -25,9 +25,8 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.PlainText(status, message)
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.PlainText(status, message)
}
// EnumeratePackages serves the package list
@@ -184,6 +183,7 @@ func DownloadPackageFile(ctx *context.Context) {
&packages_service.PackageFileInfo{
Filename: filename,
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
diff --git a/routers/api/packages/swift/swift.go b/routers/api/packages/swift/swift.go
index bf542f33a7c..e1c3b368345 100644
--- a/routers/api/packages/swift/swift.go
+++ b/routers/api/packages/swift/swift.go
@@ -77,17 +77,14 @@ func apiError(ctx *context.Context, status int, obj any) {
Detail string `json:"detail"`
}
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- setResponseHeaders(ctx.Resp, &headers{
- Status: status,
- ContentType: "application/problem+json",
- })
- if err := json.NewEncoder(ctx.Resp).Encode(Problem{
- Status: status,
- Detail: message,
- }); err != nil {
- log.Error("JSON encode: %v", err)
- }
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ setResponseHeaders(ctx.Resp, &headers{
+ Status: status,
+ ContentType: "application/problem+json",
+ })
+ _ = json.NewEncoder(ctx.Resp).Encode(Problem{
+ Status: status,
+ Detail: message,
})
}
@@ -429,7 +426,7 @@ func DownloadPackageFile(ctx *context.Context) {
pf := pd.Files[0].File
- s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
+ s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
diff --git a/routers/api/packages/vagrant/vagrant.go b/routers/api/packages/vagrant/vagrant.go
index 9eb67e53973..36fc41f5819 100644
--- a/routers/api/packages/vagrant/vagrant.go
+++ b/routers/api/packages/vagrant/vagrant.go
@@ -24,14 +24,13 @@ import (
)
func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.JSON(status, struct {
- Errors []string `json:"errors"`
- }{
- Errors: []string{
- message,
- },
- })
+ message := helper.ProcessErrorForUser(ctx, status, obj)
+ ctx.JSON(status, struct {
+ Errors []string `json:"errors"`
+ }{
+ Errors: []string{
+ message,
+ },
})
}
@@ -229,6 +228,7 @@ func DownloadPackageFile(ctx *context.Context) {
&packages_service.PackageFileInfo{
Filename: ctx.PathParam("provider"),
},
+ ctx.Req.Method,
)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go
index 8a267cc418d..494bace5851 100644
--- a/routers/api/v1/admin/user.go
+++ b/routers/api/v1/admin/user.go
@@ -240,7 +240,7 @@ func EditUser(ctx *context.APIContext) {
Description: optional.FromPtr(form.Description),
IsActive: optional.FromPtr(form.Active),
IsAdmin: user_service.UpdateOptionFieldFromPtr(form.Admin),
- Visibility: optional.FromNonDefault(api.VisibilityModes[form.Visibility]),
+ Visibility: optional.FromMapLookup(api.VisibilityModes, form.Visibility),
AllowGitHook: optional.FromPtr(form.AllowGitHook),
AllowImportLocal: optional.FromPtr(form.AllowImportLocal),
MaxRepoCreation: optional.FromPtr(form.MaxRepoCreation),
diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go
index 05744ba1552..cd676860658 100644
--- a/routers/api/v1/org/org.go
+++ b/routers/api/v1/org/org.go
@@ -391,7 +391,7 @@ func Edit(ctx *context.APIContext) {
Description: optional.Some(form.Description),
Website: optional.Some(form.Website),
Location: optional.Some(form.Location),
- Visibility: optional.FromNonDefault(api.VisibilityModes[form.Visibility]),
+ Visibility: optional.FromMapLookup(api.VisibilityModes, form.Visibility),
RepoAdminChangeTeamAccess: optional.FromPtr(form.RepoAdminChangeTeamAccess),
}
if err := user_service.UpdateUser(ctx, ctx.Org.Organization.AsUser(), opts); err != nil {
diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go
index a57db015f02..ef0c5cc1995 100644
--- a/routers/api/v1/repo/action.go
+++ b/routers/api/v1/repo/action.go
@@ -747,7 +747,7 @@ func (Action) ListWorkflowRuns(ctx *context.APIContext) {
// type: integer
// responses:
// "200":
- // "$ref": "#/responses/ArtifactsList"
+ // "$ref": "#/responses/WorkflowRunsList"
// "400":
// "$ref": "#/responses/error"
// "404":
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index 69b59962229..a85dda79d00 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -210,7 +210,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
if setting.LFS.Storage.ServeDirect() {
// If we have a signed url (S3, object storage), redirect to this directly.
- u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name(), nil)
+ u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name(), ctx.Req.Method, nil)
if u != nil && err == nil {
ctx.Redirect(u.String())
return
@@ -331,7 +331,7 @@ func download(ctx *context.APIContext, archiveName string, archiver *repo_model.
rPath := archiver.RelativePath()
if setting.RepoArchive.Storage.ServeDirect() {
// If we have a signed url (S3, object storage), redirect to this directly.
- u, err := storage.RepoArchives.URL(rPath, downloadName, nil)
+ u, err := storage.RepoArchives.URL(rPath, downloadName, ctx.Req.Method, nil)
if u != nil && err == nil {
ctx.Redirect(u.String())
return
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index 2c194f92535..e05b9b165c2 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -1461,9 +1461,9 @@ func GetPullRequestCommits(ctx *context.APIContext) {
defer closer.Close()
if pr.HasMerged {
- prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), false, false)
+ prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitHeadRefName(), false, false)
} else {
- prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), false, false)
+ prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitHeadRefName(), false, false)
}
if err != nil {
ctx.APIErrorInternal(err)
@@ -1584,16 +1584,16 @@ func GetPullRequestFiles(ctx *context.APIContext) {
var prInfo *git.CompareInfo
if pr.HasMerged {
- prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true, false)
+ prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitHeadRefName(), true, false)
} else {
- prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true, false)
+ prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitHeadRefName(), true, false)
}
if err != nil {
ctx.APIErrorInternal(err)
return
}
- headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
+ headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
ctx.APIErrorInternal(err)
return
diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go
index 9421a052db5..3c00193fac1 100644
--- a/routers/api/v1/repo/pull_review.go
+++ b/routers/api/v1/repo/pull_review.go
@@ -336,7 +336,7 @@ func CreatePullReview(ctx *context.APIContext) {
}
defer closer.Close()
- headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
+ headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
ctx.APIErrorInternal(err)
return
@@ -455,7 +455,7 @@ func SubmitPullReview(ctx *context.APIContext) {
return
}
- headCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(pr.GetGitRefName())
+ headCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
ctx.APIErrorInternal(err)
return
diff --git a/routers/api/v1/swagger/action.go b/routers/api/v1/swagger/action.go
index 16a250184ad..06065059502 100644
--- a/routers/api/v1/swagger/action.go
+++ b/routers/api/v1/swagger/action.go
@@ -44,5 +44,5 @@ type swaggerResponseActionWorkflow struct {
// swagger:response ActionWorkflowList
type swaggerResponseActionWorkflowList struct {
// in:body
- Body []api.ActionWorkflow `json:"body"`
+ Body api.ActionWorkflowResponse `json:"body"`
}
diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go
index 0f6f31b8841..56c384b9709 100644
--- a/routers/web/admin/auths.go
+++ b/routers/web/admin/auths.go
@@ -199,6 +199,9 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
AdminGroup: form.Oauth2AdminGroup,
GroupTeamMap: form.Oauth2GroupTeamMap,
GroupTeamMapRemoval: form.Oauth2GroupTeamMapRemoval,
+
+ SSHPublicKeyClaimName: form.Oauth2SSHPublicKeyClaimName,
+ FullNameClaimName: form.Oauth2FullNameClaimName,
}
}
diff --git a/routers/web/auth/2fa.go b/routers/web/auth/2fa.go
index d15d33dfd45..1f087a78971 100644
--- a/routers/web/auth/2fa.go
+++ b/routers/web/auth/2fa.go
@@ -14,7 +14,6 @@ import (
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
- "code.gitea.io/gitea/services/externalaccount"
"code.gitea.io/gitea/services/forms"
)
@@ -75,7 +74,7 @@ func TwoFactorPost(ctx *context.Context) {
}
if ctx.Session.Get("linkAccount") != nil {
- err = externalaccount.LinkAccountFromStore(ctx, ctx.Session, u)
+ err = linkAccountFromContext(ctx, u)
if err != nil {
ctx.ServerError("UserSignIn", err)
return
diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go
index 94f75f69ffe..2ccd1c71b5c 100644
--- a/routers/web/auth/auth.go
+++ b/routers/web/auth/auth.go
@@ -329,6 +329,7 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
"twofaUid",
"twofaRemember",
"linkAccount",
+ "linkAccountData",
}, map[string]any{
session.KeyUID: u.ID,
session.KeyUname: u.Name,
@@ -519,7 +520,7 @@ func SignUpPost(ctx *context.Context) {
Passwd: form.Password,
}
- if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, nil, false) {
+ if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, nil) {
// error already handled
return
}
@@ -530,22 +531,22 @@ func SignUpPost(ctx *context.Context) {
// createAndHandleCreatedUser calls createUserInContext and
// then handleUserCreated.
-func createAndHandleCreatedUser(ctx *context.Context, tpl templates.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) bool {
- if !createUserInContext(ctx, tpl, form, u, overwrites, gothUser, allowLink) {
+func createAndHandleCreatedUser(ctx *context.Context, tpl templates.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, possibleLinkAccountData *LinkAccountData) bool {
+ if !createUserInContext(ctx, tpl, form, u, overwrites, possibleLinkAccountData) {
return false
}
- return handleUserCreated(ctx, u, gothUser)
+ return handleUserCreated(ctx, u, possibleLinkAccountData)
}
// createUserInContext creates a user and handles errors within a given context.
-// Optionally a template can be specified.
-func createUserInContext(ctx *context.Context, tpl templates.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) {
+// Optionally, a template can be specified.
+func createUserInContext(ctx *context.Context, tpl templates.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, possibleLinkAccountData *LinkAccountData) (ok bool) {
meta := &user_model.Meta{
InitialIP: ctx.RemoteAddr(),
InitialUserAgent: ctx.Req.UserAgent(),
}
if err := user_model.CreateUser(ctx, u, meta, overwrites); err != nil {
- if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) {
+ if possibleLinkAccountData != nil && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) {
switch setting.OAuth2Client.AccountLinking {
case setting.OAuth2AccountLinkingAuto:
var user *user_model.User
@@ -561,15 +562,15 @@ func createUserInContext(ctx *context.Context, tpl templates.TplName, form any,
}
// TODO: probably we should respect 'remember' user's choice...
- linkAccount(ctx, user, *gothUser, true)
+ oauth2LinkAccount(ctx, user, possibleLinkAccountData, true)
return false // user is already created here, all redirects are handled
case setting.OAuth2AccountLinkingLogin:
- showLinkingLogin(ctx, *gothUser)
+ showLinkingLogin(ctx, possibleLinkAccountData.AuthSourceID, possibleLinkAccountData.GothUser)
return false // user will be created only after linking login
}
}
- // handle error without template
+ // handle error without a template
if len(tpl) == 0 {
ctx.ServerError("CreateUser", err)
return false
@@ -610,7 +611,7 @@ func createUserInContext(ctx *context.Context, tpl templates.TplName, form any,
// handleUserCreated does additional steps after a new user is created.
// It auto-sets admin for the only user, updates the optional external user and
// sends a confirmation email if required.
-func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.User) (ok bool) {
+func handleUserCreated(ctx *context.Context, u *user_model.User, possibleLinkAccountData *LinkAccountData) (ok bool) {
// Auto-set admin for the only user.
hasUsers, err := user_model.HasUsers(ctx)
if err != nil {
@@ -631,8 +632,8 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.
}
// update external user information
- if gothUser != nil {
- if err := externalaccount.EnsureLinkExternalToUser(ctx, u, *gothUser); err != nil {
+ if possibleLinkAccountData != nil {
+ if err := externalaccount.EnsureLinkExternalToUser(ctx, possibleLinkAccountData.AuthSourceID, u, possibleLinkAccountData.GothUser); err != nil {
log.Error("EnsureLinkExternalToUser failed: %v", err)
}
}
diff --git a/routers/web/auth/auth_test.go b/routers/web/auth/auth_test.go
index e238125407b..a0fd5c0e506 100644
--- a/routers/web/auth/auth_test.go
+++ b/routers/web/auth/auth_test.go
@@ -64,13 +64,14 @@ func TestUserLogin(t *testing.T) {
func TestSignUpOAuth2Login(t *testing.T) {
defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)()
+ _ = oauth2.Init(t.Context())
addOAuth2Source(t, "dummy-auth-source", oauth2.Source{})
t.Run("OAuth2MissingField", func(t *testing.T) {
defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
return goth.User{Provider: "dummy-auth-source", UserID: "dummy-user"}, nil
})()
- mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")}
+ mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockMemStore("dummy-sid")}
ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback?code=dummy-code", mockOpt)
ctx.SetPathParam("provider", "dummy-auth-source")
SignInOAuthCallback(ctx)
@@ -84,7 +85,7 @@ func TestSignUpOAuth2Login(t *testing.T) {
})
t.Run("OAuth2CallbackError", func(t *testing.T) {
- mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")}
+ mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockMemStore("dummy-sid")}
ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback", mockOpt)
ctx.SetPathParam("provider", "dummy-auth-source")
SignInOAuthCallback(ctx)
diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go
index b3c61946b91..c624d896ca7 100644
--- a/routers/web/auth/linkaccount.go
+++ b/routers/web/auth/linkaccount.go
@@ -5,7 +5,6 @@ package auth
import (
"errors"
- "fmt"
"net/http"
"strings"
@@ -21,8 +20,6 @@ import (
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/externalaccount"
"code.gitea.io/gitea/services/forms"
-
- "github.com/markbates/goth"
)
var tplLinkAccount templates.TplName = "user/auth/link_account"
@@ -52,28 +49,28 @@ func LinkAccount(ctx *context.Context) {
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin"
ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/link_account_signup"
- gothUser, ok := ctx.Session.Get("linkAccountGothUser").(goth.User)
+ linkAccountData := oauth2GetLinkAccountData(ctx)
// If you'd like to quickly debug the "link account" page layout, just uncomment the blow line
// Don't worry, when the below line exists, the lint won't pass: ineffectual assignment to gothUser (ineffassign)
- // gothUser, ok = goth.User{Email: "invalid-email", Name: "."}, true // intentionally use invalid data to avoid pass the registration check
+ // linkAccountData = &LinkAccountData{authSource, gothUser} // intentionally use invalid data to avoid pass the registration check
- if !ok {
+ if linkAccountData == nil {
// no account in session, so just redirect to the login page, then the user could restart the process
ctx.Redirect(setting.AppSubURL + "/user/login")
return
}
- if missingFields, ok := gothUser.RawData["__giteaAutoRegMissingFields"].([]string); ok {
- ctx.Data["AutoRegistrationFailedPrompt"] = ctx.Tr("auth.oauth_callback_unable_auto_reg", gothUser.Provider, strings.Join(missingFields, ","))
+ if missingFields, ok := linkAccountData.GothUser.RawData["__giteaAutoRegMissingFields"].([]string); ok {
+ ctx.Data["AutoRegistrationFailedPrompt"] = ctx.Tr("auth.oauth_callback_unable_auto_reg", linkAccountData.GothUser.Provider, strings.Join(missingFields, ","))
}
- uname, err := extractUserNameFromOAuth2(&gothUser)
+ uname, err := extractUserNameFromOAuth2(&linkAccountData.GothUser)
if err != nil {
ctx.ServerError("UserSignIn", err)
return
}
- email := gothUser.Email
+ email := linkAccountData.GothUser.Email
ctx.Data["user_name"] = uname
ctx.Data["email"] = email
@@ -152,8 +149,8 @@ func LinkAccountPostSignIn(ctx *context.Context) {
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin"
ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/link_account_signup"
- gothUser := ctx.Session.Get("linkAccountGothUser")
- if gothUser == nil {
+ linkAccountData := oauth2GetLinkAccountData(ctx)
+ if linkAccountData == nil {
ctx.ServerError("UserSignIn", errors.New("not in LinkAccount session"))
return
}
@@ -169,11 +166,14 @@ func LinkAccountPostSignIn(ctx *context.Context) {
return
}
- linkAccount(ctx, u, gothUser.(goth.User), signInForm.Remember)
+ oauth2LinkAccount(ctx, u, linkAccountData, signInForm.Remember)
}
-func linkAccount(ctx *context.Context, u *user_model.User, gothUser goth.User, remember bool) {
- updateAvatarIfNeed(ctx, gothUser.AvatarURL, u)
+func oauth2LinkAccount(ctx *context.Context, u *user_model.User, linkAccountData *LinkAccountData, remember bool) {
+ oauth2SignInSync(ctx, linkAccountData.AuthSourceID, u, linkAccountData.GothUser)
+ if ctx.Written() {
+ return
+ }
// If this user is enrolled in 2FA, we can't sign the user in just yet.
// Instead, redirect them to the 2FA authentication page.
@@ -185,7 +185,7 @@ func linkAccount(ctx *context.Context, u *user_model.User, gothUser goth.User, r
return
}
- err = externalaccount.LinkAccountToUser(ctx, u, gothUser)
+ err = externalaccount.LinkAccountToUser(ctx, linkAccountData.AuthSourceID, u, linkAccountData.GothUser)
if err != nil {
ctx.ServerError("UserLinkAccount", err)
return
@@ -243,17 +243,11 @@ func LinkAccountPostRegister(ctx *context.Context) {
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin"
ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/link_account_signup"
- gothUserInterface := ctx.Session.Get("linkAccountGothUser")
- if gothUserInterface == nil {
+ linkAccountData := oauth2GetLinkAccountData(ctx)
+ if linkAccountData == nil {
ctx.ServerError("UserSignUp", errors.New("not in LinkAccount session"))
return
}
- gothUser, ok := gothUserInterface.(goth.User)
- if !ok {
- ctx.ServerError("UserSignUp", fmt.Errorf("session linkAccountGothUser type is %t but not goth.User", gothUserInterface))
- return
- }
-
if ctx.HasError() {
ctx.HTML(http.StatusOK, tplLinkAccount)
return
@@ -296,31 +290,38 @@ func LinkAccountPostRegister(ctx *context.Context) {
}
}
- authSource, err := auth.GetActiveOAuth2SourceByName(ctx, gothUser.Provider)
- if err != nil {
- ctx.ServerError("CreateUser", err)
- return
- }
-
u := &user_model.User{
Name: form.UserName,
Email: form.Email,
Passwd: form.Password,
LoginType: auth.OAuth2,
- LoginSource: authSource.ID,
- LoginName: gothUser.UserID,
+ LoginSource: linkAccountData.AuthSourceID,
+ LoginName: linkAccountData.GothUser.UserID,
}
- if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, nil, &gothUser, false) {
+ if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, nil, linkAccountData) {
// error already handled
return
}
+ authSource, err := auth.GetSourceByID(ctx, linkAccountData.AuthSourceID)
+ if err != nil {
+ ctx.ServerError("GetSourceByID", err)
+ return
+ }
source := authSource.Cfg.(*oauth2.Source)
- if err := syncGroupsToTeams(ctx, source, &gothUser, u); err != nil {
+ if err := syncGroupsToTeams(ctx, source, &linkAccountData.GothUser, u); err != nil {
ctx.ServerError("SyncGroupsToTeams", err)
return
}
handleSignIn(ctx, u, false)
}
+
+func linkAccountFromContext(ctx *context.Context, user *user_model.User) error {
+ linkAccountData := oauth2GetLinkAccountData(ctx)
+ if linkAccountData == nil {
+ return errors.New("not in LinkAccount session")
+ }
+ return externalaccount.LinkAccountToUser(ctx, linkAccountData.AuthSourceID, user, linkAccountData.GothUser)
+}
diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go
index a13b987aabe..f1c155e78f5 100644
--- a/routers/web/auth/oauth.go
+++ b/routers/web/auth/oauth.go
@@ -4,6 +4,7 @@
package auth
import (
+ "encoding/gob"
"errors"
"fmt"
"html"
@@ -20,7 +21,6 @@ import (
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/web/middleware"
source_service "code.gitea.io/gitea/services/auth/source"
"code.gitea.io/gitea/services/auth/source/oauth2"
@@ -35,9 +35,8 @@ import (
// SignInOAuth handles the OAuth2 login buttons
func SignInOAuth(ctx *context.Context) {
- provider := ctx.PathParam("provider")
-
- authSource, err := auth.GetActiveOAuth2SourceByName(ctx, provider)
+ authName := ctx.PathParam("provider")
+ authSource, err := auth.GetActiveOAuth2SourceByAuthName(ctx, authName)
if err != nil {
ctx.ServerError("SignIn", err)
return
@@ -74,8 +73,6 @@ func SignInOAuth(ctx *context.Context) {
// SignInOAuthCallback handles the callback from the given provider
func SignInOAuthCallback(ctx *context.Context) {
- provider := ctx.PathParam("provider")
-
if ctx.Req.FormValue("error") != "" {
var errorKeyValues []string
for k, vv := range ctx.Req.Form {
@@ -88,7 +85,8 @@ func SignInOAuthCallback(ctx *context.Context) {
}
// first look if the provider is still active
- authSource, err := auth.GetActiveOAuth2SourceByName(ctx, provider)
+ authName := ctx.PathParam("provider")
+ authSource, err := auth.GetActiveOAuth2SourceByAuthName(ctx, authName)
if err != nil {
ctx.ServerError("SignIn", err)
return
@@ -133,7 +131,7 @@ func SignInOAuthCallback(ctx *context.Context) {
if u == nil {
if ctx.Doer != nil {
// attach user to the current signed-in user
- err = externalaccount.LinkAccountToUser(ctx, ctx.Doer, gothUser)
+ err = externalaccount.LinkAccountToUser(ctx, authSource.ID, ctx.Doer, gothUser)
if err != nil {
ctx.ServerError("UserLinkAccount", err)
return
@@ -174,12 +172,11 @@ func SignInOAuthCallback(ctx *context.Context) {
gothUser.RawData = make(map[string]any)
}
gothUser.RawData["__giteaAutoRegMissingFields"] = missingFields
- showLinkingLogin(ctx, gothUser)
+ showLinkingLogin(ctx, authSource.ID, gothUser)
return
}
u = &user_model.User{
Name: uname,
- FullName: gothUser.Name,
Email: gothUser.Email,
LoginType: auth.OAuth2,
LoginSource: authSource.ID,
@@ -196,7 +193,11 @@ func SignInOAuthCallback(ctx *context.Context) {
u.IsAdmin = isAdmin.ValueOrDefault(user_service.UpdateOptionField[bool]{FieldValue: false}).FieldValue
u.IsRestricted = isRestricted.ValueOrDefault(setting.Service.DefaultUserIsRestricted)
- if !createAndHandleCreatedUser(ctx, templates.TplName(""), nil, u, overwriteDefault, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) {
+ linkAccountData := &LinkAccountData{authSource.ID, gothUser}
+ if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingDisabled {
+ linkAccountData = nil
+ }
+ if !createAndHandleCreatedUser(ctx, "", nil, u, overwriteDefault, linkAccountData) {
// error already handled
return
}
@@ -207,7 +208,7 @@ func SignInOAuthCallback(ctx *context.Context) {
}
} else {
// no existing user is found, request attach or new account
- showLinkingLogin(ctx, gothUser)
+ showLinkingLogin(ctx, authSource.ID, gothUser)
return
}
}
@@ -271,17 +272,36 @@ func getUserAdminAndRestrictedFromGroupClaims(source *oauth2.Source, gothUser *g
return isAdmin, isRestricted
}
-func showLinkingLogin(ctx *context.Context, gothUser goth.User) {
- if err := updateSession(ctx, nil, map[string]any{
- "linkAccountGothUser": gothUser,
- }); err != nil {
- ctx.ServerError("updateSession", err)
+type LinkAccountData struct {
+ AuthSourceID int64
+ GothUser goth.User
+}
+
+func oauth2GetLinkAccountData(ctx *context.Context) *LinkAccountData {
+ gob.Register(LinkAccountData{})
+ v, ok := ctx.Session.Get("linkAccountData").(LinkAccountData)
+ if !ok {
+ return nil
+ }
+ return &v
+}
+
+func Oauth2SetLinkAccountData(ctx *context.Context, linkAccountData LinkAccountData) error {
+ gob.Register(LinkAccountData{})
+ return updateSession(ctx, nil, map[string]any{
+ "linkAccountData": linkAccountData,
+ })
+}
+
+func showLinkingLogin(ctx *context.Context, authSourceID int64, gothUser goth.User) {
+ if err := Oauth2SetLinkAccountData(ctx, LinkAccountData{authSourceID, gothUser}); err != nil {
+ ctx.ServerError("Oauth2SetLinkAccountData", err)
return
}
ctx.Redirect(setting.AppSubURL + "/user/link_account")
}
-func updateAvatarIfNeed(ctx *context.Context, url string, u *user_model.User) {
+func oauth2UpdateAvatarIfNeed(ctx *context.Context, url string, u *user_model.User) {
if setting.OAuth2Client.UpdateAvatar && len(url) > 0 {
resp, err := http.Get(url)
if err == nil {
@@ -299,11 +319,14 @@ func updateAvatarIfNeed(ctx *context.Context, url string, u *user_model.User) {
}
}
-func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model.User, gothUser goth.User) {
- updateAvatarIfNeed(ctx, gothUser.AvatarURL, u)
+func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_model.User, gothUser goth.User) {
+ oauth2SignInSync(ctx, authSource.ID, u, gothUser)
+ if ctx.Written() {
+ return
+ }
needs2FA := false
- if !source.TwoFactorShouldSkip() {
+ if !authSource.TwoFactorShouldSkip() {
_, err := auth.GetTwoFactorByUID(ctx, u.ID)
if err != nil && !auth.IsErrTwoFactorNotEnrolled(err) {
ctx.ServerError("UserSignIn", err)
@@ -312,7 +335,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
needs2FA = err == nil
}
- oauth2Source := source.Cfg.(*oauth2.Source)
+ oauth2Source := authSource.Cfg.(*oauth2.Source)
groupTeamMapping, err := auth_module.UnmarshalGroupTeamMapping(oauth2Source.GroupTeamMap)
if err != nil {
ctx.ServerError("UnmarshalGroupTeamMapping", err)
@@ -338,7 +361,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
}
}
- if err := externalaccount.EnsureLinkExternalToUser(ctx, u, gothUser); err != nil {
+ if err := externalaccount.EnsureLinkExternalToUser(ctx, authSource.ID, u, gothUser); err != nil {
ctx.ServerError("EnsureLinkExternalToUser", err)
return
}
diff --git a/routers/web/auth/oauth_signin_sync.go b/routers/web/auth/oauth_signin_sync.go
new file mode 100644
index 00000000000..86d19660245
--- /dev/null
+++ b/routers/web/auth/oauth_signin_sync.go
@@ -0,0 +1,93 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package auth
+
+import (
+ "fmt"
+
+ asymkey_model "code.gitea.io/gitea/models/asymkey"
+ "code.gitea.io/gitea/models/auth"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/util"
+ asymkey_service "code.gitea.io/gitea/services/asymkey"
+ "code.gitea.io/gitea/services/auth/source/oauth2"
+ "code.gitea.io/gitea/services/context"
+
+ "github.com/markbates/goth"
+)
+
+func oauth2SignInSync(ctx *context.Context, authSourceID int64, u *user_model.User, gothUser goth.User) {
+ oauth2UpdateAvatarIfNeed(ctx, gothUser.AvatarURL, u)
+
+ authSource, err := auth.GetSourceByID(ctx, authSourceID)
+ if err != nil {
+ ctx.ServerError("GetSourceByID", err)
+ return
+ }
+ oauth2Source, _ := authSource.Cfg.(*oauth2.Source)
+ if !authSource.IsOAuth2() || oauth2Source == nil {
+ ctx.ServerError("oauth2SignInSync", fmt.Errorf("source %s is not an OAuth2 source", gothUser.Provider))
+ return
+ }
+
+ // sync full name
+ fullNameKey := util.IfZero(oauth2Source.FullNameClaimName, "name")
+ fullName, _ := gothUser.RawData[fullNameKey].(string)
+ fullName = util.IfZero(fullName, gothUser.Name)
+
+ // need to update if the user has no full name set
+ shouldUpdateFullName := u.FullName == ""
+ // force to update if the attribute is set
+ shouldUpdateFullName = shouldUpdateFullName || oauth2Source.FullNameClaimName != ""
+ // only update if the full name is different
+ shouldUpdateFullName = shouldUpdateFullName && u.FullName != fullName
+ if shouldUpdateFullName {
+ u.FullName = fullName
+ if err := user_model.UpdateUserCols(ctx, u, "full_name"); err != nil {
+ log.Error("Unable to sync OAuth2 user full name %s: %v", gothUser.Provider, err)
+ }
+ }
+
+ err = oauth2UpdateSSHPubIfNeed(ctx, authSource, &gothUser, u)
+ if err != nil {
+ log.Error("Unable to sync OAuth2 SSH public key %s: %v", gothUser.Provider, err)
+ }
+}
+
+func oauth2SyncGetSSHKeys(source *oauth2.Source, gothUser *goth.User) ([]string, error) {
+ value, exists := gothUser.RawData[source.SSHPublicKeyClaimName]
+ if !exists {
+ return []string{}, nil
+ }
+ rawSlice, ok := value.([]any)
+ if !ok {
+ return nil, fmt.Errorf("invalid SSH public key value type: %T", value)
+ }
+
+ sshKeys := make([]string, 0, len(rawSlice))
+ for _, v := range rawSlice {
+ str, ok := v.(string)
+ if !ok {
+ return nil, fmt.Errorf("invalid SSH public key value item type: %T", v)
+ }
+ sshKeys = append(sshKeys, str)
+ }
+ return sshKeys, nil
+}
+
+func oauth2UpdateSSHPubIfNeed(ctx *context.Context, authSource *auth.Source, gothUser *goth.User, user *user_model.User) error {
+ oauth2Source, _ := authSource.Cfg.(*oauth2.Source)
+ if oauth2Source == nil || oauth2Source.SSHPublicKeyClaimName == "" {
+ return nil
+ }
+ sshKeys, err := oauth2SyncGetSSHKeys(oauth2Source, gothUser)
+ if err != nil {
+ return err
+ }
+ if !asymkey_model.SynchronizePublicKeys(ctx, user, authSource, sshKeys) {
+ return nil
+ }
+ return asymkey_service.RewriteAllPublicKeys(ctx)
+}
diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go
index 2ef4a860222..4ef4c96ccc1 100644
--- a/routers/web/auth/openid.go
+++ b/routers/web/auth/openid.go
@@ -361,7 +361,7 @@ func RegisterOpenIDPost(ctx *context.Context) {
Email: form.Email,
Passwd: password,
}
- if !createUserInContext(ctx, tplSignUpOID, form, u, nil, nil, false) {
+ if !createUserInContext(ctx, tplSignUpOID, form, u, nil, nil) {
// error already handled
return
}
diff --git a/routers/web/auth/webauthn.go b/routers/web/auth/webauthn.go
index 78f6c3b58e6..dacb6be225e 100644
--- a/routers/web/auth/webauthn.go
+++ b/routers/web/auth/webauthn.go
@@ -15,7 +15,6 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/services/context"
- "code.gitea.io/gitea/services/externalaccount"
"github.com/go-webauthn/webauthn/protocol"
"github.com/go-webauthn/webauthn/webauthn"
@@ -150,7 +149,7 @@ func WebAuthnPasskeyLogin(ctx *context.Context) {
// Now handle account linking if that's requested
if ctx.Session.Get("linkAccount") != nil {
- if err := externalaccount.LinkAccountFromStore(ctx, ctx.Session, user); err != nil {
+ if err := linkAccountFromContext(ctx, user); err != nil {
ctx.ServerError("LinkAccountFromStore", err)
return
}
@@ -268,7 +267,7 @@ func WebAuthnLoginAssertionPost(ctx *context.Context) {
// Now handle account linking if that's requested
if ctx.Session.Get("linkAccount") != nil {
- if err := externalaccount.LinkAccountFromStore(ctx, ctx.Session, user); err != nil {
+ if err := linkAccountFromContext(ctx, user); err != nil {
ctx.ServerError("LinkAccountFromStore", err)
return
}
diff --git a/routers/web/base.go b/routers/web/base.go
index e43f36a97be..0f06cb5e4b9 100644
--- a/routers/web/base.go
+++ b/routers/web/base.go
@@ -39,7 +39,7 @@ func avatarStorageHandler(storageSetting *setting.Storage, prefix string, objSto
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
rPath = util.PathJoinRelX(rPath)
- u, err := objStore.URL(rPath, path.Base(rPath), nil)
+ u, err := objStore.URL(rPath, path.Base(rPath), req.Method, nil)
if err != nil {
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
log.Warn("Unable to find %s %s", prefix, rPath)
diff --git a/routers/web/devtest/mail_preview.go b/routers/web/devtest/mail_preview.go
new file mode 100644
index 00000000000..d6bade15d7a
--- /dev/null
+++ b/routers/web/devtest/mail_preview.go
@@ -0,0 +1,58 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package devtest
+
+import (
+ "net/http"
+ "strings"
+
+ "code.gitea.io/gitea/modules/templates"
+ "code.gitea.io/gitea/services/context"
+ "code.gitea.io/gitea/services/mailer"
+
+ "gopkg.in/yaml.v3"
+)
+
+func MailPreviewRender(ctx *context.Context) {
+ tmplName := ctx.PathParam("*")
+ mockDataContent, err := templates.AssetFS().ReadFile("mail/" + tmplName + ".devtest.yml")
+ mockData := map[string]any{}
+ if err == nil {
+ err = yaml.Unmarshal(mockDataContent, &mockData)
+ if err != nil {
+ http.Error(ctx.Resp, "Failed to parse mock data: "+err.Error(), http.StatusInternalServerError)
+ return
+ }
+ }
+ mockData["locale"] = ctx.Locale
+ err = mailer.LoadedTemplates().BodyTemplates.ExecuteTemplate(ctx.Resp, tmplName, mockData)
+ if err != nil {
+ _, _ = ctx.Resp.Write([]byte(err.Error()))
+ }
+}
+
+func prepareMailPreviewRender(ctx *context.Context, tmplName string) {
+ tmplSubject := mailer.LoadedTemplates().SubjectTemplates.Lookup(tmplName)
+ if tmplSubject == nil {
+ ctx.Data["RenderMailSubject"] = "default subject"
+ } else {
+ var buf strings.Builder
+ err := tmplSubject.Execute(&buf, nil)
+ if err != nil {
+ ctx.Data["RenderMailSubject"] = err.Error()
+ } else {
+ ctx.Data["RenderMailSubject"] = buf.String()
+ }
+ }
+ ctx.Data["RenderMailTemplateName"] = tmplName
+}
+
+func MailPreview(ctx *context.Context) {
+ ctx.Data["MailTemplateNames"] = mailer.LoadedTemplates().TemplateNames
+ tmplName := ctx.FormString("tmpl")
+ if tmplName != "" {
+ prepareMailPreviewRender(ctx, tmplName)
+ }
+ ctx.HTML(http.StatusOK, "devtest/mail-preview")
+}
diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go
index 9eda926dad8..f6966691961 100644
--- a/routers/web/repo/attachment.go
+++ b/routers/web/repo/attachment.go
@@ -129,7 +129,7 @@ func ServeAttachment(ctx *context.Context, uuid string) {
if setting.Attachment.Storage.ServeDirect() {
// If we have a signed url (S3, object storage), redirect to this directly.
- u, err := storage.Attachments.URL(attach.RelativePath(), attach.Name, nil)
+ u, err := storage.Attachments.URL(attach.RelativePath(), attach.Name, ctx.Req.Method, nil)
if u != nil && err == nil {
ctx.Redirect(u.String())
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index 8f5c6a42e65..9a06c9359b5 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -311,7 +311,7 @@ func Diff(ctx *context.Context) {
maxLines, maxFiles = -1, -1
}
- diff, err := gitdiff.GetDiffForRender(ctx, gitRepo, &gitdiff.DiffOptions{
+ diff, err := gitdiff.GetDiffForRender(ctx, ctx.Repo.RepoLink, gitRepo, &gitdiff.DiffOptions{
AfterCommitID: commitID,
SkipTo: ctx.FormString("skip-to"),
MaxLines: maxLines,
diff --git a/routers/web/repo/common_recentbranches.go b/routers/web/repo/common_recentbranches.go
new file mode 100644
index 00000000000..c2083dec738
--- /dev/null
+++ b/routers/web/repo/common_recentbranches.go
@@ -0,0 +1,73 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repo
+
+import (
+ git_model "code.gitea.io/gitea/models/git"
+ access_model "code.gitea.io/gitea/models/perm/access"
+ unit_model "code.gitea.io/gitea/models/unit"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/services/context"
+ repo_service "code.gitea.io/gitea/services/repository"
+)
+
+type RecentBranchesPromptDataStruct struct {
+ RecentlyPushedNewBranches []*git_model.RecentlyPushedNewBranch
+}
+
+func prepareRecentlyPushedNewBranches(ctx *context.Context) {
+ if ctx.Doer == nil {
+ return
+ }
+ if err := ctx.Repo.Repository.GetBaseRepo(ctx); err != nil {
+ log.Error("GetBaseRepo: %v", err)
+ return
+ }
+
+ opts := git_model.FindRecentlyPushedNewBranchesOptions{
+ Repo: ctx.Repo.Repository,
+ BaseRepo: ctx.Repo.Repository,
+ }
+ if ctx.Repo.Repository.IsFork {
+ opts.BaseRepo = ctx.Repo.Repository.BaseRepo
+ }
+
+ baseRepoPerm, err := access_model.GetUserRepoPermission(ctx, opts.BaseRepo, ctx.Doer)
+ if err != nil {
+ log.Error("GetUserRepoPermission: %v", err)
+ return
+ }
+ if !opts.Repo.CanContentChange() || !opts.BaseRepo.CanContentChange() {
+ return
+ }
+ if !opts.BaseRepo.UnitEnabled(ctx, unit_model.TypePullRequests) || !baseRepoPerm.CanRead(unit_model.TypePullRequests) {
+ return
+ }
+
+ var finalBranches []*git_model.RecentlyPushedNewBranch
+ branches, err := git_model.FindRecentlyPushedNewBranches(ctx, ctx.Doer, opts)
+ if err != nil {
+ log.Error("FindRecentlyPushedNewBranches failed: %v", err)
+ return
+ }
+
+ for _, branch := range branches {
+ divergingInfo, err := repo_service.GetBranchDivergingInfo(ctx,
+ branch.BranchRepo, branch.BranchName, // "base" repo for diverging info
+ opts.BaseRepo, opts.BaseRepo.DefaultBranch, // "head" repo for diverging info
+ )
+ if err != nil {
+ log.Error("GetBranchDivergingInfo failed: %v", err)
+ continue
+ }
+ branchRepoHasNewCommits := divergingInfo.BaseHasNewCommits
+ baseRepoCommitsBehind := divergingInfo.HeadCommitsBehind
+ if branchRepoHasNewCommits || baseRepoCommitsBehind > 0 {
+ finalBranches = append(finalBranches, branch)
+ }
+ }
+ if len(finalBranches) > 0 {
+ ctx.Data["RecentBranchesPromptData"] = RecentBranchesPromptDataStruct{finalBranches}
+ }
+}
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index de34a9375c5..c771b30e5ff 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -614,7 +614,7 @@ func PrepareCompareDiff(
fileOnly := ctx.FormBool("file-only")
- diff, err := gitdiff.GetDiffForRender(ctx, ci.HeadGitRepo,
+ diff, err := gitdiff.GetDiffForRender(ctx, ci.HeadRepo.Link(), ci.HeadGitRepo,
&gitdiff.DiffOptions{
BeforeCommitID: beforeCommitID,
AfterCommitID: headCommitID,
diff --git a/routers/web/repo/download.go b/routers/web/repo/download.go
index 020cebf1963..6f394aae27d 100644
--- a/routers/web/repo/download.go
+++ b/routers/web/repo/download.go
@@ -54,7 +54,7 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified *time.Tim
if setting.LFS.Storage.ServeDirect() {
// If we have a signed url (S3, object storage, blob storage), redirect to this directly.
- u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name(), nil)
+ u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name(), ctx.Req.Method, nil)
if u != nil && err == nil {
ctx.Redirect(u.String())
return nil
diff --git a/routers/web/repo/issue_comment.go b/routers/web/repo/issue_comment.go
index c2a7f6b6822..cb5b2d80195 100644
--- a/routers/web/repo/issue_comment.go
+++ b/routers/web/repo/issue_comment.go
@@ -103,7 +103,7 @@ func NewComment(ctx *context.Context) {
// check whether the ref of PR in base repo is consistent with the head commit of head branch in the head repo
// get head commit of PR
if pull.Flow == issues_model.PullRequestFlowGithub {
- prHeadRef := pull.GetGitRefName()
+ prHeadRef := pull.GetGitHeadRefName()
if err := pull.LoadBaseRepo(ctx); err != nil {
ctx.ServerError("Unable to load base repo", err)
return
diff --git a/routers/web/repo/issue_list.go b/routers/web/repo/issue_list.go
index b55f4bcc90f..fd34422cfcc 100644
--- a/routers/web/repo/issue_list.go
+++ b/routers/web/repo/issue_list.go
@@ -767,6 +767,10 @@ func Issues(ctx *context.Context) {
}
ctx.Data["Title"] = ctx.Tr("repo.pulls")
ctx.Data["PageIsPullList"] = true
+ prepareRecentlyPushedNewBranches(ctx)
+ if ctx.Written() {
+ return
+ }
} else {
MustEnableIssues(ctx)
if ctx.Written() {
diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go
index d4458ed19ec..d0064e763ef 100644
--- a/routers/web/repo/issue_view.go
+++ b/routers/web/repo/issue_view.go
@@ -492,7 +492,7 @@ func preparePullViewSigning(ctx *context.Context, issue *issues_model.Issue) {
pull := issue.PullRequest
ctx.Data["WillSign"] = false
if ctx.Doer != nil {
- sign, key, _, err := asymkey_service.SignMerge(ctx, pull, ctx.Doer, pull.BaseRepo.RepoPath(), pull.BaseBranch, pull.GetGitRefName())
+ sign, key, _, err := asymkey_service.SignMerge(ctx, pull, ctx.Doer, pull.BaseRepo.RepoPath(), pull.BaseBranch, pull.GetGitHeadRefName())
ctx.Data["WillSign"] = sign
ctx.Data["SigningKey"] = key
if err != nil {
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index f662152e2e7..c5302dd50f5 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -196,7 +196,7 @@ func GetPullDiffStats(ctx *context.Context) {
}
// do not report 500 server error to end users if error occurs, otherwise a PR missing ref won't be able to view.
- headCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(pull.GetGitRefName())
+ headCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(pull.GetGitHeadRefName())
if err != nil {
log.Error("Failed to GetRefCommitID: %v, repo: %v", err, ctx.Repo.Repository.FullName())
return
@@ -218,13 +218,13 @@ func GetMergedBaseCommitID(ctx *context.Context, issue *issues_model.Issue) stri
if pull.MergeBase == "" {
var commitSHA, parentCommit string
// If there is a head or a patch file, and it is readable, grab info
- commitSHA, err := ctx.Repo.GitRepo.GetRefCommitID(pull.GetGitRefName())
+ commitSHA, err := ctx.Repo.GitRepo.GetRefCommitID(pull.GetGitHeadRefName())
if err != nil {
// Head File does not exist, try the patch
commitSHA, err = ctx.Repo.GitRepo.ReadPatchCommit(pull.Index)
if err == nil {
// Recreate pull head in files for next time
- if err := ctx.Repo.GitRepo.SetReference(pull.GetGitRefName(), commitSHA); err != nil {
+ if err := ctx.Repo.GitRepo.SetReference(pull.GetGitHeadRefName(), commitSHA); err != nil {
log.Error("Could not write head file", err)
}
} else {
@@ -274,7 +274,7 @@ func prepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue)
baseCommit := GetMergedBaseCommitID(ctx, issue)
compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(),
- baseCommit, pull.GetGitRefName(), false, false)
+ baseCommit, pull.GetGitHeadRefName(), false, false)
if err != nil {
if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "unknown revision or path not in the working tree") {
ctx.Data["IsPullRequestBroken"] = true
@@ -354,9 +354,9 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["BaseTarget"] = pull.BaseBranch
ctx.Data["HeadTarget"] = pull.HeadBranch
- sha, err := baseGitRepo.GetRefCommitID(pull.GetGitRefName())
+ sha, err := baseGitRepo.GetRefCommitID(pull.GetGitHeadRefName())
if err != nil {
- ctx.ServerError(fmt.Sprintf("GetRefCommitID(%s)", pull.GetGitRefName()), err)
+ ctx.ServerError(fmt.Sprintf("GetRefCommitID(%s)", pull.GetGitHeadRefName()), err)
return nil
}
commitStatuses, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll)
@@ -374,7 +374,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
}
compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(),
- pull.MergeBase, pull.GetGitRefName(), false, false)
+ pull.MergeBase, pull.GetGitHeadRefName(), false, false)
if err != nil {
if strings.Contains(err.Error(), "fatal: Not a valid object name") {
ctx.Data["IsPullRequestBroken"] = true
@@ -407,12 +407,12 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
if pull.Flow == issues_model.PullRequestFlowGithub {
headBranchExist = gitrepo.IsBranchExist(ctx, pull.HeadRepo, pull.HeadBranch)
} else {
- headBranchExist = gitrepo.IsReferenceExist(ctx, pull.BaseRepo, pull.GetGitRefName())
+ headBranchExist = gitrepo.IsReferenceExist(ctx, pull.BaseRepo, pull.GetGitHeadRefName())
}
if headBranchExist {
if pull.Flow != issues_model.PullRequestFlowGithub {
- headBranchSha, err = baseGitRepo.GetRefCommitID(pull.GetGitRefName())
+ headBranchSha, err = baseGitRepo.GetRefCommitID(pull.GetGitHeadRefName())
} else {
headBranchSha, err = headGitRepo.GetBranchCommitID(pull.HeadBranch)
}
@@ -435,7 +435,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["GetCommitMessages"] = ""
}
- sha, err := baseGitRepo.GetRefCommitID(pull.GetGitRefName())
+ sha, err := baseGitRepo.GetRefCommitID(pull.GetGitHeadRefName())
if err != nil {
if git.IsErrNotExist(err) {
ctx.Data["IsPullRequestBroken"] = true
@@ -451,7 +451,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["NumFiles"] = 0
return nil
}
- ctx.ServerError(fmt.Sprintf("GetRefCommitID(%s)", pull.GetGitRefName()), err)
+ ctx.ServerError(fmt.Sprintf("GetRefCommitID(%s)", pull.GetGitHeadRefName()), err)
return nil
}
@@ -522,7 +522,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
}
compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(),
- git.BranchPrefix+pull.BaseBranch, pull.GetGitRefName(), false, false)
+ git.BranchPrefix+pull.BaseBranch, pull.GetGitHeadRefName(), false, false)
if err != nil {
if strings.Contains(err.Error(), "fatal: Not a valid object name") {
ctx.Data["IsPullRequestBroken"] = true
@@ -698,7 +698,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
return
}
- headCommitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
+ headCommitID, err := gitRepo.GetRefCommitID(pull.GetGitHeadRefName())
if err != nil {
ctx.ServerError("GetRefCommitID", err)
return
@@ -750,7 +750,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
diffOptions.BeforeCommitID = startCommitID
}
- diff, err := gitdiff.GetDiffForRender(ctx, gitRepo, diffOptions, files...)
+ diff, err := gitdiff.GetDiffForRender(ctx, ctx.Repo.RepoLink, gitRepo, diffOptions, files...)
if err != nil {
ctx.ServerError("GetDiff", err)
return
@@ -1509,7 +1509,7 @@ func CleanUpPullRequest(ctx *context.Context) {
}()
// Check if branch has no new commits
- headCommitID, err := gitBaseRepo.GetRefCommitID(pr.GetGitRefName())
+ headCommitID, err := gitBaseRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
log.Error("GetRefCommitID: %v", err)
ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", fullBranchName))
diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go
index 929e131d613..18e14e9b224 100644
--- a/routers/web/repo/pull_review.go
+++ b/routers/web/repo/pull_review.go
@@ -49,7 +49,7 @@ func RenderNewCodeCommentForm(ctx *context.Context) {
ctx.Data["PageIsPullFiles"] = true
ctx.Data["Issue"] = issue
ctx.Data["CurrentReview"] = currentReview
- pullHeadCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(issue.PullRequest.GetGitRefName())
+ pullHeadCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(issue.PullRequest.GetGitHeadRefName())
if err != nil {
ctx.ServerError("GetRefCommitID", err)
return
@@ -199,7 +199,7 @@ func renderConversation(ctx *context.Context, comment *issues_model.Comment, ori
ctx.ServerError("comment.Issue.LoadPullRequest", err)
return
}
- pullHeadCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(comment.Issue.PullRequest.GetGitRefName())
+ pullHeadCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(comment.Issue.PullRequest.GetGitHeadRefName())
if err != nil {
ctx.ServerError("GetRefCommitID", err)
return
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index 828ec08a8a1..1b700aa6da0 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -398,7 +398,7 @@ func download(ctx *context.Context, archiveName string, archiver *repo_model.Rep
rPath := archiver.RelativePath()
if setting.RepoArchive.Storage.ServeDirect() {
// If we have a signed url (S3, object storage), redirect to this directly.
- u, err := storage.RepoArchives.URL(rPath, downloadName, nil)
+ u, err := storage.RepoArchives.URL(rPath, downloadName, ctx.Req.Method, nil)
if u != nil && err == nil {
ctx.Redirect(u.String())
return
diff --git a/routers/web/repo/treelist.go b/routers/web/repo/treelist.go
index 7d7f5a1473d..340b2bc0917 100644
--- a/routers/web/repo/treelist.go
+++ b/routers/web/repo/treelist.go
@@ -144,7 +144,7 @@ func transformDiffTreeForWeb(renderedIconPool *fileicon.RenderedIconPool, diffTr
func TreeViewNodes(ctx *context.Context) {
renderedIconPool := fileicon.NewRenderedIconPool()
- results, err := files_service.GetTreeViewNodes(ctx, renderedIconPool, ctx.Repo.Commit, ctx.Repo.TreePath, ctx.FormString("sub_path"))
+ results, err := files_service.GetTreeViewNodes(ctx, ctx.Repo.RepoLink, renderedIconPool, ctx.Repo.Commit, ctx.Repo.TreePath, ctx.FormString("sub_path"))
if err != nil {
ctx.ServerError("GetTreeViewNodes", err)
return
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 773919c054e..e47bc56d081 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -305,7 +305,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
defer cancel()
}
- files, latestCommit, err := allEntries.GetCommitsInfo(commitInfoCtx, ctx.Repo.Commit, ctx.Repo.TreePath)
+ files, latestCommit, err := allEntries.GetCommitsInfo(commitInfoCtx, ctx.Repo.RepoLink, ctx.Repo.Commit, ctx.Repo.TreePath)
if err != nil {
ctx.ServerError("GetCommitsInfo", err)
return nil
diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go
index c7396d44e33..fd6e746381b 100644
--- a/routers/web/repo/view_home.go
+++ b/routers/web/repo/view_home.go
@@ -15,7 +15,6 @@ import (
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
- access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
@@ -196,56 +195,6 @@ func prepareUpstreamDivergingInfo(ctx *context.Context) {
ctx.Data["UpstreamDivergingInfo"] = upstreamDivergingInfo
}
-func prepareRecentlyPushedNewBranches(ctx *context.Context) {
- if ctx.Doer != nil {
- if err := ctx.Repo.Repository.GetBaseRepo(ctx); err != nil {
- ctx.ServerError("GetBaseRepo", err)
- return
- }
-
- opts := &git_model.FindRecentlyPushedNewBranchesOptions{
- Repo: ctx.Repo.Repository,
- BaseRepo: ctx.Repo.Repository,
- }
- if ctx.Repo.Repository.IsFork {
- opts.BaseRepo = ctx.Repo.Repository.BaseRepo
- }
-
- baseRepoPerm, err := access_model.GetUserRepoPermission(ctx, opts.BaseRepo, ctx.Doer)
- if err != nil {
- ctx.ServerError("GetUserRepoPermission", err)
- return
- }
-
- if !opts.Repo.IsMirror && !opts.BaseRepo.IsMirror &&
- opts.BaseRepo.UnitEnabled(ctx, unit_model.TypePullRequests) &&
- baseRepoPerm.CanRead(unit_model.TypePullRequests) {
- var finalBranches []*git_model.RecentlyPushedNewBranch
- branches, err := git_model.FindRecentlyPushedNewBranches(ctx, ctx.Doer, opts)
- if err != nil {
- log.Error("FindRecentlyPushedNewBranches failed: %v", err)
- }
-
- for _, branch := range branches {
- divergingInfo, err := repo_service.GetBranchDivergingInfo(ctx,
- branch.BranchRepo, branch.BranchName, // "base" repo for diverging info
- opts.BaseRepo, opts.BaseRepo.DefaultBranch, // "head" repo for diverging info
- )
- if err != nil {
- log.Error("GetBranchDivergingInfo failed: %v", err)
- continue
- }
- branchRepoHasNewCommits := divergingInfo.BaseHasNewCommits
- baseRepoCommitsBehind := divergingInfo.HeadCommitsBehind
- if branchRepoHasNewCommits || baseRepoCommitsBehind > 0 {
- finalBranches = append(finalBranches, branch)
- }
- }
- ctx.Data["RecentlyPushedNewBranches"] = finalBranches
- }
- }
-}
-
func updateContextRepoEmptyAndStatus(ctx *context.Context, empty bool, status repo_model.RepositoryStatus) {
if ctx.Repo.Repository.IsEmpty == empty && ctx.Repo.Repository.Status == status {
return
@@ -310,9 +259,10 @@ func handleRepoEmptyOrBroken(ctx *context.Context) {
}
func handleRepoViewSubmodule(ctx *context.Context, submodule *git.SubModule) {
+ // TODO: it needs to use git.NewCommitSubmoduleFile and SubmoduleWebLinkTree to correctly handle relative paths
submoduleRepoURL, err := giturl.ParseRepositoryURL(ctx, submodule.URL)
if err != nil {
- HandleGitError(ctx, "prepareToRenderDirOrFile: ParseRepositoryURL", err)
+ HandleGitError(ctx, "handleRepoViewSubmodule: ParseRepositoryURL", err)
return
}
submoduleURL := giturl.MakeRepositoryWebLink(submoduleRepoURL)
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
index 69858c96925..a35b7b86e12 100644
--- a/routers/web/repo/wiki.go
+++ b/routers/web/repo/wiki.go
@@ -6,7 +6,6 @@ package repo
import (
"bytes"
- gocontext "context"
"html/template"
"io"
"net/http"
@@ -569,7 +568,7 @@ func WikiPages(ctx *context.Context) {
}
allEntries.CustomSort(base.NaturalSortLess)
- entries, _, err := allEntries.GetCommitsInfo(gocontext.Context(ctx), commit, treePath)
+ entries, _, err := allEntries.GetCommitsInfo(ctx, ctx.Repo.RepoLink, commit, treePath)
if err != nil {
ctx.ServerError("GetCommitsInfo", err)
return
diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go
index 610a9b80760..aaf9d435c09 100644
--- a/routers/web/user/notification.go
+++ b/routers/web/user/notification.go
@@ -4,10 +4,8 @@
package user
import (
- "errors"
"fmt"
"net/http"
- "net/url"
"strings"
activities_model "code.gitea.io/gitea/models/activities"
@@ -34,58 +32,42 @@ const (
tplNotificationSubscriptions templates.TplName = "user/notification/notification_subscriptions"
)
-// Notifications is the notifications page
+// Notifications is the notification list page
func Notifications(ctx *context.Context) {
- getNotifications(ctx)
+ prepareUserNotificationsData(ctx)
if ctx.Written() {
return
}
if ctx.FormBool("div-only") {
- ctx.Data["SequenceNumber"] = ctx.FormString("sequence-number")
ctx.HTML(http.StatusOK, tplNotificationDiv)
return
}
ctx.HTML(http.StatusOK, tplNotification)
}
-func getNotifications(ctx *context.Context) {
- var (
- keyword = ctx.FormTrim("q")
- status activities_model.NotificationStatus
- page = ctx.FormInt("page")
- perPage = ctx.FormInt("perPage")
- )
- if page < 1 {
- page = 1
- }
- if perPage < 1 {
- perPage = 20
- }
-
- switch keyword {
- case "read":
- status = activities_model.NotificationStatusRead
- default:
- status = activities_model.NotificationStatusUnread
- }
+func prepareUserNotificationsData(ctx *context.Context) {
+ pageType := ctx.FormString("type", ctx.FormString("q")) // "q" is the legacy query parameter for "page type"
+ page := max(1, ctx.FormInt("page"))
+ perPage := util.IfZero(ctx.FormInt("perPage"), 20) // this value is never used or exposed ....
+ queryStatus := util.Iif(pageType == "read", activities_model.NotificationStatusRead, activities_model.NotificationStatusUnread)
total, err := db.Count[activities_model.Notification](ctx, activities_model.FindNotificationOptions{
UserID: ctx.Doer.ID,
- Status: []activities_model.NotificationStatus{status},
+ Status: []activities_model.NotificationStatus{queryStatus},
})
if err != nil {
ctx.ServerError("ErrGetNotificationCount", err)
return
}
- // redirect to last page if request page is more than total pages
pager := context.NewPagination(int(total), perPage, page, 5)
if pager.Paginater.Current() < page {
- ctx.Redirect(fmt.Sprintf("%s/notifications?q=%s&page=%d", setting.AppSubURL, url.QueryEscape(ctx.FormString("q")), pager.Paginater.Current()))
- return
+ // use the last page if the requested page is more than total pages
+ page = pager.Paginater.Current()
+ pager = context.NewPagination(int(total), perPage, page, 5)
}
- statuses := []activities_model.NotificationStatus{status, activities_model.NotificationStatusPinned}
+ statuses := []activities_model.NotificationStatus{queryStatus, activities_model.NotificationStatusPinned}
nls, err := db.Find[activities_model.Notification](ctx, activities_model.FindNotificationOptions{
ListOptions: db.ListOptions{
PageSize: perPage,
@@ -142,51 +124,37 @@ func getNotifications(ctx *context.Context) {
}
ctx.Data["Title"] = ctx.Tr("notifications")
- ctx.Data["Keyword"] = keyword
- ctx.Data["Status"] = status
+ ctx.Data["PageType"] = pageType
ctx.Data["Notifications"] = notifications
-
+ ctx.Data["Link"] = setting.AppSubURL + "/notifications"
+ ctx.Data["SequenceNumber"] = ctx.FormString("sequence-number")
pager.AddParamFromRequest(ctx.Req)
ctx.Data["Page"] = pager
}
// NotificationStatusPost is a route for changing the status of a notification
func NotificationStatusPost(ctx *context.Context) {
- var (
- notificationID = ctx.FormInt64("notification_id")
- statusStr = ctx.FormString("status")
- status activities_model.NotificationStatus
- )
-
- switch statusStr {
- case "read":
- status = activities_model.NotificationStatusRead
- case "unread":
- status = activities_model.NotificationStatusUnread
- case "pinned":
- status = activities_model.NotificationStatusPinned
+ notificationID := ctx.FormInt64("notification_id")
+ var newStatus activities_model.NotificationStatus
+ switch ctx.FormString("notification_action") {
+ case "mark_as_read":
+ newStatus = activities_model.NotificationStatusRead
+ case "mark_as_unread":
+ newStatus = activities_model.NotificationStatusUnread
+ case "pin":
+ newStatus = activities_model.NotificationStatusPinned
default:
- ctx.ServerError("InvalidNotificationStatus", errors.New("Invalid notification status"))
- return
+ return // ignore user's invalid input
}
-
- if _, err := activities_model.SetNotificationStatus(ctx, notificationID, ctx.Doer, status); err != nil {
+ if _, err := activities_model.SetNotificationStatus(ctx, notificationID, ctx.Doer, newStatus); err != nil {
ctx.ServerError("SetNotificationStatus", err)
return
}
- if !ctx.FormBool("noredirect") {
- url := fmt.Sprintf("%s/notifications?page=%s", setting.AppSubURL, url.QueryEscape(ctx.FormString("page")))
- ctx.Redirect(url, http.StatusSeeOther)
- }
-
- getNotifications(ctx)
+ prepareUserNotificationsData(ctx)
if ctx.Written() {
return
}
- ctx.Data["Link"] = setting.AppSubURL + "/notifications"
- ctx.Data["SequenceNumber"] = ctx.Req.PostFormValue("sequence-number")
-
ctx.HTML(http.StatusOK, tplNotificationDiv)
}
diff --git a/routers/web/user/package.go b/routers/web/user/package.go
index 216acdf927b..d130d1dca18 100644
--- a/routers/web/user/package.go
+++ b/routers/web/user/package.go
@@ -513,7 +513,7 @@ func DownloadPackageFile(ctx *context.Context) {
return
}
- s, u, _, err := packages_service.OpenFileForDownload(ctx, pf)
+ s, u, _, err := packages_service.OpenFileForDownload(ctx, pf, ctx.Req.Method)
if err != nil {
ctx.ServerError("OpenFileForDownload", err)
return
diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go
index b124d5e1def..6b17da50e5b 100644
--- a/routers/web/user/setting/account.go
+++ b/routers/web/user/setting/account.go
@@ -35,7 +35,7 @@ const (
// Account renders change user's password, user's email and user suicide page
func Account(ctx *context.Context) {
- if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials, setting.UserFeatureDeletion) && !setting.Service.EnableNotifyMail {
+ if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials, setting.UserFeatureDeletion) {
ctx.NotFound(errors.New("account setting are not allowed to be changed"))
return
}
@@ -43,7 +43,6 @@ func Account(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings.account")
ctx.Data["PageIsSettingsAccount"] = true
ctx.Data["Email"] = ctx.Doer.Email
- ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
loadAccountData(ctx)
@@ -61,7 +60,6 @@ func AccountPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsAccount"] = true
ctx.Data["Email"] = ctx.Doer.Email
- ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
if ctx.HasError() {
loadAccountData(ctx)
@@ -112,7 +110,6 @@ func EmailPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsAccount"] = true
ctx.Data["Email"] = ctx.Doer.Email
- ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
// Make email address primary.
if ctx.FormString("_method") == "PRIMARY" {
@@ -172,30 +169,6 @@ func EmailPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
- // Set Email Notification Preference
- if ctx.FormString("_method") == "NOTIFICATION" {
- preference := ctx.FormString("preference")
- if !(preference == user_model.EmailNotificationsEnabled ||
- preference == user_model.EmailNotificationsOnMention ||
- preference == user_model.EmailNotificationsDisabled ||
- preference == user_model.EmailNotificationsAndYourOwn) {
- log.Error("Email notifications preference change returned unrecognized option %s: %s", preference, ctx.Doer.Name)
- ctx.ServerError("SetEmailPreference", errors.New("option unrecognized"))
- return
- }
- opts := &user.UpdateOptions{
- EmailNotificationsPreference: optional.Some(preference),
- }
- if err := user.UpdateUser(ctx, ctx.Doer, opts); err != nil {
- log.Error("Set Email Notifications failed: %v", err)
- ctx.ServerError("UpdateUser", err)
- return
- }
- log.Trace("Email notifications preference made %s: %s", preference, ctx.Doer.Name)
- ctx.Flash.Success(ctx.Tr("settings.email_preference_set_success"))
- ctx.Redirect(setting.AppSubURL + "/user/settings/account")
- return
- }
if ctx.HasError() {
loadAccountData(ctx)
@@ -267,7 +240,6 @@ func DeleteAccount(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsAccount"] = true
ctx.Data["Email"] = ctx.Doer.Email
- ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
if _, _, err := auth.UserSignIn(ctx, ctx.Doer.Name, ctx.FormString("password")); err != nil {
switch {
@@ -342,7 +314,6 @@ func loadAccountData(ctx *context.Context) {
emails[i] = &email
}
ctx.Data["Emails"] = emails
- ctx.Data["EmailNotificationsPreference"] = ctx.Doer.EmailNotificationsPreference
ctx.Data["ActivationsPending"] = pendingActivation
ctx.Data["CanAddEmails"] = !pendingActivation || !setting.Service.RegisterEmailConfirm
ctx.Data["UserDisabledFeatures"] = user_model.DisabledFeaturesWithLoginType(ctx.Doer)
diff --git a/routers/web/user/setting/notifications.go b/routers/web/user/setting/notifications.go
new file mode 100644
index 00000000000..8ff6f1d941f
--- /dev/null
+++ b/routers/web/user/setting/notifications.go
@@ -0,0 +1,89 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package setting
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/optional"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/templates"
+ "code.gitea.io/gitea/services/context"
+ "code.gitea.io/gitea/services/user"
+)
+
+const tplSettingsNotifications templates.TplName = "user/settings/notifications"
+
+// Notifications render user's notifications settings
+func Notifications(ctx *context.Context) {
+ if !setting.Service.EnableNotifyMail {
+ ctx.NotFound(nil)
+ return
+ }
+
+ ctx.Data["Title"] = ctx.Tr("notifications")
+ ctx.Data["PageIsSettingsNotifications"] = true
+ ctx.Data["EmailNotificationsPreference"] = ctx.Doer.EmailNotificationsPreference
+
+ actionsEmailPref, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyEmailNotificationGiteaActions, user_model.SettingEmailNotificationGiteaActionsFailureOnly)
+ if err != nil {
+ ctx.ServerError("GetUserSetting", err)
+ return
+ }
+ ctx.Data["ActionsEmailNotificationsPreference"] = actionsEmailPref
+
+ ctx.HTML(http.StatusOK, tplSettingsNotifications)
+}
+
+// NotificationsEmailPost set user's email notification preference
+func NotificationsEmailPost(ctx *context.Context) {
+ if !setting.Service.EnableNotifyMail {
+ ctx.NotFound(nil)
+ return
+ }
+
+ preference := ctx.FormString("preference")
+ if !(preference == user_model.EmailNotificationsEnabled ||
+ preference == user_model.EmailNotificationsOnMention ||
+ preference == user_model.EmailNotificationsDisabled ||
+ preference == user_model.EmailNotificationsAndYourOwn) {
+ ctx.Flash.Error(ctx.Tr("invalid_data", preference))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/notifications")
+ return
+ }
+ opts := &user.UpdateOptions{
+ EmailNotificationsPreference: optional.Some(preference),
+ }
+ if err := user.UpdateUser(ctx, ctx.Doer, opts); err != nil {
+ ctx.ServerError("UpdateUser", err)
+ return
+ }
+ ctx.Flash.Success(ctx.Tr("settings.email_preference_set_success"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/notifications")
+}
+
+// NotificationsActionsEmailPost set user's email notification preference on Gitea Actions
+func NotificationsActionsEmailPost(ctx *context.Context) {
+ if !setting.Actions.Enabled || unit.TypeActions.UnitGlobalDisabled() {
+ ctx.NotFound(nil)
+ return
+ }
+
+ preference := ctx.FormString("preference")
+ if !(preference == user_model.SettingEmailNotificationGiteaActionsAll ||
+ preference == user_model.SettingEmailNotificationGiteaActionsDisabled ||
+ preference == user_model.SettingEmailNotificationGiteaActionsFailureOnly) {
+ ctx.Flash.Error(ctx.Tr("invalid_data", preference))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/notifications")
+ return
+ }
+ if err := user_model.SetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyEmailNotificationGiteaActions, preference); err != nil {
+ ctx.ServerError("SetUserSetting", err)
+ return
+ }
+ ctx.Flash.Success(ctx.Tr("settings.email_preference_set_success"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/notifications")
+}
diff --git a/routers/web/web.go b/routers/web/web.go
index b2aadeef281..7013753184f 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -595,6 +595,11 @@ func registerWebRoutes(m *web.Router) {
m.Post("/hidden_comments", user_setting.UpdateUserHiddenComments)
m.Post("/theme", web.Bind(forms.UpdateThemeForm{}), user_setting.UpdateUIThemePost)
})
+ m.Group("/notifications", func() {
+ m.Get("", user_setting.Notifications)
+ m.Post("/email", user_setting.NotificationsEmailPost)
+ m.Post("/actions", user_setting.NotificationsActionsEmailPost)
+ })
m.Group("/security", func() {
m.Get("", security.Security)
m.Group("/two_factor", func() {
@@ -682,7 +687,7 @@ func registerWebRoutes(m *web.Router) {
m.Get("", user_setting.BlockedUsers)
m.Post("", web.Bind(forms.BlockUserForm{}), user_setting.BlockedUsersPost)
})
- }, reqSignIn, ctxDataSet("PageIsUserSettings", true, "EnablePackages", setting.Packages.Enabled))
+ }, reqSignIn, ctxDataSet("PageIsUserSettings", true, "EnablePackages", setting.Packages.Enabled, "EnableNotifyMail", setting.Service.EnableNotifyMail))
m.Group("/user", func() {
m.Get("/activate", auth.Activate)
@@ -1660,6 +1665,8 @@ func registerWebRoutes(m *web.Router) {
m.Group("/devtest", func() {
m.Any("", devtest.List)
m.Any("/fetch-action-test", devtest.FetchActionTest)
+ m.Any("/mail-preview", devtest.MailPreview)
+ m.Any("/mail-preview/*", devtest.MailPreviewRender)
m.Any("/{sub}", devtest.TmplCommon)
m.Get("/repo-action-view/{run}/{job}", devtest.MockActionsView)
m.Post("/actions-mock/runs/{run}/jobs/{job}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs)
diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go
index 8010f51a861..b8bc20cdbb1 100644
--- a/services/actions/notifier_helper.go
+++ b/services/actions/notifier_helper.go
@@ -104,7 +104,7 @@ func (input *notifyInput) WithPayload(payload api.Payloader) *notifyInput {
func (input *notifyInput) WithPullRequest(pr *issues_model.PullRequest) *notifyInput {
input.PullRequest = pr
if input.Ref == "" {
- input.Ref = git.RefName(pr.GetGitRefName())
+ input.Ref = git.RefName(pr.GetGitHeadRefName())
}
return input
}
diff --git a/services/agit/agit.go b/services/agit/agit.go
index b27dfc8ecd3..63b3eab4f2d 100644
--- a/services/agit/agit.go
+++ b/services/agit/agit.go
@@ -5,6 +5,7 @@ package agit
import (
"context"
+ "encoding/base64"
"fmt"
"os"
"strings"
@@ -18,17 +19,30 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
notify_service "code.gitea.io/gitea/services/notify"
pull_service "code.gitea.io/gitea/services/pull"
)
+func parseAgitPushOptionValue(s string) string {
+ if base64Value, ok := strings.CutPrefix(s, "{base64}"); ok {
+ decoded, err := base64.StdEncoding.DecodeString(base64Value)
+ return util.Iif(err == nil, string(decoded), s)
+ }
+ return s
+}
+
// ProcReceive handle proc receive work
func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, opts *private.HookOptions) ([]private.HookProcReceiveRefResult, error) {
results := make([]private.HookProcReceiveRefResult, 0, len(opts.OldCommitIDs))
forcePush := opts.GitPushOptions.Bool(private.GitPushOptionForcePush)
topicBranch := opts.GitPushOptions["topic"]
- title := strings.TrimSpace(opts.GitPushOptions["title"])
- description := strings.TrimSpace(opts.GitPushOptions["description"])
+
+ // some options are base64-encoded with "{base64}" prefix if they contain new lines
+ // other agit push options like "issue", "reviewer" and "cc" are not supported
+ title := parseAgitPushOptionValue(opts.GitPushOptions["title"])
+ description := parseAgitPushOptionValue(opts.GitPushOptions["description"])
+
objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName)
userName := strings.ToLower(opts.UserName)
@@ -151,7 +165,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID)
results = append(results, private.HookProcReceiveRefResult{
- Ref: pr.GetGitRefName(),
+ Ref: pr.GetGitHeadRefName(),
OriginalRef: opts.RefFullNames[i],
OldOID: objectFormat.EmptyObjectID().String(),
NewOID: opts.NewCommitIDs[i],
@@ -168,7 +182,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
return nil, fmt.Errorf("unable to load base repository for PR[%d] Error: %w", pr.ID, err)
}
- oldCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
+ oldCommitID, err := gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
return nil, fmt.Errorf("unable to get ref commit id in base repository for PR[%d] Error: %w", pr.ID, err)
}
@@ -246,7 +260,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
results = append(results, private.HookProcReceiveRefResult{
OldOID: oldCommitID,
NewOID: opts.NewCommitIDs[i],
- Ref: pr.GetGitRefName(),
+ Ref: pr.GetGitHeadRefName(),
OriginalRef: opts.RefFullNames[i],
IsForcePush: isForcePush,
IsCreatePR: false,
diff --git a/services/agit/agit_test.go b/services/agit/agit_test.go
new file mode 100644
index 00000000000..feaf7dca9ba
--- /dev/null
+++ b/services/agit/agit_test.go
@@ -0,0 +1,16 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package agit
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestParseAgitPushOptionValue(t *testing.T) {
+ assert.Equal(t, "a", parseAgitPushOptionValue("a"))
+ assert.Equal(t, "a", parseAgitPushOptionValue("{base64}YQ=="))
+ assert.Equal(t, "{base64}invalid value", parseAgitPushOptionValue("{base64}invalid value"))
+}
diff --git a/services/asymkey/commit.go b/services/asymkey/commit.go
index 148f51fd10e..54ef052a507 100644
--- a/services/asymkey/commit.go
+++ b/services/asymkey/commit.go
@@ -24,47 +24,44 @@ import (
// ParseCommitWithSignature check if signature is good against keystore.
func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *asymkey_model.CommitVerification {
- var committer *user_model.User
- if c.Committer != nil {
- var err error
- // Find Committer account
- committer, err = user_model.GetUserByEmail(ctx, c.Committer.Email) // This finds the user by primary email or activated email so commit will not be valid if email is not
- if err != nil { // Skipping not user for committer
- committer = &user_model.User{
- Name: c.Committer.Name,
- Email: c.Committer.Email,
- }
- // We can expect this to often be an ErrUserNotExist. in the case
- // it is not, however, it is important to log it.
- if !user_model.IsErrUserNotExist(err) {
- log.Error("GetUserByEmail: %v", err)
- return &asymkey_model.CommitVerification{
- CommittingUser: committer,
- Verified: false,
- Reason: "gpg.error.no_committer_account",
- }
- }
+ committer, err := user_model.GetUserByEmail(ctx, c.Committer.Email)
+ if err != nil && !user_model.IsErrUserNotExist(err) {
+ log.Error("GetUserByEmail: %v", err)
+ return &asymkey_model.CommitVerification{
+ Verified: false,
+ Reason: "gpg.error.no_committer_account", // this error is not right, but such error should seldom happen
}
}
-
return ParseCommitWithSignatureCommitter(ctx, c, committer)
}
+// ParseCommitWithSignatureCommitter parses a commit's GPG or SSH signature.
+// The caller guarantees that the committer user is related to the commit by checking its activated email addresses or no-reply address.
+// If the commit is singed by an instance key, then committer can be nil.
+// If the signature exists, even if committer is nil, the returned CommittingUser will be a non-nil fake user (e.g.: instance key)
func ParseCommitWithSignatureCommitter(ctx context.Context, c *git.Commit, committer *user_model.User) *asymkey_model.CommitVerification {
- // If no signature just report the committer
+ // If no signature, just report the committer
if c.Signature == nil {
return &asymkey_model.CommitVerification{
CommittingUser: committer,
- Verified: false, // Default value
- Reason: "gpg.error.not_signed_commit", // Default value
+ Verified: false,
+ Reason: "gpg.error.not_signed_commit",
}
}
-
- // If this a SSH signature handle it differently
- if strings.HasPrefix(c.Signature.Signature, "-----BEGIN SSH SIGNATURE-----") {
- return ParseCommitWithSSHSignature(ctx, c, committer)
+ // to support instance key, we need a fake committer user (not really needed, but legacy code accesses the committer without nil-check)
+ if committer == nil {
+ committer = &user_model.User{
+ Name: c.Committer.Name,
+ Email: c.Committer.Email,
+ }
}
+ if strings.HasPrefix(c.Signature.Signature, "-----BEGIN SSH SIGNATURE-----") {
+ return parseCommitWithSSHSignature(ctx, c, committer)
+ }
+ return parseCommitWithGPGSignature(ctx, c, committer)
+}
+func parseCommitWithGPGSignature(ctx context.Context, c *git.Commit, committer *user_model.User) *asymkey_model.CommitVerification {
// Parsing signature
sig, err := asymkey_model.ExtractSignature(c.Signature.Signature)
if err != nil { // Skipping failed to extract sign
@@ -118,20 +115,11 @@ func ParseCommitWithSignatureCommitter(ctx context.Context, c *git.Commit, commi
}
}
- committerEmailAddresses, _ := cache.GetWithContextCache(ctx, cachegroup.UserEmailAddresses, committer.ID, user_model.GetEmailAddresses)
- activated := false
- for _, e := range committerEmailAddresses {
- if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
- activated = true
- break
- }
- }
-
for _, k := range keys {
// Pre-check (& optimization) that emails attached to key can be attached to the committer email and can validate
canValidate := false
email := ""
- if k.Verified && activated {
+ if k.Verified {
canValidate = true
email = c.Committer.Email
}
@@ -165,7 +153,7 @@ func ParseCommitWithSignatureCommitter(ctx context.Context, c *git.Commit, commi
}
if err := gpgSettings.LoadPublicKeyContent(); err != nil {
log.Error("Error getting default signing key: %s %v", gpgSettings.KeyID, err)
- } else if commitVerification := VerifyWithGPGSettings(ctx, &gpgSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil {
+ } else if commitVerification := verifyWithGPGSettings(ctx, &gpgSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil {
if commitVerification.Reason == asymkey_model.BadSignature {
defaultReason = asymkey_model.BadSignature
} else {
@@ -180,7 +168,7 @@ func ParseCommitWithSignatureCommitter(ctx context.Context, c *git.Commit, commi
} else if defaultGPGSettings == nil {
log.Warn("Unable to get defaultGPGSettings for unattached commit: %s", c.ID.String())
} else if defaultGPGSettings.Sign {
- if commitVerification := VerifyWithGPGSettings(ctx, defaultGPGSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil {
+ if commitVerification := verifyWithGPGSettings(ctx, defaultGPGSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil {
if commitVerification.Reason == asymkey_model.BadSignature {
defaultReason = asymkey_model.BadSignature
} else {
@@ -221,8 +209,8 @@ func checkKeyEmails(ctx context.Context, email string, keys ...*asymkey_model.GP
return true, e.Email
}
}
- if user.KeepEmailPrivate && strings.EqualFold(email, user.GetEmail()) {
- return true, user.GetEmail()
+ if user != nil && strings.EqualFold(email, user.GetPlaceholderEmail()) {
+ return true, user.GetPlaceholderEmail()
}
}
}
@@ -295,7 +283,7 @@ func HashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s
}
}
-func VerifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *asymkey_model.CommitVerification {
+func verifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *asymkey_model.CommitVerification {
// First try to find the key in the db
if commitVerification := HashAndVerifyForKeyID(ctx, sig, payload, committer, gpgSettings.KeyID, gpgSettings.Name, gpgSettings.Email); commitVerification != nil {
return commitVerification
@@ -375,8 +363,8 @@ func verifySSHCommitVerificationByInstanceKey(c *git.Commit, committerUser, sign
return verifySSHCommitVerification(c.Signature.Signature, c.Signature.Payload, sshPubKey, committerUser, signerUser, committerGitEmail)
}
-// ParseCommitWithSSHSignature check if signature is good against keystore.
-func ParseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committerUser *user_model.User) *asymkey_model.CommitVerification {
+// parseCommitWithSSHSignature check if signature is good against keystore.
+func parseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committerUser *user_model.User) *asymkey_model.CommitVerification {
// Now try to associate the signature with the committer, if present
if committerUser.ID != 0 {
keys, err := db.Find[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{
@@ -392,21 +380,8 @@ func ParseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committerUs
}
}
- committerEmailAddresses, err := cache.GetWithContextCache(ctx, cachegroup.UserEmailAddresses, committerUser.ID, user_model.GetEmailAddresses)
- if err != nil {
- log.Error("GetEmailAddresses: %v", err)
- }
-
- activated := false
- for _, e := range committerEmailAddresses {
- if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
- activated = true
- break
- }
- }
-
for _, k := range keys {
- if k.Verified && activated {
+ if k.Verified {
commitVerification := verifySSHCommitVerification(c.Signature.Signature, c.Signature.Payload, k, committerUser, committerUser, c.Committer.Email)
if commitVerification != nil {
return commitVerification
diff --git a/services/asymkey/commit_test.go b/services/asymkey/commit_test.go
index 0438209a619..6edba1e90af 100644
--- a/services/asymkey/commit_test.go
+++ b/services/asymkey/commit_test.go
@@ -7,6 +7,9 @@ import (
"strings"
"testing"
+ asymkey_model "code.gitea.io/gitea/models/asymkey"
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
@@ -17,7 +20,49 @@ import (
)
func TestParseCommitWithSSHSignature(t *testing.T) {
- // Here we only test the TrustedSSHKeys. The complete signing test is in tests/integration/gpg_ssh_git_test.go
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ // Here we only need to do some tests that "tests/integration/gpg_ssh_git_test.go" doesn't cover
+
+ // -----BEGIN OPENSSH PRIVATE KEY-----
+ // b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+ // QyNTUxOQAAACC6T6zF0oPak8dOIzzT1kXB7LrcsVo04SKc3GjuvMllZwAAAJgy08upMtPL
+ // qQAAAAtzc2gtZWQyNTUxOQAAACC6T6zF0oPak8dOIzzT1kXB7LrcsVo04SKc3GjuvMllZw
+ // AAAEDWqPHTH51xb4hy1y1f1VeWL/2A9Q0b6atOyv5fx8x5prpPrMXSg9qTx04jPNPWRcHs
+ // utyxWjThIpzcaO68yWVnAAAAEXVzZXIyQGV4YW1wbGUuY29tAQIDBA==
+ // -----END OPENSSH PRIVATE KEY-----
+ sshPubKey, err := asymkey_model.AddPublicKey(t.Context(), 999, "user-ssh-key-any-name", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILpPrMXSg9qTx04jPNPWRcHsutyxWjThIpzcaO68yWVn", 0)
+ require.NoError(t, err)
+ _, err = db.GetEngine(t.Context()).ID(sshPubKey.ID).Cols("verified").Update(&asymkey_model.PublicKey{Verified: true})
+ require.NoError(t, err)
+
+ t.Run("UserSSHKey", func(t *testing.T) {
+ commit, err := git.CommitFromReader(nil, git.Sha1ObjectFormat.EmptyObjectID(), strings.NewReader(`tree a3b1fad553e0f9a2b4a58327bebde36c7da75aa2
+author user2 1752194028 -0700
+committer user2 1752194028 -0700
+gpgsig -----BEGIN SSH SIGNATURE-----
+ U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAguk+sxdKD2pPHTiM809ZFwey63L
+ FaNOEinNxo7rzJZWcAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
+ AAAAQBfX+6mcKZBnXckwHcBFqRuXMD3vTKi1yv5wgrqIxTyr2LWB97xxmO92cvjsr0POQ2
+ 2YA7mQS510Cg2s1uU1XAk=
+ -----END SSH SIGNATURE-----
+
+init project
+`))
+ require.NoError(t, err)
+
+ // the committingUser is guaranteed by the caller, parseCommitWithSSHSignature doesn't do any more checks
+ committingUser := &user_model.User{ID: 999, Name: "user-x"}
+ ret := parseCommitWithSSHSignature(t.Context(), commit, committingUser)
+ require.NotNil(t, ret)
+ assert.True(t, ret.Verified)
+ assert.Equal(t, committingUser.Name+" / "+sshPubKey.Fingerprint, ret.Reason)
+ assert.False(t, ret.Warning)
+ assert.Equal(t, committingUser, ret.SigningUser)
+ assert.Equal(t, committingUser, ret.CommittingUser)
+ assert.Equal(t, sshPubKey.ID, ret.SigningSSHKey.ID)
+ })
+
t.Run("TrustedSSHKey", func(t *testing.T) {
defer test.MockVariableValue(&setting.Repository.Signing.SigningName, "gitea")()
defer test.MockVariableValue(&setting.Repository.Signing.SigningEmail, "gitea@fake.local")()
@@ -41,7 +86,7 @@ Initial commit with signed file
Name: "User Two",
Email: "user2@example.com",
}
- ret := ParseCommitWithSSHSignature(t.Context(), commit, committingUser)
+ ret := parseCommitWithSSHSignature(t.Context(), commit, committingUser)
require.NotNil(t, ret)
assert.True(t, ret.Verified)
assert.False(t, ret.Warning)
diff --git a/services/auth/basic.go b/services/auth/basic.go
index b2bd14ef5d3..6d147deeb13 100644
--- a/services/auth/basic.go
+++ b/services/auth/basic.go
@@ -46,10 +46,10 @@ func (b *Basic) Name() string {
// name/token on successful validation.
// Returns nil if header is empty or validation fails.
func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) {
- // Basic authentication should only fire on API, Feed, Download or on Git or LFSPaths
+ // Basic authentication should only fire on API, Feed, Download, Archives or on Git or LFSPaths
// Not all feed (rss/atom) clients feature the ability to add cookies or headers, so we need to allow basic auth for feeds
detector := newAuthPathDetector(req)
- if !detector.isAPIPath() && !detector.isFeedRequest(req) && !detector.isContainerPath() && !detector.isAttachmentDownload() && !detector.isGitRawOrAttachOrLFSPath() {
+ if !detector.isAPIPath() && !detector.isFeedRequest(req) && !detector.isContainerPath() && !detector.isAttachmentDownload() && !detector.isArchivePath() && !detector.isGitRawOrAttachOrLFSPath() {
return nil, nil
}
diff --git a/services/auth/interface.go b/services/auth/interface.go
index e7eccecea0d..c4bed2b6401 100644
--- a/services/auth/interface.go
+++ b/services/auth/interface.go
@@ -20,7 +20,7 @@ type SessionStore session.Store
// Method represents an authentication method (plugin) for HTTP requests.
type Method interface {
// Verify tries to verify the authentication data contained in the request.
- // If verification is successful returns either an existing user object (with id > 0)
+ // If verification succeeds, it returns either an existing user object (with id > 0)
// or a new user object (with id = 0) populated with the information that was found
// in the authentication data (username or email).
// Second argument returns err if verification fails, otherwise
diff --git a/services/auth/source/oauth2/providers.go b/services/auth/source/oauth2/providers.go
index f2c1bb4894d..75ed41ba668 100644
--- a/services/auth/source/oauth2/providers.go
+++ b/services/auth/source/oauth2/providers.go
@@ -27,6 +27,7 @@ type Provider interface {
DisplayName() string
IconHTML(size int) template.HTML
CustomURLSettings() *CustomURLSettings
+ SupportSSHPublicKey() bool
}
// GothProviderCreator provides a function to create a goth.Provider
diff --git a/services/auth/source/oauth2/providers_base.go b/services/auth/source/oauth2/providers_base.go
index 9d4ab106e5c..d34597d6d98 100644
--- a/services/auth/source/oauth2/providers_base.go
+++ b/services/auth/source/oauth2/providers_base.go
@@ -14,6 +14,13 @@ import (
type BaseProvider struct {
name string
displayName string
+
+ // TODO: maybe some providers also support SSH public keys, then they can set this to true
+ supportSSHPublicKey bool
+}
+
+func (b *BaseProvider) SupportSSHPublicKey() bool {
+ return b.supportSSHPublicKey
}
// Name provides the technical name for this provider
diff --git a/services/auth/source/oauth2/providers_openid.go b/services/auth/source/oauth2/providers_openid.go
index 285876d5ac3..e86dc48232f 100644
--- a/services/auth/source/oauth2/providers_openid.go
+++ b/services/auth/source/oauth2/providers_openid.go
@@ -17,6 +17,10 @@ import (
// OpenIDProvider is a GothProvider for OpenID
type OpenIDProvider struct{}
+func (o *OpenIDProvider) SupportSSHPublicKey() bool {
+ return true
+}
+
// Name provides the technical name for this provider
func (o *OpenIDProvider) Name() string {
return "openidConnect"
diff --git a/services/auth/source/oauth2/source.go b/services/auth/source/oauth2/source.go
index 08837de3777..00d89b3481b 100644
--- a/services/auth/source/oauth2/source.go
+++ b/services/auth/source/oauth2/source.go
@@ -27,6 +27,9 @@ type Source struct {
GroupTeamMap string
GroupTeamMapRemoval bool
RestrictedGroup string
+
+ SSHPublicKeyClaimName string
+ FullNameClaimName string
}
// FromDB fills up an OAuth2Config from serialized format.
diff --git a/services/auth/source/oauth2/store.go b/services/auth/source/oauth2/store.go
index 90fa965602a..7b6b26edc83 100644
--- a/services/auth/source/oauth2/store.go
+++ b/services/auth/source/oauth2/store.go
@@ -11,7 +11,6 @@ import (
"code.gitea.io/gitea/modules/log"
session_module "code.gitea.io/gitea/modules/session"
- chiSession "gitea.com/go-chi/session"
"github.com/gorilla/sessions"
)
@@ -35,11 +34,11 @@ func (st *SessionsStore) New(r *http.Request, name string) (*sessions.Session, e
// getOrNew gets the session from the chi-session if it exists. Override permits the overriding of an unexpected object.
func (st *SessionsStore) getOrNew(r *http.Request, name string, override bool) (*sessions.Session, error) {
- chiStore := chiSession.GetSession(r)
+ store := session_module.GetContextSession(r)
session := sessions.NewSession(st, name)
- rawData := chiStore.Get(name)
+ rawData := store.Get(name)
if rawData != nil {
oldSession, ok := rawData.(*sessions.Session)
if ok {
@@ -56,21 +55,21 @@ func (st *SessionsStore) getOrNew(r *http.Request, name string, override bool) (
}
session.IsNew = override
- session.ID = chiStore.ID() // Simply copy the session id from the chi store
+ session.ID = store.ID() // Simply copy the session id from the chi store
- return session, chiStore.Set(name, session)
+ return session, store.Set(name, session)
}
// Save should persist session to the underlying store implementation.
func (st *SessionsStore) Save(r *http.Request, w http.ResponseWriter, session *sessions.Session) error {
- chiStore := chiSession.GetSession(r)
+ store := session_module.GetContextSession(r)
if session.IsNew {
_, _ = session_module.RegenerateSession(w, r)
session.IsNew = false
}
- if err := chiStore.Set(session.Name(), session); err != nil {
+ if err := store.Set(session.Name(), session); err != nil {
return err
}
@@ -83,7 +82,7 @@ func (st *SessionsStore) Save(r *http.Request, w http.ResponseWriter, session *s
}
}
- return chiStore.Release()
+ return store.Release()
}
type sizeWriter struct {
diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go
index 1a37d70e5af..a60883b4cc5 100644
--- a/services/automerge/automerge.go
+++ b/services/automerge/automerge.go
@@ -187,7 +187,7 @@ func handlePullRequestAutoMerge(pullID int64, sha string) {
}
defer baseGitRepo.Close()
- headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
+ headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
log.Error("GetRefCommitID: %v", err)
return
@@ -225,7 +225,7 @@ func handlePullRequestAutoMerge(pullID int64, sha string) {
return
}
case issues_model.PullRequestFlowAGit:
- headBranchExist := gitrepo.IsReferenceExist(ctx, pr.BaseRepo, pr.GetGitRefName())
+ headBranchExist := gitrepo.IsReferenceExist(ctx, pr.BaseRepo, pr.GetGitHeadRefName())
if !headBranchExist {
log.Warn("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch(Agit): %s]", pr, pr.HeadRepoID, pr.HeadBranch)
return
diff --git a/services/automergequeue/automergequeue.go b/services/automergequeue/automergequeue.go
index cdf257e6c80..fa9c04da874 100644
--- a/services/automergequeue/automergequeue.go
+++ b/services/automergequeue/automergequeue.go
@@ -39,7 +39,7 @@ func StartPRCheckAndAutoMerge(ctx context.Context, pull *issues_model.PullReques
return
}
defer gitRepo.Close()
- commitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
+ commitID, err := gitRepo.GetRefCommitID(pull.GetGitHeadRefName())
if err != nil {
log.Error("GetRefCommitID: %v", err)
return
diff --git a/services/context/base.go b/services/context/base.go
index f3f92b7eeb9..28d6656fd14 100644
--- a/services/context/base.go
+++ b/services/context/base.go
@@ -83,6 +83,7 @@ func (b *Base) RespHeader() http.Header {
}
// HTTPError returned an error to web browser
+// FIXME: many calls to this HTTPError are not right: it shouldn't expose err.Error() directly, it doesn't accept more than one content
func (b *Base) HTTPError(status int, contents ...string) {
v := http.StatusText(status)
if len(contents) > 0 {
diff --git a/services/contexttest/context_tests.go b/services/contexttest/context_tests.go
index b54023897b0..44d9f4a70f0 100644
--- a/services/contexttest/context_tests.go
+++ b/services/contexttest/context_tests.go
@@ -49,7 +49,7 @@ func mockRequest(t *testing.T, reqPath string) *http.Request {
type MockContextOption struct {
Render context.Render
- SessionStore *session.MockStore
+ SessionStore session.Store
}
// MockContext mock context for unit tests
diff --git a/services/convert/pull.go b/services/convert/pull.go
index 8f9679f6497..4acbd880dc6 100644
--- a/services/convert/pull.go
+++ b/services/convert/pull.go
@@ -112,7 +112,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
},
Head: &api.PRBranchInfo{
Name: pr.HeadBranch,
- Ref: fmt.Sprintf("%s%d/head", git.PullPrefix, pr.Index),
+ Ref: pr.GetGitHeadRefName(),
RepoID: -1,
},
}
@@ -170,9 +170,9 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
}
if pr.Flow == issues_model.PullRequestFlowAGit {
- apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitRefName())
+ apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
- log.Error("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
+ log.Error("GetRefCommitID[%s]: %v", pr.GetGitHeadRefName(), err)
return nil
}
apiPullRequest.Head.RepoID = pr.BaseRepoID
@@ -383,7 +383,7 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
},
Head: &api.PRBranchInfo{
Name: pr.HeadBranch,
- Ref: pr.GetGitRefName(),
+ Ref: pr.GetGitHeadRefName(),
RepoID: -1,
},
}
@@ -444,15 +444,15 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
}
}
if apiPullRequest.Head.Ref == "" {
- apiPullRequest.Head.Ref = pr.GetGitRefName()
+ apiPullRequest.Head.Ref = pr.GetGitHeadRefName()
}
if pr.Flow == issues_model.PullRequestFlowAGit {
apiPullRequest.Head.Name = ""
}
- apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitRefName())
+ apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
- log.Error("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
+ log.Error("GetRefCommitID[%s]: %v", pr.GetGitHeadRefName(), err)
}
if len(apiPullRequest.Head.Sha) == 0 && len(apiPullRequest.Head.Ref) != 0 {
diff --git a/services/convert/repository.go b/services/convert/repository.go
index 614eb58a883..a364591bb8f 100644
--- a/services/convert/repository.go
+++ b/services/convert/repository.go
@@ -251,7 +251,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
RepoTransfer: transfer,
Topics: util.SliceNilAsEmpty(repo.Topics),
ObjectFormatName: repo.ObjectFormatName,
- Licenses: repoLicenses.StringList(),
+ Licenses: util.SliceNilAsEmpty(repoLicenses.StringList()),
}
}
diff --git a/services/doctor/mergebase.go b/services/doctor/mergebase.go
index 482bcd0a465..cbd8aa59fdb 100644
--- a/services/doctor/mergebase.go
+++ b/services/doctor/mergebase.go
@@ -42,7 +42,7 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro
if !pr.HasMerged {
var err error
- pr.MergeBase, _, err = git.NewCommand("merge-base").AddDashesAndList(pr.BaseBranch, pr.GetGitRefName()).RunStdString(ctx, &git.RunOpts{Dir: repoPath})
+ pr.MergeBase, _, err = git.NewCommand("merge-base").AddDashesAndList(pr.BaseBranch, pr.GetGitHeadRefName()).RunStdString(ctx, &git.RunOpts{Dir: repoPath})
if err != nil {
var err2 error
pr.MergeBase, _, err2 = git.NewCommand("rev-parse").AddDynamicArguments(git.BranchPrefix+pr.BaseBranch).RunStdString(ctx, &git.RunOpts{Dir: repoPath})
@@ -63,7 +63,7 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro
}
refs := append([]string{}, parents[1:]...)
- refs = append(refs, pr.GetGitRefName())
+ refs = append(refs, pr.GetGitHeadRefName())
cmd := git.NewCommand("merge-base").AddDashesAndList(refs...)
pr.MergeBase, _, err = cmd.RunStdString(ctx, &git.RunOpts{Dir: repoPath})
if err != nil {
diff --git a/services/externalaccount/link.go b/services/externalaccount/link.go
deleted file mode 100644
index ab853140cb4..00000000000
--- a/services/externalaccount/link.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2021 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package externalaccount
-
-import (
- "context"
- "errors"
-
- user_model "code.gitea.io/gitea/models/user"
-
- "github.com/markbates/goth"
-)
-
-// Store represents a thing that stores things
-type Store interface {
- Get(any) any
- Set(any, any) error
- Release() error
-}
-
-// LinkAccountFromStore links the provided user with a stored external user
-func LinkAccountFromStore(ctx context.Context, store Store, user *user_model.User) error {
- gothUser := store.Get("linkAccountGothUser")
- if gothUser == nil {
- return errors.New("not in LinkAccount session")
- }
-
- return LinkAccountToUser(ctx, user, gothUser.(goth.User))
-}
diff --git a/services/externalaccount/user.go b/services/externalaccount/user.go
index b53e33654a2..1eddc4a5df3 100644
--- a/services/externalaccount/user.go
+++ b/services/externalaccount/user.go
@@ -8,7 +8,6 @@ import (
"strconv"
"strings"
- "code.gitea.io/gitea/models/auth"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
@@ -17,15 +16,11 @@ import (
"github.com/markbates/goth"
)
-func toExternalLoginUser(ctx context.Context, user *user_model.User, gothUser goth.User) (*user_model.ExternalLoginUser, error) {
- authSource, err := auth.GetActiveOAuth2SourceByName(ctx, gothUser.Provider)
- if err != nil {
- return nil, err
- }
+func toExternalLoginUser(authSourceID int64, user *user_model.User, gothUser goth.User) *user_model.ExternalLoginUser {
return &user_model.ExternalLoginUser{
ExternalID: gothUser.UserID,
UserID: user.ID,
- LoginSourceID: authSource.ID,
+ LoginSourceID: authSourceID,
RawData: gothUser.RawData,
Provider: gothUser.Provider,
Email: gothUser.Email,
@@ -40,15 +35,12 @@ func toExternalLoginUser(ctx context.Context, user *user_model.User, gothUser go
AccessTokenSecret: gothUser.AccessTokenSecret,
RefreshToken: gothUser.RefreshToken,
ExpiresAt: gothUser.ExpiresAt,
- }, nil
+ }
}
// LinkAccountToUser link the gothUser to the user
-func LinkAccountToUser(ctx context.Context, user *user_model.User, gothUser goth.User) error {
- externalLoginUser, err := toExternalLoginUser(ctx, user, gothUser)
- if err != nil {
- return err
- }
+func LinkAccountToUser(ctx context.Context, authSourceID int64, user *user_model.User, gothUser goth.User) error {
+ externalLoginUser := toExternalLoginUser(authSourceID, user, gothUser)
if err := user_model.LinkExternalToUser(ctx, user, externalLoginUser); err != nil {
return err
@@ -72,12 +64,8 @@ func LinkAccountToUser(ctx context.Context, user *user_model.User, gothUser goth
}
// EnsureLinkExternalToUser link the gothUser to the user
-func EnsureLinkExternalToUser(ctx context.Context, user *user_model.User, gothUser goth.User) error {
- externalLoginUser, err := toExternalLoginUser(ctx, user, gothUser)
- if err != nil {
- return err
- }
-
+func EnsureLinkExternalToUser(ctx context.Context, authSourceID int64, user *user_model.User, gothUser goth.User) error {
+ externalLoginUser := toExternalLoginUser(authSourceID, user, gothUser)
return user_model.EnsureLinkExternalToUser(ctx, externalLoginUser)
}
diff --git a/services/forms/auth_form.go b/services/forms/auth_form.go
index a8f97572b10..886110236c2 100644
--- a/services/forms/auth_form.go
+++ b/services/forms/auth_form.go
@@ -18,45 +18,54 @@ type AuthenticationForm struct {
Type int `binding:"Range(2,7)"`
Name string `binding:"Required;MaxSize(30)"`
TwoFactorPolicy string
+ IsActive bool
+ IsSyncEnabled bool
- Host string
- Port int
- BindDN string
- BindPassword string
- UserBase string
- UserDN string
- AttributeUsername string
- AttributeName string
- AttributeSurname string
- AttributeMail string
- AttributeSSHPublicKey string
- AttributeAvatar string
- AttributesInBind bool
- UsePagedSearch bool
- SearchPageSize int
- Filter string
- AdminFilter string
- GroupsEnabled bool
- GroupDN string
- GroupFilter string
- GroupMemberUID string
- UserUID string
- RestrictedFilter string
- AllowDeactivateAll bool
- IsActive bool
- IsSyncEnabled bool
- SMTPAuth string
- SMTPHost string
- SMTPPort int
- AllowedDomains string
- SecurityProtocol int `binding:"Range(0,2)"`
- TLS bool
- SkipVerify bool
- HeloHostname string
- DisableHelo bool
- ForceSMTPS bool
- PAMServiceName string
- PAMEmailDomain string
+ // LDAP
+ Host string
+ Port int
+ BindDN string
+ BindPassword string
+ UserBase string
+ UserDN string
+ AttributeUsername string
+ AttributeName string
+ AttributeSurname string
+ AttributeMail string
+ AttributeSSHPublicKey string
+ AttributeAvatar string
+ AttributesInBind bool
+ UsePagedSearch bool
+ SearchPageSize int
+ Filter string
+ AdminFilter string
+ GroupsEnabled bool
+ GroupDN string
+ GroupFilter string
+ GroupMemberUID string
+ UserUID string
+ RestrictedFilter string
+ AllowDeactivateAll bool
+ GroupTeamMap string `binding:"ValidGroupTeamMap"`
+ GroupTeamMapRemoval bool
+
+ // SMTP
+ SMTPAuth string
+ SMTPHost string
+ SMTPPort int
+ AllowedDomains string
+ SecurityProtocol int `binding:"Range(0,2)"`
+ TLS bool
+ SkipVerify bool
+ HeloHostname string
+ DisableHelo bool
+ ForceSMTPS bool
+
+ // PAM
+ PAMServiceName string
+ PAMEmailDomain string
+
+ // Oauth2 & OIDC
Oauth2Provider string
Oauth2Key string
Oauth2Secret string
@@ -76,13 +85,15 @@ type AuthenticationForm struct {
Oauth2RestrictedGroup string
Oauth2GroupTeamMap string `binding:"ValidGroupTeamMap"`
Oauth2GroupTeamMapRemoval bool
- SSPIAutoCreateUsers bool
- SSPIAutoActivateUsers bool
- SSPIStripDomainNames bool
- SSPISeparatorReplacement string `binding:"AlphaDashDot;MaxSize(5)"`
- SSPIDefaultLanguage string
- GroupTeamMap string `binding:"ValidGroupTeamMap"`
- GroupTeamMapRemoval bool
+ Oauth2SSHPublicKeyClaimName string
+ Oauth2FullNameClaimName string
+
+ // SSPI
+ SSPIAutoCreateUsers bool
+ SSPIAutoActivateUsers bool
+ SSPIStripDomainNames bool
+ SSPISeparatorReplacement string `binding:"AlphaDashDot;MaxSize(5)"`
+ SSPIDefaultLanguage string
}
// Validate validates fields
diff --git a/services/git/commit.go b/services/git/commit.go
index 2e0e8a5096f..e4755ef93d7 100644
--- a/services/git/commit.go
+++ b/services/git/commit.go
@@ -35,13 +35,6 @@ func ParseCommitsWithSignature(ctx context.Context, repo *repo_model.Repository,
for _, c := range oldCommits {
committerUser := emailUsers.GetByEmail(c.Committer.Email) // FIXME: why ValidateCommitsWithEmails uses "Author", but ParseCommitsWithSignature uses "Committer"?
- if committerUser == nil {
- committerUser = &user_model.User{
- Name: c.Committer.Name,
- Email: c.Committer.Email,
- }
- }
-
signCommit := &asymkey_model.SignCommit{
UserCommit: c,
Verification: asymkey_service.ParseCommitWithSignatureCommitter(ctx, c.Commit, committerUser),
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index 99643298765..7c99e049d54 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -179,7 +179,7 @@ func (d *DiffLine) GetExpandDirection() DiffLineExpandDirection {
}
func getDiffLineSectionInfo(treePath, line string, lastLeftIdx, lastRightIdx int) *DiffLineSectionInfo {
- leftLine, leftHunk, rightLine, righHunk := git.ParseDiffHunkString(line)
+ leftLine, leftHunk, rightLine, rightHunk := git.ParseDiffHunkString(line)
return &DiffLineSectionInfo{
Path: treePath,
@@ -188,7 +188,7 @@ func getDiffLineSectionInfo(treePath, line string, lastLeftIdx, lastRightIdx int
LeftIdx: leftLine,
RightIdx: rightLine,
LeftHunkSize: leftHunk,
- RightHunkSize: righHunk,
+ RightHunkSize: rightHunk,
}
}
@@ -290,7 +290,7 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine, loc
// try to find equivalent diff line. ignore, otherwise
switch diffLine.Type {
case DiffLineSection:
- return getLineContent(diffLine.Content[1:], locale)
+ return getLineContent(diffLine.Content, locale)
case DiffLineAdd:
compareDiffLine := diffSection.GetLine(diffLine.Match)
return diffSection.getDiffLineForRender(DiffLineAdd, compareDiffLine, diffLine, locale)
@@ -856,6 +856,7 @@ func parseHunks(ctx context.Context, curFile *DiffFile, maxLines, maxLineCharact
lastLeftIdx = -1
curFile.Sections = append(curFile.Sections, curSection)
+ // FIXME: the "-1" can't be right, these "line idx" are all 1-based, maybe there are other bugs that covers this bug.
lineSectionInfo := getDiffLineSectionInfo(curFile.Name, line, leftLine-1, rightLine-1)
diffLine := &DiffLine{
Type: DiffLineSection,
@@ -1184,13 +1185,13 @@ func GetDiffForAPI(ctx context.Context, gitRepo *git.Repository, opts *DiffOptio
return diff, err
}
-func GetDiffForRender(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) {
+func GetDiffForRender(ctx context.Context, repoLink string, gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) {
diff, beforeCommit, afterCommit, err := getDiffBasic(ctx, gitRepo, opts, files...)
if err != nil {
return nil, err
}
- checker, err := attribute.NewBatchChecker(gitRepo, opts.AfterCommitID, []string{attribute.LinguistVendored, attribute.LinguistGenerated, attribute.LinguistLanguage, attribute.GitlabLanguage})
+ checker, err := attribute.NewBatchChecker(gitRepo, opts.AfterCommitID, []string{attribute.LinguistVendored, attribute.LinguistGenerated, attribute.LinguistLanguage, attribute.GitlabLanguage, attribute.Diff})
if err != nil {
return nil, err
}
@@ -1199,6 +1200,7 @@ func GetDiffForRender(ctx context.Context, gitRepo *git.Repository, opts *DiffOp
for _, diffFile := range diff.Files {
isVendored := optional.None[bool]()
isGenerated := optional.None[bool]()
+ attrDiff := optional.None[string]()
attrs, err := checker.CheckPath(diffFile.Name)
if err == nil {
isVendored, isGenerated = attrs.GetVendored(), attrs.GetGenerated()
@@ -1206,11 +1208,12 @@ func GetDiffForRender(ctx context.Context, gitRepo *git.Repository, opts *DiffOp
if language.Has() {
diffFile.Language = language.Value()
}
+ attrDiff = attrs.Get(attribute.Diff).ToString()
}
// Populate Submodule URLs
if diffFile.SubmoduleDiffInfo != nil {
- diffFile.SubmoduleDiffInfo.PopulateURL(diffFile, beforeCommit, afterCommit)
+ diffFile.SubmoduleDiffInfo.PopulateURL(repoLink, diffFile, beforeCommit, afterCommit)
}
if !isVendored.Has() {
@@ -1227,7 +1230,8 @@ func GetDiffForRender(ctx context.Context, gitRepo *git.Repository, opts *DiffOp
diffFile.Sections = append(diffFile.Sections, tailSection)
}
- if !setting.Git.DisableDiffHighlight {
+ shouldFullFileHighlight := !setting.Git.DisableDiffHighlight && attrDiff.Value() == ""
+ if shouldFullFileHighlight {
if limitedContent.LeftContent != nil && limitedContent.LeftContent.buf.Len() < MaxDiffHighlightEntireFileSize {
diffFile.highlightedLeftLines = highlightCodeLines(diffFile, true /* left */, limitedContent.LeftContent.buf.String())
}
diff --git a/services/gitdiff/submodule.go b/services/gitdiff/submodule.go
index 02ca666544c..4347743e3d0 100644
--- a/services/gitdiff/submodule.go
+++ b/services/gitdiff/submodule.go
@@ -20,7 +20,7 @@ type SubmoduleDiffInfo struct {
PreviousRefID string
}
-func (si *SubmoduleDiffInfo) PopulateURL(diffFile *DiffFile, leftCommit, rightCommit *git.Commit) {
+func (si *SubmoduleDiffInfo) PopulateURL(repoLink string, diffFile *DiffFile, leftCommit, rightCommit *git.Commit) {
si.SubmoduleName = diffFile.Name
submoduleCommit := rightCommit // If the submodule is added or updated, check at the right commit
if diffFile.IsDeleted {
@@ -30,18 +30,19 @@ func (si *SubmoduleDiffInfo) PopulateURL(diffFile *DiffFile, leftCommit, rightCo
return
}
- submodule, err := submoduleCommit.GetSubModule(diffFile.GetDiffFileName())
+ submoduleFullPath := diffFile.GetDiffFileName()
+ submodule, err := submoduleCommit.GetSubModule(submoduleFullPath)
if err != nil {
- log.Error("Unable to PopulateURL for submodule %q: GetSubModule: %v", diffFile.GetDiffFileName(), err)
+ log.Error("Unable to PopulateURL for submodule %q: GetSubModule: %v", submoduleFullPath, err)
return // ignore the error, do not cause 500 errors for end users
}
if submodule != nil {
- si.SubmoduleFile = git.NewCommitSubmoduleFile(submodule.URL, submoduleCommit.ID.String())
+ si.SubmoduleFile = git.NewCommitSubmoduleFile(repoLink, submoduleFullPath, submodule.URL, submoduleCommit.ID.String())
}
}
func (si *SubmoduleDiffInfo) CommitRefIDLinkHTML(ctx context.Context, commitID string) template.HTML {
- webLink := si.SubmoduleFile.SubmoduleWebLink(ctx, commitID)
+ webLink := si.SubmoduleFile.SubmoduleWebLinkTree(ctx, commitID)
if webLink == nil {
return htmlutil.HTMLFormat("%s", base.ShortSha(commitID))
}
@@ -49,7 +50,7 @@ func (si *SubmoduleDiffInfo) CommitRefIDLinkHTML(ctx context.Context, commitID s
}
func (si *SubmoduleDiffInfo) CompareRefIDLinkHTML(ctx context.Context) template.HTML {
- webLink := si.SubmoduleFile.SubmoduleWebLink(ctx, si.PreviousRefID, si.NewRefID)
+ webLink := si.SubmoduleFile.SubmoduleWebLinkCompare(ctx, si.PreviousRefID, si.NewRefID)
if webLink == nil {
return htmlutil.HTMLFormat("%s...%s", base.ShortSha(si.PreviousRefID), base.ShortSha(si.NewRefID))
}
@@ -57,7 +58,7 @@ func (si *SubmoduleDiffInfo) CompareRefIDLinkHTML(ctx context.Context) template.
}
func (si *SubmoduleDiffInfo) SubmoduleRepoLinkHTML(ctx context.Context) template.HTML {
- webLink := si.SubmoduleFile.SubmoduleWebLink(ctx)
+ webLink := si.SubmoduleFile.SubmoduleWebLinkTree(ctx)
if webLink == nil {
return htmlutil.HTMLFormat("%s", si.SubmoduleName)
}
diff --git a/services/gitdiff/submodule_test.go b/services/gitdiff/submodule_test.go
index 152c5b7066d..c793969f0e6 100644
--- a/services/gitdiff/submodule_test.go
+++ b/services/gitdiff/submodule_test.go
@@ -227,7 +227,7 @@ func TestSubmoduleInfo(t *testing.T) {
assert.EqualValues(t, "aaaa...bbbb", sdi.CompareRefIDLinkHTML(ctx))
assert.EqualValues(t, "name", sdi.SubmoduleRepoLinkHTML(ctx))
- sdi.SubmoduleFile = git.NewCommitSubmoduleFile("https://github.com/owner/repo", "1234")
+ sdi.SubmoduleFile = git.NewCommitSubmoduleFile("/any/repo-link", "fullpath", "https://github.com/owner/repo", "1234")
assert.EqualValues(t, `1111`, sdi.CommitRefIDLinkHTML(ctx, "1111"))
assert.EqualValues(t, `aaaa...bbbb`, sdi.CompareRefIDLinkHTML(ctx))
assert.EqualValues(t, `name`, sdi.SubmoduleRepoLinkHTML(ctx))
diff --git a/services/issue/issue.go b/services/issue/issue.go
index 2cb5f2801d4..f03be3e18f6 100644
--- a/services/issue/issue.go
+++ b/services/issue/issue.go
@@ -200,7 +200,7 @@ func DeleteIssue(ctx context.Context, doer *user_model.User, gitRepo *git.Reposi
// delete pull request related git data
if issue.IsPull && gitRepo != nil {
- if err := gitRepo.RemoveReference(fmt.Sprintf("%s%d/head", git.PullPrefix, issue.PullRequest.Index)); err != nil {
+ if err := gitRepo.RemoveReference(issue.PullRequest.GetGitHeadRefName()); err != nil {
return err
}
}
diff --git a/services/issue/pull.go b/services/issue/pull.go
index 3543b05b18f..512fdf78e84 100644
--- a/services/issue/pull.go
+++ b/services/issue/pull.go
@@ -97,14 +97,14 @@ func PullRequestCodeOwnersReview(ctx context.Context, pr *issues_model.PullReque
}
// get the mergebase
- mergeBase, err := getMergeBase(repo, pr, git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName())
+ mergeBase, err := getMergeBase(repo, pr, git.BranchPrefix+pr.BaseBranch, pr.GetGitHeadRefName())
if err != nil {
return nil, err
}
// https://github.com/go-gitea/gitea/issues/29763, we need to get the files changed
// between the merge base and the head commit but not the base branch and the head commit
- changedFiles, err := repo.GetFilesChangedBetween(mergeBase, pr.GetGitRefName())
+ changedFiles, err := repo.GetFilesChangedBetween(mergeBase, pr.GetGitHeadRefName())
if err != nil {
return nil, err
}
diff --git a/services/lfs/server.go b/services/lfs/server.go
index c44cc35e53c..c9d9f164bf3 100644
--- a/services/lfs/server.go
+++ b/services/lfs/server.go
@@ -43,6 +43,7 @@ type requestContext struct {
User string
Repo string
Authorization string
+ Method string
}
// Claims is a JWT Token Claims
@@ -397,6 +398,7 @@ func getRequestContext(ctx *context.Context) *requestContext {
User: ctx.PathParam("username"),
Repo: strings.TrimSuffix(ctx.PathParam("reponame"), ".git"),
Authorization: ctx.Req.Header.Get("Authorization"),
+ Method: ctx.Req.Method,
}
}
@@ -465,7 +467,7 @@ func buildObjectResponse(rc *requestContext, pointer lfs_module.Pointer, downloa
var link *lfs_module.Link
if setting.LFS.Storage.ServeDirect() {
// If we have a signed url (S3, object storage), redirect to this directly.
- u, err := storage.LFS.URL(pointer.RelativePath(), pointer.Oid, nil)
+ u, err := storage.LFS.URL(pointer.RelativePath(), pointer.Oid, rc.Method, nil)
if u != nil && err == nil {
// Presigned url does not need the Authorization header
// https://github.com/go-gitea/gitea/issues/21525
diff --git a/services/mailer/mail.go b/services/mailer/mail.go
index aa51cbdbcfb..d81b6d10afc 100644
--- a/services/mailer/mail.go
+++ b/services/mailer/mail.go
@@ -15,7 +15,7 @@ import (
"mime"
"regexp"
"strings"
- texttmpl "text/template"
+ "sync/atomic"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
@@ -23,6 +23,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
+ "code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/typesniffer"
sender_service "code.gitea.io/gitea/services/mailer/sender"
@@ -31,11 +32,13 @@ import (
const mailMaxSubjectRunes = 256 // There's no actual limit for subject in RFC 5322
-var (
- bodyTemplates *template.Template
- subjectTemplates *texttmpl.Template
- subjectRemoveSpaces = regexp.MustCompile(`[\s]+`)
-)
+var loadedTemplates atomic.Pointer[templates.MailTemplates]
+
+var subjectRemoveSpaces = regexp.MustCompile(`[\s]+`)
+
+func LoadedTemplates() *templates.MailTemplates {
+ return loadedTemplates.Load()
+}
// SendTestMail sends a test mail
func SendTestMail(email string) error {
@@ -171,3 +174,41 @@ func fromDisplayName(u *user_model.User) string {
}
return u.GetCompleteName()
}
+
+func generateMetadataHeaders(repo *repo_model.Repository) map[string]string {
+ return map[string]string{
+ // https://datatracker.ietf.org/doc/html/rfc2919
+ "List-ID": fmt.Sprintf("%s <%s.%s.%s>", repo.FullName(), repo.Name, repo.OwnerName, setting.Domain),
+
+ // https://datatracker.ietf.org/doc/html/rfc2369
+ "List-Archive": fmt.Sprintf("<%s>", repo.HTMLURL()),
+
+ "X-Mailer": "Gitea",
+
+ "X-Gitea-Repository": repo.Name,
+ "X-Gitea-Repository-Path": repo.FullName(),
+ "X-Gitea-Repository-Link": repo.HTMLURL(),
+
+ "X-GitLab-Project": repo.Name,
+ "X-GitLab-Project-Path": repo.FullName(),
+ }
+}
+
+func generateSenderRecipientHeaders(doer, recipient *user_model.User) map[string]string {
+ return map[string]string{
+ "X-Gitea-Sender": doer.Name,
+ "X-Gitea-Recipient": recipient.Name,
+ "X-Gitea-Recipient-Address": recipient.Email,
+ "X-GitHub-Sender": doer.Name,
+ "X-GitHub-Recipient": recipient.Name,
+ "X-GitHub-Recipient-Address": recipient.Email,
+ }
+}
+
+func generateReasonHeaders(reason string) map[string]string {
+ return map[string]string{
+ "X-Gitea-Reason": reason,
+ "X-GitHub-Reason": reason,
+ "X-GitLab-NotificationReason": reason,
+ }
+}
diff --git a/services/mailer/mail_issue_common.go b/services/mailer/mail_issue_common.go
index ebfd52162cb..a34d8a68c97 100644
--- a/services/mailer/mail_issue_common.go
+++ b/services/mailer/mail_issue_common.go
@@ -7,6 +7,7 @@ import (
"bytes"
"context"
"fmt"
+ "maps"
"strconv"
"strings"
"time"
@@ -29,7 +30,7 @@ import (
// Many e-mail service providers have limitations on the size of the email body, it's usually from 10MB to 25MB
const maxEmailBodySize = 9_000_000
-func fallbackMailSubject(issue *issues_model.Issue) string {
+func fallbackIssueMailSubject(issue *issues_model.Issue) string {
return fmt.Sprintf("[%s] %s (#%d)", issue.Repo.FullName(), issue.Title, issue.Index)
}
@@ -86,7 +87,7 @@ func composeIssueCommentMessages(ctx context.Context, comment *mailComment, lang
if actName != "new" {
prefix = "Re: "
}
- fallback = prefix + fallbackMailSubject(comment.Issue)
+ fallback = prefix + fallbackIssueMailSubject(comment.Issue)
if comment.Comment != nil && comment.Comment.Review != nil {
reviewComments = make([]*issues_model.Comment, 0, 10)
@@ -119,7 +120,7 @@ func composeIssueCommentMessages(ctx context.Context, comment *mailComment, lang
}
var mailSubject bytes.Buffer
- if err := subjectTemplates.ExecuteTemplate(&mailSubject, tplName, mailMeta); err == nil {
+ if err := LoadedTemplates().SubjectTemplates.ExecuteTemplate(&mailSubject, tplName, mailMeta); err == nil {
subject = sanitizeSubject(mailSubject.String())
if subject == "" {
subject = fallback
@@ -134,7 +135,7 @@ func composeIssueCommentMessages(ctx context.Context, comment *mailComment, lang
var mailBody bytes.Buffer
- if err := bodyTemplates.ExecuteTemplate(&mailBody, tplName, mailMeta); err != nil {
+ if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&mailBody, tplName, mailMeta); err != nil {
log.Error("ExecuteTemplate [%s]: %v", tplName+"/body", err)
}
@@ -202,7 +203,7 @@ func composeIssueCommentMessages(ctx context.Context, comment *mailComment, lang
msg.SetHeader("References", references...)
msg.SetHeader("List-Unsubscribe", listUnsubscribe...)
- for key, value := range generateAdditionalHeaders(comment, actType, recipient) {
+ for key, value := range generateAdditionalHeadersForIssue(comment, actType, recipient) {
msg.SetHeader(key, value)
}
@@ -260,14 +261,14 @@ func actionToTemplate(issue *issues_model.Issue, actionType activities_model.Act
}
template = typeName + "/" + name
- ok := bodyTemplates.Lookup(template) != nil
+ ok := LoadedTemplates().BodyTemplates.Lookup(template) != nil
if !ok && typeName != "issue" {
template = "issue/" + name
- ok = bodyTemplates.Lookup(template) != nil
+ ok = LoadedTemplates().BodyTemplates.Lookup(template) != nil
}
if !ok {
template = typeName + "/default"
- ok = bodyTemplates.Lookup(template) != nil
+ ok = LoadedTemplates().BodyTemplates.Lookup(template) != nil
}
if !ok {
template = "issue/default"
@@ -302,35 +303,18 @@ func generateMessageIDForIssue(issue *issues_model.Issue, comment *issues_model.
return fmt.Sprintf("<%s/%s/%d%s@%s>", issue.Repo.FullName(), path, issue.Index, extra, setting.Domain)
}
-func generateAdditionalHeaders(ctx *mailComment, reason string, recipient *user_model.User) map[string]string {
+func generateAdditionalHeadersForIssue(ctx *mailComment, reason string, recipient *user_model.User) map[string]string {
repo := ctx.Issue.Repo
- return map[string]string{
- // https://datatracker.ietf.org/doc/html/rfc2919
- "List-ID": fmt.Sprintf("%s <%s.%s.%s>", repo.FullName(), repo.Name, repo.OwnerName, setting.Domain),
+ issueID := strconv.FormatInt(ctx.Issue.Index, 10)
+ headers := generateMetadataHeaders(repo)
- // https://datatracker.ietf.org/doc/html/rfc2369
- "List-Archive": fmt.Sprintf("<%s>", repo.HTMLURL()),
+ maps.Copy(headers, generateSenderRecipientHeaders(ctx.Doer, recipient))
+ maps.Copy(headers, generateReasonHeaders(reason))
- "X-Mailer": "Gitea",
- "X-Gitea-Reason": reason,
- "X-Gitea-Sender": ctx.Doer.Name,
- "X-Gitea-Recipient": recipient.Name,
- "X-Gitea-Recipient-Address": recipient.Email,
- "X-Gitea-Repository": repo.Name,
- "X-Gitea-Repository-Path": repo.FullName(),
- "X-Gitea-Repository-Link": repo.HTMLURL(),
- "X-Gitea-Issue-ID": strconv.FormatInt(ctx.Issue.Index, 10),
- "X-Gitea-Issue-Link": ctx.Issue.HTMLURL(),
+ headers["X-Gitea-Issue-ID"] = issueID
+ headers["X-Gitea-Issue-Link"] = ctx.Issue.HTMLURL()
+ headers["X-GitLab-Issue-IID"] = issueID
- "X-GitHub-Reason": reason,
- "X-GitHub-Sender": ctx.Doer.Name,
- "X-GitHub-Recipient": recipient.Name,
- "X-GitHub-Recipient-Address": recipient.Email,
-
- "X-GitLab-NotificationReason": reason,
- "X-GitLab-Project": repo.Name,
- "X-GitLab-Project-Path": repo.FullName(),
- "X-GitLab-Issue-IID": strconv.FormatInt(ctx.Issue.Index, 10),
- }
+ return headers
}
diff --git a/services/mailer/mail_release.go b/services/mailer/mail_release.go
index bfff73c39c8..fd97fb53124 100644
--- a/services/mailer/mail_release.go
+++ b/services/mailer/mail_release.go
@@ -79,7 +79,7 @@ func mailNewRelease(ctx context.Context, lang string, tos []*user_model.User, re
var mailBody bytes.Buffer
- if err := bodyTemplates.ExecuteTemplate(&mailBody, string(tplNewReleaseMail), mailMeta); err != nil {
+ if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&mailBody, string(tplNewReleaseMail), mailMeta); err != nil {
log.Error("ExecuteTemplate [%s]: %v", string(tplNewReleaseMail)+"/body", err)
return
}
diff --git a/services/mailer/mail_repo.go b/services/mailer/mail_repo.go
index b6b2d5ca07e..1ec7995ab94 100644
--- a/services/mailer/mail_repo.go
+++ b/services/mailer/mail_repo.go
@@ -78,7 +78,7 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
"Destination": destination,
}
- if err := bodyTemplates.ExecuteTemplate(&content, string(mailRepoTransferNotify), data); err != nil {
+ if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(mailRepoTransferNotify), data); err != nil {
return err
}
diff --git a/services/mailer/mail_team_invite.go b/services/mailer/mail_team_invite.go
index f4aa788dec8..034dc14e3d7 100644
--- a/services/mailer/mail_team_invite.go
+++ b/services/mailer/mail_team_invite.go
@@ -62,7 +62,7 @@ func MailTeamInvite(ctx context.Context, inviter *user_model.User, team *org_mod
}
var mailBody bytes.Buffer
- if err := bodyTemplates.ExecuteTemplate(&mailBody, string(tplTeamInviteMail), mailMeta); err != nil {
+ if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&mailBody, string(tplTeamInviteMail), mailMeta); err != nil {
log.Error("ExecuteTemplate [%s]: %v", string(tplTeamInviteMail)+"/body", err)
return err
}
diff --git a/services/mailer/mail_test.go b/services/mailer/mail_test.go
index b15949f3524..24f5d39d50d 100644
--- a/services/mailer/mail_test.go
+++ b/services/mailer/mail_test.go
@@ -16,6 +16,7 @@ import (
"testing"
texttmpl "text/template"
+ actions_model "code.gitea.io/gitea/models/actions"
activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
@@ -25,6 +26,7 @@ import (
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
+ "code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/services/attachment"
sender_service "code.gitea.io/gitea/services/mailer/sender"
@@ -95,6 +97,13 @@ func prepareMailerBase64Test(t *testing.T) (doer *user_model.User, repo *repo_mo
return user, repo, issue, att1, att2
}
+func prepareMailTemplates(name, subjectTmpl, bodyTmpl string) {
+ loadedTemplates.Store(&templates.MailTemplates{
+ SubjectTemplates: texttmpl.Must(texttmpl.New(name).Parse(subjectTmpl)),
+ BodyTemplates: template.Must(template.New(name).Parse(bodyTmpl)),
+ })
+}
+
func TestComposeIssueComment(t *testing.T) {
doer, _, issue, comment := prepareMailerTest(t)
@@ -107,8 +116,7 @@ func TestComposeIssueComment(t *testing.T) {
setting.IncomingEmail.Enabled = true
defer func() { setting.IncomingEmail.Enabled = false }()
- subjectTemplates = texttmpl.Must(texttmpl.New("issue/comment").Parse(subjectTpl))
- bodyTemplates = template.Must(template.New("issue/comment").Parse(bodyTpl))
+ prepareMailTemplates("issue/comment", subjectTpl, bodyTpl)
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}}
msgs, err := composeIssueCommentMessages(t.Context(), &mailComment{
@@ -153,8 +161,7 @@ func TestComposeIssueComment(t *testing.T) {
func TestMailMentionsComment(t *testing.T) {
doer, _, issue, comment := prepareMailerTest(t)
comment.Poster = doer
- subjectTemplates = texttmpl.Must(texttmpl.New("issue/comment").Parse(subjectTpl))
- bodyTemplates = template.Must(template.New("issue/comment").Parse(bodyTpl))
+ prepareMailTemplates("issue/comment", subjectTpl, bodyTpl)
mails := 0
defer test.MockVariableValue(&SendAsync, func(msgs ...*sender_service.Message) {
@@ -169,9 +176,7 @@ func TestMailMentionsComment(t *testing.T) {
func TestComposeIssueMessage(t *testing.T) {
doer, _, issue, _ := prepareMailerTest(t)
- subjectTemplates = texttmpl.Must(texttmpl.New("issue/new").Parse(subjectTpl))
- bodyTemplates = template.Must(template.New("issue/new").Parse(bodyTpl))
-
+ prepareMailTemplates("issue/new", subjectTpl, bodyTpl)
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}}
msgs, err := composeIssueCommentMessages(t.Context(), &mailComment{
Issue: issue, Doer: doer, ActionType: activities_model.ActionCreateIssue,
@@ -200,15 +205,14 @@ func TestTemplateSelection(t *testing.T) {
doer, repo, issue, comment := prepareMailerTest(t)
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}}
- subjectTemplates = texttmpl.Must(texttmpl.New("issue/default").Parse("issue/default/subject"))
- texttmpl.Must(subjectTemplates.New("issue/new").Parse("issue/new/subject"))
- texttmpl.Must(subjectTemplates.New("pull/comment").Parse("pull/comment/subject"))
- texttmpl.Must(subjectTemplates.New("issue/close").Parse("")) // Must default to fallback subject
+ prepareMailTemplates("issue/default", "issue/default/subject", "issue/default/body")
- bodyTemplates = template.Must(template.New("issue/default").Parse("issue/default/body"))
- template.Must(bodyTemplates.New("issue/new").Parse("issue/new/body"))
- template.Must(bodyTemplates.New("pull/comment").Parse("pull/comment/body"))
- template.Must(bodyTemplates.New("issue/close").Parse("issue/close/body"))
+ texttmpl.Must(LoadedTemplates().SubjectTemplates.New("issue/new").Parse("issue/new/subject"))
+ texttmpl.Must(LoadedTemplates().SubjectTemplates.New("pull/comment").Parse("pull/comment/subject"))
+ texttmpl.Must(LoadedTemplates().SubjectTemplates.New("issue/close").Parse("")) // Must default to a fallback subject
+ template.Must(LoadedTemplates().BodyTemplates.New("issue/new").Parse("issue/new/body"))
+ template.Must(LoadedTemplates().BodyTemplates.New("pull/comment").Parse("pull/comment/body"))
+ template.Must(LoadedTemplates().BodyTemplates.New("issue/close").Parse("issue/close/body"))
expect := func(t *testing.T, msg *sender_service.Message, expSubject, expBody string) {
subject := msg.ToMessage().GetGenHeader("Subject")
@@ -253,9 +257,7 @@ func TestTemplateServices(t *testing.T) {
expect := func(t *testing.T, issue *issues_model.Issue, comment *issues_model.Comment, doer *user_model.User,
actionType activities_model.ActionType, fromMention bool, tplSubject, tplBody, expSubject, expBody string,
) {
- subjectTemplates = texttmpl.Must(texttmpl.New("issue/default").Parse(tplSubject))
- bodyTemplates = template.Must(template.New("issue/default").Parse(tplBody))
-
+ prepareMailTemplates("issue/default", tplSubject, tplBody)
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}}
msg := testComposeIssueCommentMessage(t, &mailComment{
Issue: issue, Doer: doer, ActionType: actionType,
@@ -297,13 +299,13 @@ func testComposeIssueCommentMessage(t *testing.T, ctx *mailComment, recipients [
return msgs[0]
}
-func TestGenerateAdditionalHeaders(t *testing.T) {
+func TestGenerateAdditionalHeadersForIssue(t *testing.T) {
doer, _, issue, _ := prepareMailerTest(t)
comment := &mailComment{Issue: issue, Doer: doer}
recipient := &user_model.User{Name: "test", Email: "test@gitea.com"}
- headers := generateAdditionalHeaders(comment, "dummy-reason", recipient)
+ headers := generateAdditionalHeadersForIssue(comment, "dummy-reason", recipient)
expected := map[string]string{
"List-ID": "user2/repo1 ",
@@ -440,6 +442,16 @@ func TestGenerateMessageIDForRelease(t *testing.T) {
assert.Equal(t, "", msgID)
}
+func TestGenerateMessageIDForActionsWorkflowRunStatusEmail(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
+ run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 795, RepoID: repo.ID})
+ assert.NoError(t, run.LoadAttributes(db.DefaultContext))
+ msgID := generateMessageIDForActionsWorkflowRunStatusEmail(repo, run)
+ assert.Equal(t, "", msgID)
+}
+
func TestFromDisplayName(t *testing.T) {
tmpl, err := texttmpl.New("mailFrom").Parse("{{ .DisplayName }}")
assert.NoError(t, err)
@@ -512,8 +524,7 @@ func TestEmbedBase64Images(t *testing.T) {
att2ImgBase64 := fmt.Sprintf(``, att2Base64)
t.Run("ComposeMessage", func(t *testing.T) {
- subjectTemplates = texttmpl.Must(texttmpl.New("issue/new").Parse(subjectTpl))
- bodyTemplates = template.Must(template.New("issue/new").Parse(bodyTpl))
+ prepareMailTemplates("issue/new", subjectTpl, bodyTpl)
issue.Content = fmt.Sprintf(`MSG-BEFORE MSG-AFTER`, att1.UUID)
require.NoError(t, issues_model.UpdateIssueCols(t.Context(), issue, "content"))
diff --git a/services/mailer/mail_user.go b/services/mailer/mail_user.go
index 5a200a5fa74..68df81f6a3a 100644
--- a/services/mailer/mail_user.go
+++ b/services/mailer/mail_user.go
@@ -39,7 +39,7 @@ func sendUserMail(language string, u *user_model.User, tpl templates.TplName, co
var content bytes.Buffer
- if err := bodyTemplates.ExecuteTemplate(&content, string(tpl), data); err != nil {
+ if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(tpl), data); err != nil {
log.Error("Template: %v", err)
return
}
@@ -90,7 +90,7 @@ func SendActivateEmailMail(u *user_model.User, email string) {
var content bytes.Buffer
- if err := bodyTemplates.ExecuteTemplate(&content, string(mailAuthActivateEmail), data); err != nil {
+ if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(mailAuthActivateEmail), data); err != nil {
log.Error("Template: %v", err)
return
}
@@ -118,7 +118,7 @@ func SendRegisterNotifyMail(u *user_model.User) {
var content bytes.Buffer
- if err := bodyTemplates.ExecuteTemplate(&content, string(mailAuthRegisterNotify), data); err != nil {
+ if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(mailAuthRegisterNotify), data); err != nil {
log.Error("Template: %v", err)
return
}
@@ -149,7 +149,7 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository)
var content bytes.Buffer
- if err := bodyTemplates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil {
+ if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil {
log.Error("Template: %v", err)
return
}
diff --git a/services/mailer/mail_workflow_run.go b/services/mailer/mail_workflow_run.go
new file mode 100644
index 00000000000..29b3abda8ee
--- /dev/null
+++ b/services/mailer/mail_workflow_run.go
@@ -0,0 +1,165 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package mailer
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "sort"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ repo_model "code.gitea.io/gitea/models/repo"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/translation"
+ "code.gitea.io/gitea/services/convert"
+ sender_service "code.gitea.io/gitea/services/mailer/sender"
+)
+
+const tplWorkflowRun = "notify/workflow_run"
+
+type convertedWorkflowJob struct {
+ HTMLURL string
+ Status actions_model.Status
+ Name string
+ Attempt int64
+}
+
+func generateMessageIDForActionsWorkflowRunStatusEmail(repo *repo_model.Repository, run *actions_model.ActionRun) string {
+ return fmt.Sprintf("<%s/actions/runs/%d@%s>", repo.FullName(), run.Index, setting.Domain)
+}
+
+func composeAndSendActionsWorkflowRunStatusEmail(ctx context.Context, repo *repo_model.Repository, run *actions_model.ActionRun, sender *user_model.User, recipients []*user_model.User) {
+ subject := "Run"
+ switch run.Status {
+ case actions_model.StatusFailure:
+ subject += " failed"
+ case actions_model.StatusCancelled:
+ subject += " cancelled"
+ case actions_model.StatusSuccess:
+ subject += " succeeded"
+ }
+ subject = fmt.Sprintf("%s: %s (%s)", subject, run.WorkflowID, base.ShortSha(run.CommitSHA))
+ displayName := fromDisplayName(sender)
+ messageID := generateMessageIDForActionsWorkflowRunStatusEmail(repo, run)
+ metadataHeaders := generateMetadataHeaders(repo)
+
+ jobs, err := actions_model.GetRunJobsByRunID(ctx, run.ID)
+ if err != nil {
+ log.Error("GetRunJobsByRunID: %v", err)
+ return
+ }
+ sort.SliceStable(jobs, func(i, j int) bool {
+ si, sj := jobs[i].Status, jobs[j].Status
+ /*
+ If both i and j are/are not success, leave it to si < sj.
+ If i is success and j is not, since the desired is j goes "smaller" and i goes "bigger", this func should return false.
+ If j is success and i is not, since the desired is i goes "smaller" and j goes "bigger", this func should return true.
+ */
+ if si.IsSuccess() != sj.IsSuccess() {
+ return !si.IsSuccess()
+ }
+ return si < sj
+ })
+
+ convertedJobs := make([]convertedWorkflowJob, 0, len(jobs))
+ for _, job := range jobs {
+ converted0, err := convert.ToActionWorkflowJob(ctx, repo, nil, job)
+ if err != nil {
+ log.Error("convert.ToActionWorkflowJob: %v", err)
+ continue
+ }
+ convertedJobs = append(convertedJobs, convertedWorkflowJob{
+ HTMLURL: converted0.HTMLURL,
+ Name: converted0.Name,
+ Status: job.Status,
+ Attempt: converted0.RunAttempt,
+ })
+ }
+
+ langMap := make(map[string][]*user_model.User)
+ for _, user := range recipients {
+ langMap[user.Language] = append(langMap[user.Language], user)
+ }
+ for lang, tos := range langMap {
+ locale := translation.NewLocale(lang)
+ var runStatusText string
+ switch run.Status {
+ case actions_model.StatusSuccess:
+ runStatusText = "All jobs have succeeded"
+ case actions_model.StatusFailure:
+ runStatusText = "All jobs have failed"
+ for _, job := range jobs {
+ if !job.Status.IsFailure() {
+ runStatusText = "Some jobs were not successful"
+ break
+ }
+ }
+ case actions_model.StatusCancelled:
+ runStatusText = "All jobs have been cancelled"
+ }
+ var mailBody bytes.Buffer
+ if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&mailBody, tplWorkflowRun, map[string]any{
+ "Subject": subject,
+ "Repo": repo,
+ "Run": run,
+ "RunStatusText": runStatusText,
+ "Jobs": convertedJobs,
+ "locale": locale,
+ }); err != nil {
+ log.Error("ExecuteTemplate [%s]: %v", tplWorkflowRun, err)
+ return
+ }
+ msgs := make([]*sender_service.Message, 0, len(tos))
+ for _, rec := range tos {
+ msg := sender_service.NewMessageFrom(
+ rec.Email,
+ displayName,
+ setting.MailService.FromEmail,
+ subject,
+ mailBody.String(),
+ )
+ msg.Info = subject
+ for k, v := range generateSenderRecipientHeaders(sender, rec) {
+ msg.SetHeader(k, v)
+ }
+ for k, v := range metadataHeaders {
+ msg.SetHeader(k, v)
+ }
+ msg.SetHeader("Message-ID", messageID)
+ msgs = append(msgs, msg)
+ }
+ SendAsync(msgs...)
+ }
+}
+
+func MailActionsTrigger(ctx context.Context, sender *user_model.User, repo *repo_model.Repository, run *actions_model.ActionRun) {
+ if setting.MailService == nil {
+ return
+ }
+ if run.Status.IsSkipped() {
+ return
+ }
+
+ recipients := make([]*user_model.User, 0)
+
+ if !sender.IsGiteaActions() && !sender.IsGhost() && sender.IsMailable() {
+ notifyPref, err := user_model.GetUserSetting(ctx, sender.ID,
+ user_model.SettingsKeyEmailNotificationGiteaActions, user_model.SettingEmailNotificationGiteaActionsFailureOnly)
+ if err != nil {
+ log.Error("GetUserSetting: %v", err)
+ return
+ }
+ if notifyPref == user_model.SettingEmailNotificationGiteaActionsAll || !run.Status.IsSuccess() && notifyPref != user_model.SettingEmailNotificationGiteaActionsDisabled {
+ recipients = append(recipients, sender)
+ }
+ }
+
+ if len(recipients) > 0 {
+ composeAndSendActionsWorkflowRunStatusEmail(ctx, repo, run, sender, recipients)
+ }
+}
diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go
index bcd4facca92..db00aac4f1b 100644
--- a/services/mailer/mailer.go
+++ b/services/mailer/mailer.go
@@ -43,7 +43,7 @@ func NewContext(ctx context.Context) {
sender = &sender_service.SMTPSender{}
}
- subjectTemplates, bodyTemplates = templates.Mailer(ctx)
+ templates.LoadMailTemplates(ctx, &loadedTemplates)
mailQueue = queue.CreateSimpleQueue(graceful.GetManager().ShutdownContext(), "mail", func(items ...*sender_service.Message) []*sender_service.Message {
for _, msg := range items {
diff --git a/services/mailer/notify.go b/services/mailer/notify.go
index 77c366fe319..c008685e131 100644
--- a/services/mailer/notify.go
+++ b/services/mailer/notify.go
@@ -7,6 +7,7 @@ import (
"context"
"fmt"
+ actions_model "code.gitea.io/gitea/models/actions"
activities_model "code.gitea.io/gitea/models/activities"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
@@ -205,3 +206,10 @@ func (m *mailNotifier) RepoPendingTransfer(ctx context.Context, doer, newOwner *
log.Error("SendRepoTransferNotifyMail: %v", err)
}
}
+
+func (m *mailNotifier) WorkflowRunStatusUpdate(ctx context.Context, repo *repo_model.Repository, sender *user_model.User, run *actions_model.ActionRun) {
+ if !run.Status.IsDone() {
+ return
+ }
+ MailActionsTrigger(ctx, sender, repo, run)
+}
diff --git a/services/migrations/dump.go b/services/migrations/dump.go
index b4ca1e41e0e..8edd567b082 100644
--- a/services/migrations/dump.go
+++ b/services/migrations/dump.go
@@ -488,7 +488,7 @@ func (g *RepositoryDumper) handlePullRequest(ctx context.Context, pr *base.PullR
if pr.Head.CloneURL == "" || pr.Head.Ref == "" {
// Set head information if pr.Head.SHA is available
if pr.Head.SHA != "" {
- _, _, err = git.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitRefName(), pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.gitPath()})
+ _, _, err = git.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.gitPath()})
if err != nil {
log.Error("PR #%d in %s/%s unable to update-ref for pr HEAD: %v", pr.Number, g.repoOwner, g.repoName, err)
}
@@ -518,7 +518,7 @@ func (g *RepositoryDumper) handlePullRequest(ctx context.Context, pr *base.PullR
if !ok {
// Set head information if pr.Head.SHA is available
if pr.Head.SHA != "" {
- _, _, err = git.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitRefName(), pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.gitPath()})
+ _, _, err = git.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.gitPath()})
if err != nil {
log.Error("PR #%d in %s/%s unable to update-ref for pr HEAD: %v", pr.Number, g.repoOwner, g.repoName, err)
}
@@ -577,7 +577,7 @@ func (g *RepositoryDumper) handlePullRequest(ctx context.Context, pr *base.PullR
pr.Head.SHA = headSha
}
if pr.Head.SHA != "" {
- _, _, err = git.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitRefName(), pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.gitPath()})
+ _, _, err = git.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.gitPath()})
if err != nil {
log.Error("unable to set %s as the local head for PR #%d from %s in %s/%s. Error: %v", pr.Head.SHA, pr.Number, pr.Head.Ref, g.repoOwner, g.repoName, err)
}
diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go
index 737bff24d09..75eb06d01fa 100644
--- a/services/migrations/gitea_uploader.go
+++ b/services/migrations/gitea_uploader.go
@@ -681,7 +681,7 @@ func (g *GiteaLocalUploader) updateGitForPullRequest(ctx context.Context, pr *ba
pr.Head.SHA = headSha
}
- _, _, err = git.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitRefName(), pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.repo.RepoPath()})
+ _, _, err = git.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.repo.RepoPath()})
if err != nil {
return "", err
}
@@ -701,10 +701,10 @@ func (g *GiteaLocalUploader) updateGitForPullRequest(ctx context.Context, pr *ba
_, _, err = git.NewCommand("rev-list", "--quiet", "-1").AddDynamicArguments(pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.repo.RepoPath()})
if err != nil {
// Git update-ref remove bad references with a relative path
- log.Warn("Deprecated local head %s for PR #%d in %s/%s, removing %s", pr.Head.SHA, pr.Number, g.repoOwner, g.repoName, pr.GetGitRefName())
+ log.Warn("Deprecated local head %s for PR #%d in %s/%s, removing %s", pr.Head.SHA, pr.Number, g.repoOwner, g.repoName, pr.GetGitHeadRefName())
} else {
// set head information
- _, _, err = git.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitRefName(), pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.repo.RepoPath()})
+ _, _, err = git.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).RunStdString(ctx, &git.RunOpts{Dir: g.repo.RepoPath()})
if err != nil {
log.Error("unable to set %s as the local head for PR #%d from %s in %s/%s. Error: %v", pr.Head.SHA, pr.Number, pr.Head.Ref, g.repoOwner, g.repoName, err)
}
@@ -880,9 +880,9 @@ func (g *GiteaLocalUploader) CreateReviews(ctx context.Context, reviews ...*base
continue
}
- headCommitID, err := g.gitRepo.GetRefCommitID(pr.GetGitRefName())
+ headCommitID, err := g.gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
- log.Warn("PR #%d GetRefCommitID[%s] in %s/%s: %v, all review comments will be ignored", pr.Index, pr.GetGitRefName(), g.repoOwner, g.repoName, err)
+ log.Warn("PR #%d GetRefCommitID[%s] in %s/%s: %v, all review comments will be ignored", pr.Index, pr.GetGitHeadRefName(), g.repoOwner, g.repoName, err)
continue
}
diff --git a/services/migrations/github.go b/services/migrations/github.go
index 2ce11615c6d..c6cd6ea1733 100644
--- a/services/migrations/github.go
+++ b/services/migrations/github.go
@@ -322,7 +322,10 @@ func (g *GithubDownloaderV3) convertGithubRelease(ctx context.Context, rel *gith
httpClient := NewMigrationHTTPClient()
for _, asset := range rel.Assets {
- assetID := *asset.ID // Don't optimize this, for closure we need a local variable
+ assetID := asset.GetID() // Don't optimize this, for closure we need a local variable TODO: no need to do so in new Golang
+ if assetID == 0 {
+ continue
+ }
r.Assets = append(r.Assets, &base.ReleaseAsset{
ID: asset.GetID(),
Name: asset.GetName(),
diff --git a/services/packages/packages.go b/services/packages/packages.go
index 517334cbc71..4b16ee7285f 100644
--- a/services/packages/packages.go
+++ b/services/packages/packages.go
@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
+ "net/http"
"net/url"
"strings"
@@ -564,7 +565,7 @@ func DeletePackageFile(ctx context.Context, pf *packages_model.PackageFile) erro
}
// OpenFileForDownloadByPackageNameAndVersion returns the content of the specific package file and increases the download counter.
-func OpenFileForDownloadByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
+func OpenFileForDownloadByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo, method string) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
log.Trace("Getting package file stream: %v, %v, %s, %s, %s, %s", pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version, pfi.Filename, pfi.CompositeKey)
pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
@@ -576,27 +577,27 @@ func OpenFileForDownloadByPackageNameAndVersion(ctx context.Context, pvi *Packag
return nil, nil, nil, err
}
- return OpenFileForDownloadByPackageVersion(ctx, pv, pfi)
+ return OpenFileForDownloadByPackageVersion(ctx, pv, pfi, method)
}
// OpenFileForDownloadByPackageVersion returns the content of the specific package file and increases the download counter.
-func OpenFileForDownloadByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
+func OpenFileForDownloadByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo, method string) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey)
if err != nil {
return nil, nil, nil, err
}
- return OpenFileForDownload(ctx, pf)
+ return OpenFileForDownload(ctx, pf, method)
}
// OpenFileForDownload returns the content of the specific package file and increases the download counter.
-func OpenFileForDownload(ctx context.Context, pf *packages_model.PackageFile) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
+func OpenFileForDownload(ctx context.Context, pf *packages_model.PackageFile, method string) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
if err != nil {
return nil, nil, nil, err
}
- return OpenBlobForDownload(ctx, pf, pb, nil)
+ return OpenBlobForDownload(ctx, pf, pb, method, nil)
}
func OpenBlobStream(pb *packages_model.PackageBlob) (io.ReadSeekCloser, error) {
@@ -607,7 +608,7 @@ func OpenBlobStream(pb *packages_model.PackageBlob) (io.ReadSeekCloser, error) {
// OpenBlobForDownload returns the content of the specific package blob and increases the download counter.
// If the storage supports direct serving and it's enabled, only the direct serving url is returned.
-func OpenBlobForDownload(ctx context.Context, pf *packages_model.PackageFile, pb *packages_model.PackageBlob, serveDirectReqParams url.Values) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
+func OpenBlobForDownload(ctx context.Context, pf *packages_model.PackageFile, pb *packages_model.PackageBlob, method string, serveDirectReqParams url.Values) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
key := packages_module.BlobHash256Key(pb.HashSHA256)
cs := packages_module.NewContentStore()
@@ -617,23 +618,24 @@ func OpenBlobForDownload(ctx context.Context, pf *packages_model.PackageFile, pb
var err error
if cs.ShouldServeDirect() {
- u, err = cs.GetServeDirectURL(key, pf.Name, serveDirectReqParams)
+ u, err = cs.GetServeDirectURL(key, pf.Name, method, serveDirectReqParams)
if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
- log.Error("Error getting serve direct url: %v", err)
+ log.Error("Error getting serve direct url (fallback to local reader): %v", err)
}
}
if u == nil {
s, err = cs.OpenBlob(key)
}
+ if err != nil {
+ return nil, nil, nil, err
+ }
- if err == nil {
- if pf.IsLead {
- if err := packages_model.IncrementDownloadCounter(ctx, pf.VersionID); err != nil {
- log.Error("Error incrementing download counter: %v", err)
- }
+ if pf.IsLead && method == http.MethodGet {
+ if err := packages_model.IncrementDownloadCounter(ctx, pf.VersionID); err != nil {
+ log.Error("Error incrementing download counter: %v", err)
}
}
- return s, u, pf, err
+ return s, u, pf, nil
}
// RemoveAllPackages for User
diff --git a/services/pull/check.go b/services/pull/check.go
index bf6c5fa1c45..7fcec22f492 100644
--- a/services/pull/check.go
+++ b/services/pull/check.go
@@ -231,7 +231,7 @@ func isSignedIfRequired(ctx context.Context, pr *issues_model.PullRequest, doer
return true, nil
}
- sign, _, _, err := asymkey_service.SignMerge(ctx, pr, doer, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName())
+ sign, _, _, err := asymkey_service.SignMerge(ctx, pr, doer, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitHeadRefName())
return sign, err
}
@@ -277,7 +277,7 @@ func getMergeCommit(ctx context.Context, pr *issues_model.PullRequest) (*git.Com
return nil, fmt.Errorf("unable to load base repo for %s: %w", pr, err)
}
- prHeadRef := pr.GetGitRefName()
+ prHeadRef := pr.GetGitHeadRefName()
// Check if the pull request is merged into BaseBranch
if _, _, err := git.NewCommand("merge-base", "--is-ancestor").
diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go
index 7952ca6fe39..d15d3181497 100644
--- a/services/pull/commit_status.go
+++ b/services/pull/commit_status.go
@@ -99,7 +99,7 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullR
if pr.Flow == issues_model.PullRequestFlowGithub && !gitrepo.IsBranchExist(ctx, pr.HeadRepo, pr.HeadBranch) {
return "", errors.New("Head branch does not exist, can not merge")
}
- if pr.Flow == issues_model.PullRequestFlowAGit && !gitrepo.IsReferenceExist(ctx, pr.HeadRepo, pr.GetGitRefName()) {
+ if pr.Flow == issues_model.PullRequestFlowAGit && !gitrepo.IsReferenceExist(ctx, pr.HeadRepo, pr.GetGitHeadRefName()) {
return "", errors.New("Head branch does not exist, can not merge")
}
@@ -107,7 +107,7 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullR
if pr.Flow == issues_model.PullRequestFlowGithub {
sha, err = headGitRepo.GetBranchCommitID(pr.HeadBranch)
} else {
- sha, err = headGitRepo.GetRefCommitID(pr.GetGitRefName())
+ sha, err = headGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
}
if err != nil {
return "", err
diff --git a/services/pull/patch.go b/services/pull/patch.go
index 153e0baf87a..9d9b8d0d076 100644
--- a/services/pull/patch.go
+++ b/services/pull/patch.go
@@ -41,7 +41,7 @@ func DownloadDiffOrPatch(ctx context.Context, pr *issues_model.PullRequest, w io
}
defer closer.Close()
- compareArg := pr.MergeBase + "..." + pr.GetGitRefName()
+ compareArg := pr.MergeBase + "..." + pr.GetGitHeadRefName()
switch {
case patch:
err = gitRepo.GetPatch(compareArg, w)
diff --git a/services/pull/pull.go b/services/pull/pull.go
index 701c4f4d322..2829e154410 100644
--- a/services/pull/pull.go
+++ b/services/pull/pull.go
@@ -143,7 +143,7 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error {
}
compareInfo, err := baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(),
- git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName(), false, false)
+ git.BranchPrefix+pr.BaseBranch, pr.GetGitHeadRefName(), false, false)
if err != nil {
return err
}
@@ -184,7 +184,7 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error {
return nil
}); err != nil {
// cleanup: this will only remove the reference, the real commit will be clean up when next GC
- if err1 := baseGitRepo.RemoveReference(pr.GetGitRefName()); err1 != nil {
+ if err1 := baseGitRepo.RemoveReference(pr.GetGitHeadRefName()); err1 != nil {
log.Error("RemoveReference: %v", err1)
}
return err
@@ -567,7 +567,7 @@ func PushToBaseRepo(ctx context.Context, pr *issues_model.PullRequest) (err erro
}
func pushToBaseRepoHelper(ctx context.Context, pr *issues_model.PullRequest, prefixHeadBranch string) (err error) {
- log.Trace("PushToBaseRepo[%d]: pushing commits to base repo '%s'", pr.BaseRepoID, pr.GetGitRefName())
+ log.Trace("PushToBaseRepo[%d]: pushing commits to base repo '%s'", pr.BaseRepoID, pr.GetGitHeadRefName())
if err := pr.LoadHeadRepo(ctx); err != nil {
log.Error("Unable to load head repository for PR[%d] Error: %v", pr.ID, err)
@@ -588,7 +588,7 @@ func pushToBaseRepoHelper(ctx context.Context, pr *issues_model.PullRequest, pre
return fmt.Errorf("unable to load poster %d for pr %d: %w", pr.Issue.PosterID, pr.ID, err)
}
- gitRefName := pr.GetGitRefName()
+ gitRefName := pr.GetGitHeadRefName()
if err := git.Push(ctx, headRepoPath, git.PushOptions{
Remote: baseRepoPath,
@@ -642,13 +642,13 @@ func UpdatePullsRefs(ctx context.Context, repo *repo_model.Repository, update *r
// UpdateRef update refs/pull/id/head directly for agit flow pull request
func UpdateRef(ctx context.Context, pr *issues_model.PullRequest) (err error) {
- log.Trace("UpdateRef[%d]: upgate pull request ref in base repo '%s'", pr.ID, pr.GetGitRefName())
+ log.Trace("UpdateRef[%d]: upgate pull request ref in base repo '%s'", pr.ID, pr.GetGitHeadRefName())
if err := pr.LoadBaseRepo(ctx); err != nil {
log.Error("Unable to load base repository for PR[%d] Error: %v", pr.ID, err)
return err
}
- _, _, err = git.NewCommand("update-ref").AddDynamicArguments(pr.GetGitRefName(), pr.HeadCommitID).RunStdString(ctx, &git.RunOpts{Dir: pr.BaseRepo.RepoPath()})
+ _, _, err = git.NewCommand("update-ref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.HeadCommitID).RunStdString(ctx, &git.RunOpts{Dir: pr.BaseRepo.RepoPath()})
if err != nil {
log.Error("Unable to update ref in base repository for PR[%d] Error: %v", pr.ID, err)
}
@@ -816,9 +816,9 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ
if pr.Flow == issues_model.PullRequestFlowGithub {
headCommit, err = gitRepo.GetBranchCommit(pr.HeadBranch)
} else {
- pr.HeadCommitID, err = gitRepo.GetRefCommitID(pr.GetGitRefName())
+ pr.HeadCommitID, err = gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
- log.Error("Unable to get head commit: %s Error: %v", pr.GetGitRefName(), err)
+ log.Error("Unable to get head commit: %s Error: %v", pr.GetGitHeadRefName(), err)
return ""
}
headCommit, err = gitRepo.GetCommit(pr.HeadCommitID)
@@ -993,7 +993,7 @@ func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList
// getAllCommitStatus get pr's commit statuses.
func getAllCommitStatus(ctx context.Context, gitRepo *git.Repository, pr *issues_model.PullRequest) (statuses []*git_model.CommitStatus, lastStatus *git_model.CommitStatus, err error) {
- sha, shaErr := gitRepo.GetRefCommitID(pr.GetGitRefName())
+ sha, shaErr := gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if shaErr != nil {
return nil, nil, shaErr
}
@@ -1043,7 +1043,7 @@ func IsHeadEqualWithBranch(ctx context.Context, pr *issues_model.PullRequest, br
return false, err
}
} else {
- pr.HeadCommitID, err = baseGitRepo.GetRefCommitID(pr.GetGitRefName())
+ pr.HeadCommitID, err = baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
return false, err
}
@@ -1077,7 +1077,7 @@ func GetPullCommits(ctx *gitea_context.Context, issue *issues_model.Issue) ([]Co
if pull.HasMerged {
baseBranch = pull.MergeBase
}
- prInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), baseBranch, pull.GetGitRefName(), true, false)
+ prInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), baseBranch, pull.GetGitHeadRefName(), true, false)
if err != nil {
return nil, "", err
}
diff --git a/services/pull/review.go b/services/pull/review.go
index 5c80e7b3386..ee18db38599 100644
--- a/services/pull/review.go
+++ b/services/pull/review.go
@@ -200,7 +200,7 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo
defer closer.Close()
invalidated := false
- head := pr.GetGitRefName()
+ head := pr.GetGitHeadRefName()
if line > 0 {
if reviewID != 0 {
first, err := issues_model.FindComments(ctx, &issues_model.FindCommentsOptions{
@@ -237,16 +237,16 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo
if err == nil {
commitID = commit.ID.String()
} else if !(strings.Contains(err.Error(), "exit status 128 - fatal: no such path") || notEnoughLines.MatchString(err.Error())) {
- return nil, fmt.Errorf("LineBlame[%s, %s, %s, %d]: %w", pr.GetGitRefName(), gitRepo.Path, treePath, line, err)
+ return nil, fmt.Errorf("LineBlame[%s, %s, %s, %d]: %w", pr.GetGitHeadRefName(), gitRepo.Path, treePath, line, err)
}
}
}
// Only fetch diff if comment is review comment
if len(patch) == 0 && reviewID != 0 {
- headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
+ headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
- return nil, fmt.Errorf("GetRefCommitID[%s]: %w", pr.GetGitRefName(), err)
+ return nil, fmt.Errorf("GetRefCommitID[%s]: %w", pr.GetGitHeadRefName(), err)
}
if len(commitID) == 0 {
commitID = headCommitID
@@ -301,7 +301,7 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos
return nil, nil, ErrSubmitReviewOnClosedPR
}
- headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
+ headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
return nil, nil, err
}
diff --git a/services/pull/temp_repo.go b/services/pull/temp_repo.go
index 72406482e08..89f150fd92e 100644
--- a/services/pull/temp_repo.go
+++ b/services/pull/temp_repo.go
@@ -174,7 +174,7 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
} else if len(pr.HeadCommitID) == objectFormat.FullLength() { // for not created pull request
headBranch = pr.HeadCommitID
} else {
- headBranch = pr.GetGitRefName()
+ headBranch = pr.GetGitHeadRefName()
}
if err := git.NewCommand("fetch").AddArguments(fetchArgs...).AddDynamicArguments(remoteRepoName, headBranch+":"+trackingBranch).
Run(ctx, prCtx.RunOpts()); err != nil {
diff --git a/services/repository/branch.go b/services/repository/branch.go
index dd00ca7dcd2..6e0065b2776 100644
--- a/services/repository/branch.go
+++ b/services/repository/branch.go
@@ -233,7 +233,7 @@ func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *g
defer baseGitRepo.Close()
repoIDToGitRepo[pr.BaseRepoID] = baseGitRepo
}
- pullCommit, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
+ pullCommit, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil && !git.IsErrNotExist(err) {
return nil, fmt.Errorf("GetBranchCommitID: %v", err)
}
diff --git a/services/repository/files/tree.go b/services/repository/files/tree.go
index f2cbacbf1c9..419dbedd74d 100644
--- a/services/repository/files/tree.go
+++ b/services/repository/files/tree.go
@@ -154,7 +154,7 @@ func (node *TreeViewNode) sortLevel() int {
return util.Iif(node.EntryMode == "tree" || node.EntryMode == "commit", 0, 1)
}
-func newTreeViewNodeFromEntry(ctx context.Context, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, parentDir string, entry *git.TreeEntry) *TreeViewNode {
+func newTreeViewNodeFromEntry(ctx context.Context, repoLink string, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, parentDir string, entry *git.TreeEntry) *TreeViewNode {
node := &TreeViewNode{
EntryName: entry.Name(),
EntryMode: entryModeString(entry.Mode()),
@@ -172,9 +172,11 @@ func newTreeViewNodeFromEntry(ctx context.Context, renderedIconPool *fileicon.Re
if subModule, err := commit.GetSubModule(node.FullPath); err != nil {
log.Error("GetSubModule: %v", err)
} else if subModule != nil {
- submoduleFile := git.NewCommitSubmoduleFile(subModule.URL, entry.ID.String())
- webLink := submoduleFile.SubmoduleWebLink(ctx)
- node.SubmoduleURL = webLink.CommitWebLink
+ submoduleFile := git.NewCommitSubmoduleFile(repoLink, node.FullPath, subModule.URL, entry.ID.String())
+ webLink := submoduleFile.SubmoduleWebLinkTree(ctx)
+ if webLink != nil {
+ node.SubmoduleURL = webLink.CommitWebLink
+ }
}
}
@@ -192,7 +194,7 @@ func sortTreeViewNodes(nodes []*TreeViewNode) {
})
}
-func listTreeNodes(ctx context.Context, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, tree *git.Tree, treePath, subPath string) ([]*TreeViewNode, error) {
+func listTreeNodes(ctx context.Context, repoLink string, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, tree *git.Tree, treePath, subPath string) ([]*TreeViewNode, error) {
entries, err := tree.ListEntries()
if err != nil {
return nil, err
@@ -201,14 +203,14 @@ func listTreeNodes(ctx context.Context, renderedIconPool *fileicon.RenderedIconP
subPathDirName, subPathRemaining, _ := strings.Cut(subPath, "/")
nodes := make([]*TreeViewNode, 0, len(entries))
for _, entry := range entries {
- node := newTreeViewNodeFromEntry(ctx, renderedIconPool, commit, treePath, entry)
+ node := newTreeViewNodeFromEntry(ctx, repoLink, renderedIconPool, commit, treePath, entry)
nodes = append(nodes, node)
if entry.IsDir() && subPathDirName == entry.Name() {
subTreePath := treePath + "/" + node.EntryName
if subTreePath[0] == '/' {
subTreePath = subTreePath[1:]
}
- subNodes, err := listTreeNodes(ctx, renderedIconPool, commit, entry.Tree(), subTreePath, subPathRemaining)
+ subNodes, err := listTreeNodes(ctx, repoLink, renderedIconPool, commit, entry.Tree(), subTreePath, subPathRemaining)
if err != nil {
log.Error("listTreeNodes: %v", err)
} else {
@@ -220,10 +222,10 @@ func listTreeNodes(ctx context.Context, renderedIconPool *fileicon.RenderedIconP
return nodes, nil
}
-func GetTreeViewNodes(ctx context.Context, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, treePath, subPath string) ([]*TreeViewNode, error) {
+func GetTreeViewNodes(ctx context.Context, repoLink string, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, treePath, subPath string) ([]*TreeViewNode, error) {
entry, err := commit.GetTreeEntryByPath(treePath)
if err != nil {
return nil, err
}
- return listTreeNodes(ctx, renderedIconPool, commit, entry.Tree(), treePath, subPath)
+ return listTreeNodes(ctx, repoLink, renderedIconPool, commit, entry.Tree(), treePath, subPath)
}
diff --git a/services/repository/files/tree_test.go b/services/repository/files/tree_test.go
index a53f342d404..38ac9f25fc2 100644
--- a/services/repository/files/tree_test.go
+++ b/services/repository/files/tree_test.go
@@ -64,6 +64,7 @@ func TestGetTreeViewNodes(t *testing.T) {
contexttest.LoadGitRepo(t, ctx)
defer ctx.Repo.GitRepo.Close()
+ curRepoLink := "/any/repo-link"
renderedIconPool := fileicon.NewRenderedIconPool()
mockIconForFile := func(id string) template.HTML {
return template.HTML(``)
@@ -74,7 +75,7 @@ func TestGetTreeViewNodes(t *testing.T) {
mockOpenIconForFolder := func(id string) template.HTML {
return template.HTML(``)
}
- treeNodes, err := GetTreeViewNodes(ctx, renderedIconPool, ctx.Repo.Commit, "", "")
+ treeNodes, err := GetTreeViewNodes(ctx, curRepoLink, renderedIconPool, ctx.Repo.Commit, "", "")
assert.NoError(t, err)
assert.Equal(t, []*TreeViewNode{
{
@@ -86,7 +87,7 @@ func TestGetTreeViewNodes(t *testing.T) {
},
}, treeNodes)
- treeNodes, err = GetTreeViewNodes(ctx, renderedIconPool, ctx.Repo.Commit, "", "docs/README.md")
+ treeNodes, err = GetTreeViewNodes(ctx, curRepoLink, renderedIconPool, ctx.Repo.Commit, "", "docs/README.md")
assert.NoError(t, err)
assert.Equal(t, []*TreeViewNode{
{
@@ -106,7 +107,7 @@ func TestGetTreeViewNodes(t *testing.T) {
},
}, treeNodes)
- treeNodes, err = GetTreeViewNodes(ctx, renderedIconPool, ctx.Repo.Commit, "docs", "README.md")
+ treeNodes, err = GetTreeViewNodes(ctx, curRepoLink, renderedIconPool, ctx.Repo.Commit, "docs", "README.md")
assert.NoError(t, err)
assert.Equal(t, []*TreeViewNode{
{
diff --git a/templates/admin/auth/edit.tmpl b/templates/admin/auth/edit.tmpl
index 781f514af45..7b96b4e94fd 100644
--- a/templates/admin/auth/edit.tmpl
+++ b/templates/admin/auth/edit.tmpl
@@ -301,19 +301,30 @@
- {{range .OAuth2Providers}}{{if .CustomURLSettings}}
+ {{range .OAuth2Providers}}
+
+ {{if .CustomURLSettings}}
- {{end}}{{end}}
+ {{end}}
+ {{end}}
{{- if .CommitFormOptions.WillSign}} {{svg "octicon-lock" 24}} {{ctx.Locale.Tr "repo.editor.commit_signed_changes"}} diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index f86b90502df..2a6c0d2fe51 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -15,7 +15,7 @@