diff --git a/.deadcode-out b/.deadcode-out index b17d738bd6..338d22e258 100644 --- a/.deadcode-out +++ b/.deadcode-out @@ -189,6 +189,7 @@ code.gitea.io/gitea/modules/translation MockLocale.TrN MockLocale.TrPluralString MockLocale.TrSize + MockLocale.HasKey MockLocale.PrettyNumber code.gitea.io/gitea/modules/util diff --git a/.forgejo/workflows-composite/setup-cache-go/action.yaml b/.forgejo/workflows-composite/setup-cache-go/action.yaml index cc21485d14..f2818a7635 100644 --- a/.forgejo/workflows-composite/setup-cache-go/action.yaml +++ b/.forgejo/workflows-composite/setup-cache-go/action.yaml @@ -27,6 +27,7 @@ runs: - name: "Get go environment information" id: go-environment run: | + chmod 755 $HOME # ensure ${RUN_AS_USER} has permission when go is located in $HOME export GOROOT="$(go env GOROOT)" echo "modcache=$(su ${RUN_AS_USER} -c '${GOROOT}/bin/go env GOMODCACHE')" >> "$GITHUB_OUTPUT" echo "cache=$(su ${RUN_AS_USER} -c '${GOROOT}/bin/go env GOCACHE')" >> "$GITHUB_OUTPUT" diff --git a/.forgejo/workflows/renovate.yml b/.forgejo/workflows/renovate.yml index e17c77beb0..171c18e323 100644 --- a/.forgejo/workflows/renovate.yml +++ b/.forgejo/workflows/renovate.yml @@ -28,7 +28,7 @@ jobs: runs-on: docker container: - image: data.forgejo.org/renovate/renovate:39.178.1 + image: data.forgejo.org/renovate/renovate:39.185.0 steps: - name: Load renovate repo cache diff --git a/.golangci.yml b/.golangci.yml index 0678b90bfc..cceb7070e7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,12 +19,12 @@ linters: - revive - staticcheck - stylecheck - - tenv - testifylint - typecheck - unconvert - unused - unparam + - usetesting - wastedassign run: diff --git a/Makefile b/Makefile index 830a30a924..7993d06c3d 100644 --- a/Makefile +++ b/Makefile @@ -39,17 +39,17 @@ XGO_VERSION := go-1.21.x AIR_PACKAGE ?= github.com/air-verse/air@v1 # renovate: datasource=go EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.2.0 # renovate: datasource=go GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0 # renovate: datasource=go -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2 # renovate: datasource=go +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.6 # renovate: datasource=go GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 # renovate: datasource=go MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0 # renovate: datasource=go SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 # renovate: datasource=go XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0 # renovate: datasource=go GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go -DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.30.0 # renovate: datasource=go +DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.31.0 # renovate: datasource=go GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.4.0 # renovate: datasource=go GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.18.1 # renovate: datasource=go -RENOVATE_NPM_PACKAGE ?= renovate@39.178.1 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate +RENOVATE_NPM_PACKAGE ?= renovate@39.185.0 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate # https://github.com/disposable-email-domains/disposable-email-domains/commits/main/ DISPOSABLE_EMAILS_SHA ?= 0c27e671231d27cf66370034d7f6818037416989 # renovate: ... @@ -59,20 +59,8 @@ ifeq ($(HAS_GO), yes) CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS) endif -ifeq ($(GOOS),windows) - IS_WINDOWS := yes -else ifeq ($(patsubst Windows%,Windows,$(OS)),Windows) - ifeq ($(GOOS),) - IS_WINDOWS := yes - endif -endif -ifeq ($(IS_WINDOWS),yes) - GOFLAGS := -v -buildmode=exe - EXECUTABLE ?= gitea.exe -else - GOFLAGS := -v - EXECUTABLE ?= gitea -endif +GOFLAGS := -v +EXECUTABLE ?= gitea ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu) SED_INPLACE := sed -i @@ -498,13 +486,6 @@ lint-go-fix: $(GO) run $(GOLANGCI_LINT_PACKAGE) run $(GOLANGCI_LINT_ARGS) --fix $(RUN_DEADCODE) > .deadcode-out -# workaround step for the lint-go-windows CI task because 'go run' can not -# have distinct GOOS/GOARCH for its build and run steps -.PHONY: lint-go-windows -lint-go-windows: - @GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE) - golangci-lint run - .PHONY: lint-go-vet lint-go-vet: @echo "Running go vet..." @@ -534,7 +515,7 @@ lint-templates: .venv node_modules .PHONY: lint-yaml lint-yaml: .venv - @poetry run yamllint . + @poetry run yamllint -s . .PHONY: security-check security-check: @@ -877,10 +858,6 @@ sources-tarbal: frontend generate vendor release-sources release-check $(DIST_DIRS): mkdir -p $(DIST_DIRS) -.PHONY: release-windows -release-windows: | $(DIST_DIRS) - CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . - .PHONY: release-linux release-linux: | $(DIST_DIRS) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out forgejo-$(VERSION) . diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 7d6f94d755..1bea3fb805 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -19,6 +19,11 @@ "path": "code.forgejo.org/forgejo-contrib/go-libravatar/LICENSE", "licenseText": "Copyright (c) 2016 Sandro Santilli \u003cstrk@kbt.io\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" }, + { + "name": "code.forgejo.org/forgejo/levelqueue", + "path": "code.forgejo.org/forgejo/levelqueue/LICENSE", + "licenseText": "Copyright (c) 2019 Lunny Xiao\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" + }, { "name": "code.forgejo.org/forgejo/reply", "path": "code.forgejo.org/forgejo/reply/LICENSE", @@ -79,11 +84,6 @@ "path": "git.sr.ht/~mariusor/go-xsd-duration/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2019 Go xsd:duration\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, - { - "name": "gitea.com/lunny/levelqueue", - "path": "gitea.com/lunny/levelqueue/LICENSE", - "licenseText": "Copyright (c) 2019 Lunny Xiao\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, { "name": "github.com/42wim/httpsig", "path": "github.com/42wim/httpsig/LICENSE", diff --git a/cmd/hook_test.go b/cmd/hook_test.go index 1f0ee7087b..4fa249a316 100644 --- a/cmd/hook_test.go +++ b/cmd/hook_test.go @@ -6,7 +6,6 @@ package cmd import ( "bufio" "bytes" - "context" "io" "net/http" "net/http/httptest" @@ -42,7 +41,7 @@ func captureOutput(t *testing.T, stdFD *os.File) (finish func() (output string)) } func TestPktLine(t *testing.T) { - ctx := context.Background() + ctx := t.Context() t.Run("Read", func(t *testing.T) { s := strings.NewReader("0000") diff --git a/cmd/migrate_storage_test.go b/cmd/migrate_storage_test.go index 56745e9a38..245f0cacff 100644 --- a/cmd/migrate_storage_test.go +++ b/cmd/migrate_storage_test.go @@ -4,7 +4,6 @@ package cmd import ( - "context" "io" "os" "strings" @@ -31,7 +30,7 @@ func createLocalStorage(t *testing.T) (storage.ObjectStorage, string) { p := t.TempDir() storage, err := storage.NewLocalStorage( - context.Background(), + t.Context(), &setting.Storage{ Path: p, }) @@ -72,7 +71,7 @@ func TestMigratePackages(t *testing.T) { assert.NotNil(t, v) assert.NotNil(t, f) - ctx := context.Background() + ctx := t.Context() dstStorage, p := createLocalStorage(t) diff --git a/go.mod b/go.mod index 351f736389..92a79428fa 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,12 @@ module code.gitea.io/gitea go 1.24 -toolchain go1.24.0 +toolchain go1.24.1 require ( - code.forgejo.org/f3/gof3/v3 v3.10.2 + code.forgejo.org/f3/gof3/v3 v3.10.4 code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 + code.forgejo.org/forgejo/levelqueue v1.0.0 code.forgejo.org/forgejo/reply v1.0.2 code.forgejo.org/go-chi/binding v1.0.0 code.forgejo.org/go-chi/cache v1.0.0 @@ -16,18 +17,17 @@ require ( code.gitea.io/sdk/gitea v0.20.0 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 connectrpc.com/connect v1.17.0 - gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 github.com/42wim/httpsig v1.2.2 github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 - github.com/ProtonMail/go-crypto v1.1.5 - github.com/PuerkitoBio/goquery v1.10.1 + github.com/ProtonMail/go-crypto v1.1.6 + github.com/PuerkitoBio/goquery v1.10.2 github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 github.com/alecthomas/chroma/v2 v2.15.0 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blevesearch/bleve/v2 v2.4.4 github.com/buildkite/terminal-to-html/v3 v3.16.6 - github.com/caddyserver/certmagic v0.21.7 + github.com/caddyserver/certmagic v0.22.0 github.com/chi-middleware/proxy v1.1.1 github.com/djherbis/buffer v1.2.0 github.com/djherbis/nio/v3 v3.0.1 @@ -60,15 +60,15 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/feeds v1.2.0 github.com/gorilla/sessions v1.4.0 - github.com/hashicorp/go-version v1.6.0 + github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/huandu/xstrings v1.5.0 github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 - github.com/jhillyerd/enmime/v2 v2.0.0 + github.com/jhillyerd/enmime/v2 v2.1.0 github.com/json-iterator/go v1.1.12 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/klauspost/compress v1.17.11 - github.com/klauspost/cpuid/v2 v2.2.9 + github.com/klauspost/cpuid/v2 v2.2.10 github.com/lib/pq v1.10.9 github.com/markbates/goth v1.80.0 github.com/mattn/go-isatty v0.0.20 @@ -82,9 +82,9 @@ require ( github.com/niklasfasching/go-org v1.7.0 github.com/olivere/elastic/v7 v7.0.32 github.com/opencontainers/go-digest v1.0.0 - github.com/opencontainers/image-spec v1.1.0 + github.com/opencontainers/image-spec v1.1.1 github.com/pquerna/otp v1.4.0 - github.com/prometheus/client_golang v1.21.0 + github.com/prometheus/client_golang v1.21.1 github.com/redis/go-redis/v9 v9.7.0 github.com/robfig/cron/v3 v3.0.1 github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 @@ -94,22 +94,22 @@ require ( github.com/stretchr/testify v1.10.0 github.com/syndtr/goleveldb v1.0.0 github.com/ulikunitz/xz v0.5.12 - github.com/urfave/cli/v2 v2.27.5 + github.com/urfave/cli/v2 v2.27.6 github.com/valyala/fastjson v1.6.4 github.com/yohcop/openid-go v1.0.1 github.com/yuin/goldmark v1.7.8 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc - gitlab.com/gitlab-org/api/client-go v0.119.0 + gitlab.com/gitlab-org/api/client-go v0.123.0 go.uber.org/mock v0.4.0 - golang.org/x/crypto v0.35.0 - golang.org/x/image v0.23.0 - golang.org/x/net v0.35.0 - golang.org/x/oauth2 v0.24.0 - golang.org/x/sync v0.11.0 - golang.org/x/sys v0.30.0 - golang.org/x/text v0.22.0 - google.golang.org/grpc v1.70.0 - google.golang.org/protobuf v1.36.3 + golang.org/x/crypto v0.36.0 + golang.org/x/image v0.25.0 + golang.org/x/net v0.37.0 + golang.org/x/oauth2 v0.28.0 + golang.org/x/sync v0.12.0 + golang.org/x/sys v0.31.0 + golang.org/x/text v0.23.0 + google.golang.org/grpc v1.71.0 + google.golang.org/protobuf v1.36.4 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v3 v3.0.1 @@ -119,11 +119,11 @@ require ( ) require ( - cel.dev/expr v0.19.0 // indirect + cel.dev/expr v0.19.1 // indirect cloud.google.com/go v0.116.0 // indirect cloud.google.com/go/auth v0.9.9 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect - cloud.google.com/go/compute/metadata v0.5.2 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect cloud.google.com/go/iam v1.2.1 // indirect cloud.google.com/go/longrunning v0.6.1 // indirect cloud.google.com/go/monitoring v1.21.1 // indirect @@ -162,11 +162,10 @@ require ( github.com/boombuler/barcode v1.0.1 // indirect github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect github.com/caddyserver/zerossl v0.1.3 // indirect - github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudflare/circl v1.3.8 // indirect - github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect + github.com/cncf/xds/go v0.0.0-20241223141626-cff3c89139a3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/cyphar/filepath-securejoin v0.3.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -175,8 +174,8 @@ require ( github.com/dlclark/regexp2 v1.11.4 // indirect github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/envoyproxy/go-control-plane v0.13.1 // indirect - github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect + github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect github.com/fatih/color v1.16.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect @@ -200,7 +199,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.1 // indirect github.com/google/s2a-go v0.1.8 // indirect @@ -216,13 +215,13 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect - github.com/libdns/libdns v0.2.2 // indirect + github.com/libdns/libdns v0.2.3 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/markbates/going v1.0.3 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/mholt/acmez/v3 v3.0.1 // indirect - github.com/miekg/dns v1.1.62 // indirect + github.com/mholt/acmez/v3 v3.1.0 // indirect + github.com/miekg/dns v1.1.63 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -256,25 +255,26 @@ require ( github.com/zeebo/blake3 v0.2.4 // indirect go.etcd.io/bbolt v1.3.9 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.32.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect - go.opentelemetry.io/otel v1.32.0 // indirect - go.opentelemetry.io/otel/metric v1.32.0 // indirect - go.opentelemetry.io/otel/sdk v1.32.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect - go.opentelemetry.io/otel/trace v1.32.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.34.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect - golang.org/x/mod v0.22.0 // indirect - golang.org/x/time v0.8.0 // indirect - golang.org/x/tools v0.28.0 // indirect + golang.org/x/mod v0.24.0 // indirect + golang.org/x/time v0.9.0 // indirect + golang.org/x/tools v0.31.0 // indirect google.golang.org/api v0.203.0 // indirect google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index d64b8a74c1..17d41d080f 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -cel.dev/expr v0.19.0 h1:lXuo+nDhpyJSpWxpPVi5cPUwzKb+dsdOiw6IreM5yt0= -cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= +cel.dev/expr v0.19.1 h1:NciYrtDRIR0lNCnH1LFJegdjspNx9fI59O7TWcua/W4= +cel.dev/expr v0.19.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -184,8 +184,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= -cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -610,8 +610,8 @@ cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoIS cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -code.forgejo.org/f3/gof3/v3 v3.10.2 h1:EOlv9d8GR7l0BmvZF101O3LUuabb4g5Hw5fKYPiPZlI= -code.forgejo.org/f3/gof3/v3 v3.10.2/go.mod h1:qApIHumpBkFkeBEokviO28+HK2WM11IsmMOhmjvCjFQ= +code.forgejo.org/f3/gof3/v3 v3.10.4 h1:NOkw8lG3PhgYykdR5pJ19KFLdYmRFVII43YBSNKtpvk= +code.forgejo.org/f3/gof3/v3 v3.10.4/go.mod h1:aQSlSGpISIf016g1dBrmm16h53WUKjCR7nSCuoO8dq8= code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 h1:HTZl3CBk3ABNYtFI6TPLvJgGKFIhKT5CBk0sbOtkDKU= code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:PphB88CPbx601QrWPMZATeorACeVmQlyv3u+uUMbSaM= code.forgejo.org/forgejo/act v1.23.1 h1:4LU7u3FE380DicHz1oZ4ohsWU9I527OHeslVHnr9eP4= @@ -620,6 +620,8 @@ code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEj code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:RArF5AsF9LH4nEoJxqRxcP5r8hhRfWcId84G82YbqzA= code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= +code.forgejo.org/forgejo/levelqueue v1.0.0 h1:9krYpU6BM+j/1Ntj6m+VCAIu0UNnne1/UfU/XgPpLuE= +code.forgejo.org/forgejo/levelqueue v1.0.0/go.mod h1:fmG6zhVuqim2rxSFOoasgXO8V2W/k9U31VVYqLIRLhQ= code.forgejo.org/forgejo/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCdgFuQ= code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U= code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616 h1:kEZL84+02jY9RxXM4zHBWZ3Fml0B09cmP1LGkDsCfIA= @@ -647,8 +649,6 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= -gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 h1:IFT+hup2xejHqdhS7keYWioqfmxdnfblFDTGoOwcZ+o= -gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= github.com/42wim/httpsig v1.2.2 h1:ofAYoHUNs/MJOLqQ8hIxeyz2QxOz8qdSVvp3PX/oPgA= @@ -676,10 +676,10 @@ github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4= -github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/PuerkitoBio/goquery v1.10.1 h1:Y8JGYUkXWTGRB6Ars3+j3kN0xg1YqqlwvdTV8WTFQcU= -github.com/PuerkitoBio/goquery v1.10.1/go.mod h1:IYiHrOMps66ag56LEH7QYDDupKXyo5A8qrjIx3ZtujY= +github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= +github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9HqT2AM8= +github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU= github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM= github.com/RoaringBitmap/roaring v1.9.3/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90= github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 h1:cSXom2MoKJ9KPPw29RoZtHvUETY4F4n/kXl8m9btnQ0= @@ -769,13 +769,12 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/buildkite/terminal-to-html/v3 v3.16.6 h1:QKHWPjAnKQnV1hVG/Nb2TwYDr4pliSbvCQDENk8EaJo= github.com/buildkite/terminal-to-html/v3 v3.16.6/go.mod h1:PgzeBymbRFC8I2m46Sci3S18AbwonEgpaz3TGhD7EPs= -github.com/caddyserver/certmagic v0.21.7 h1:66KJioPFJwttL43KYSWk7ErSmE6LfaJgCQuhm8Sg6fg= -github.com/caddyserver/certmagic v0.21.7/go.mod h1:LCPG3WLxcnjVKl/xpjzM0gqh0knrKKKiO5WVttX2eEI= +github.com/caddyserver/certmagic v0.22.0 h1:hi2skv2jouUw9uQUEyYSTTmqPZPHgf61dOANSIVCLOw= +github.com/caddyserver/certmagic v0.22.0/go.mod h1:Vc0msarAPhOagbDc/SU6M2zbzdwVuZ0lkTh2EqtH4vs= github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI= github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8= @@ -811,8 +810,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= -github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20241223141626-cff3c89139a3 h1:boJj011Hh+874zpIySeApCX4GeOjPl9qhRF3QuIZq+Q= +github.com/cncf/xds/go v0.0.0-20241223141626-cff3c89139a3/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -870,14 +869,18 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= -github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE= -github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= +github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= -github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY= @@ -1031,7 +1034,6 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= @@ -1056,8 +1058,9 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v64 v64.0.0 h1:4G61sozmY3eiPAjjoOHponXDBONm+utovTKbyUb2Qdg= github.com/google/go-github/v64 v64.0.0/go.mod h1:xB3vqMQNdHzilXBiO2I+M7iEFtHf+DP/omBOv6tQzVo= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -1179,8 +1182,8 @@ github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQykt github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jhillyerd/enmime/v2 v2.0.0 h1:I39PYf0peLGroKq+uX2yGB1ExH/78HcRJy4VmERQAVk= -github.com/jhillyerd/enmime/v2 v2.0.0/go.mod h1:wQkz7BochDzSukAz5ajAQaXOB7pEg5Vh5QWs7m1uAPw= +github.com/jhillyerd/enmime/v2 v2.1.0 h1:c8Qwi5Xq5EdtMN6byQWoZ/8I2RMTo6OJ7Xay+s1oPO0= +github.com/jhillyerd/enmime/v2 v2.1.0/go.mod h1:EJ74dcRbBcqHSP2TBu08XRoy6y3Yx0cevwb1YkGMEmQ= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -1205,8 +1208,8 @@ github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90 github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= -github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= @@ -1225,8 +1228,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= -github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= +github.com/libdns/libdns v0.2.3 h1:ba30K4ObwMGB/QTmqUxf3H4/GmUrCAIkMWejeGl12v8= +github.com/libdns/libdns v0.2.3/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 h1:F/3FfGmKdiKFa8kL3YrpZ7pe9H4l4AzA1pbaOUnRvPI= github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0/go.mod h1:JEfTc3+2DF9Z4PXhLLvXL42zexJyh8rIq3OzUj/0rAk= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= @@ -1253,12 +1256,12 @@ github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBW github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/meilisearch/meilisearch-go v0.31.0 h1:yZRhY1qJqdH8h6GFZALGtkDLyj8f9v5aJpsNMyrUmnY= github.com/meilisearch/meilisearch-go v0.31.0/go.mod h1:aNtyuwurDg/ggxQIcKqWH6G9g2ptc8GyY7PLY4zMn/g= -github.com/mholt/acmez/v3 v3.0.1 h1:4PcjKjaySlgXK857aTfDuRbmnM5gb3Ruz3tvoSJAUp8= -github.com/mholt/acmez/v3 v3.0.1/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= +github.com/mholt/acmez/v3 v3.1.0 h1:RlOx2SSZ8dIAM5GfkMe8TdaxjjkiHTGorlMUt8GeMzg= +github.com/mholt/acmez/v3 v3.1.0/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= -github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= -github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= +github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= +github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= @@ -1304,8 +1307,8 @@ github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= @@ -1331,8 +1334,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= -github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA= -github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= +github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= @@ -1358,8 +1361,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -1412,8 +1415,8 @@ github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= -github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g= +github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -1447,8 +1450,8 @@ github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCR github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -gitlab.com/gitlab-org/api/client-go v0.119.0 h1:YBZyx9XUTtEDBBYtY36cZWz6JmT7om/8HPSk37IS95g= -gitlab.com/gitlab-org/api/client-go v0.119.0/go.mod h1:ygHmS3AU3TpvK+AC6DYO1QuAxLlv6yxYK+/Votr/WFQ= +gitlab.com/gitlab-org/api/client-go v0.123.0 h1:W3LZ5QNyiSCJA0Zchkwz8nQIUzOuDoSWMZtRDT5DjPI= +gitlab.com/gitlab-org/api/client-go v0.123.0/go.mod h1:Jh0qjLILEdbO6z/OY94RD+3NDQRUKiuFSFYozN6cpKM= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -1460,22 +1463,24 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/detectors/gcp v1.32.0 h1:P78qWqkLSShicHmAzfECaTgvslqHxblNE9j62Ws1NK8= -go.opentelemetry.io/contrib/detectors/gcp v1.32.0/go.mod h1:TVqo0Sda4Cv8gCIixd7LuLwW4EylumVWfhjZJjDD4DU= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/detectors/gcp v1.34.0 h1:JRxssobiPg23otYU5SbWtQC//snGVIM3Tx6QRzlQBao= +go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= -go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -1507,8 +1512,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1539,8 +1544,8 @@ golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeap golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68= -golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY= +golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= +golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1573,8 +1578,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1640,8 +1645,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1671,8 +1676,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1693,8 +1698,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1786,8 +1791,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1802,8 +1807,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1824,16 +1829,16 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= -golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1898,8 +1903,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= +golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2116,10 +2121,10 @@ google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= -google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a h1:OAiGFfOiA0v9MRYsSidp3ubZaBnteRUyn3xB2ZQ5G/E= -google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24= +google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -2161,8 +2166,8 @@ google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2181,8 +2186,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= -google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= +google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/models/actions/run_list.go b/models/actions/run_list.go index 4046c7d369..b9b9324e07 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -10,6 +10,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/translation" webhook_module "code.gitea.io/gitea/modules/webhook" "xorm.io/builder" @@ -112,14 +113,14 @@ type StatusInfo struct { } // GetStatusInfoList returns a slice of StatusInfo -func GetStatusInfoList(ctx context.Context) []StatusInfo { +func GetStatusInfoList(ctx context.Context, lang translation.Locale) []StatusInfo { // same as those in aggregateJobStatus allStatus := []Status{StatusSuccess, StatusFailure, StatusWaiting, StatusRunning} statusInfoList := make([]StatusInfo, 0, 4) for _, s := range allStatus { statusInfoList = append(statusInfoList, StatusInfo{ Status: int(s), - DisplayedStatus: s.String(), + DisplayedStatus: s.LocaleString(lang), }) } return statusInfoList diff --git a/models/admin/task.go b/models/admin/task.go index c8bc95f981..5c2f7af49c 100644 --- a/models/admin/task.go +++ b/models/admin/task.go @@ -44,7 +44,7 @@ func init() { // TranslatableMessage represents JSON struct that can be translated with a Locale type TranslatableMessage struct { Format string - Args []any `json:"omitempty"` + Args []any `json:",omitempty"` } // LoadRepo loads repository of the task diff --git a/models/asymkey/ssh_key_authorized_keys.go b/models/asymkey/ssh_key_authorized_keys.go index d3f9f3f3be..57baf89c0c 100644 --- a/models/asymkey/ssh_key_authorized_keys.go +++ b/models/asymkey/ssh_key_authorized_keys.go @@ -87,19 +87,16 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error { } defer f.Close() - // Note: chmod command does not support in Windows. - if !setting.IsWindows { - fi, err := f.Stat() - if err != nil { - return err - } + fi, err := f.Stat() + if err != nil { + return err + } - // .ssh directory should have mode 700, and authorized_keys file should have mode 600. - if fi.Mode().Perm() > 0o600 { - log.Error("authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String()) - if err = f.Chmod(0o600); err != nil { - return err - } + // .ssh directory should have mode 700, and authorized_keys file should have mode 600. + if fi.Mode().Perm() > 0o600 { + log.Error("authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String()) + if err = f.Chmod(0o600); err != nil { + return err } } diff --git a/models/auth/access_token.go b/models/auth/access_token.go index 63331b4841..3ac18940a8 100644 --- a/models/auth/access_token.go +++ b/models/auth/access_token.go @@ -98,6 +98,15 @@ func init() { // NewAccessToken creates new access token. func NewAccessToken(ctx context.Context, t *AccessToken) error { + err := generateAccessToken(t) + if err != nil { + return err + } + _, err = db.GetEngine(ctx).Insert(t) + return err +} + +func generateAccessToken(t *AccessToken) error { salt, err := util.CryptoRandomString(10) if err != nil { return err @@ -110,8 +119,7 @@ func NewAccessToken(ctx context.Context, t *AccessToken) error { t.Token = hex.EncodeToString(token) t.TokenHash = HashToken(t.Token, t.TokenSalt) t.TokenLastEight = t.Token[len(t.Token)-8:] - _, err = db.GetEngine(ctx).Insert(t) - return err + return nil } // DisplayPublicOnly whether to display this as a public-only token. @@ -234,3 +242,25 @@ func DeleteAccessTokenByID(ctx context.Context, id, userID int64) error { } return nil } + +// RegenerateAccessTokenByID regenerates access token by given ID. +// It regenerates token and salt, as well as updates the creation time. +func RegenerateAccessTokenByID(ctx context.Context, id, userID int64) (*AccessToken, error) { + t := &AccessToken{} + found, err := db.GetEngine(ctx).Where("id = ? AND uid = ?", id, userID).Get(t) + if err != nil { + return nil, err + } else if !found { + return nil, ErrAccessTokenNotExist{} + } + + err = generateAccessToken(t) + if err != nil { + return nil, err + } + + // Reset the creation time, token is unused + t.UpdatedUnix = timeutil.TimeStampNow() + + return t, UpdateAccessToken(ctx, t) +} diff --git a/models/auth/access_token_test.go b/models/auth/access_token_test.go index e6ea4876e5..976ff37493 100644 --- a/models/auth/access_token_test.go +++ b/models/auth/access_token_test.go @@ -131,3 +131,28 @@ func TestDeleteAccessTokenByID(t *testing.T) { require.Error(t, err) assert.True(t, auth_model.IsErrAccessTokenNotExist(err)) } + +func TestRegenerateAccessTokenByID(t *testing.T) { + require.NoError(t, unittest.PrepareTestDatabase()) + + token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "4c6f36e6cf498e2a448662f915d932c09c5a146c") + require.NoError(t, err) + + newToken, err := auth_model.RegenerateAccessTokenByID(db.DefaultContext, token.ID, 1) + require.NoError(t, err) + unittest.AssertNotExistsBean(t, &auth_model.AccessToken{ID: token.ID, UID: token.UID, TokenHash: token.TokenHash}) + newToken = &auth_model.AccessToken{ + ID: newToken.ID, + UID: newToken.UID, + TokenHash: newToken.TokenHash, + } + unittest.AssertExistsAndLoadBean(t, newToken) + + // Token has been recreated, new salt and hash, but should retain the same ID, UID, Name and Scope + assert.Equal(t, token.ID, newToken.ID) + assert.NotEqual(t, token.TokenHash, newToken.TokenHash) + assert.NotEqual(t, token.TokenSalt, newToken.TokenSalt) + assert.Equal(t, token.UID, newToken.UID) + assert.Equal(t, token.Name, newToken.Name) + assert.Equal(t, token.Scope, newToken.Scope) +} diff --git a/models/auth/source.go b/models/auth/source.go index 214eb3afa0..d7ed6b97a8 100644 --- a/models/auth/source.go +++ b/models/auth/source.go @@ -32,7 +32,7 @@ const ( PAM // 4 DLDAP // 5 OAuth2 // 6 - SSPI // 7 + _ // 7 (was SSPI) Remote // 8 ) @@ -53,7 +53,6 @@ var Names = map[Type]string{ SMTP: "SMTP", PAM: "PAM", OAuth2: "OAuth2", - SSPI: "SPNEGO with SSPI", Remote: "Remote", } @@ -178,11 +177,6 @@ func (source *Source) IsOAuth2() bool { return source.Type == OAuth2 } -// IsSSPI returns true of this source is of the SSPI type. -func (source *Source) IsSSPI() bool { - return source.Type == SSPI -} - func (source *Source) IsRemote() bool { return source.Type == Remote } @@ -265,20 +259,6 @@ func (opts FindSourcesOptions) ToConds() builder.Cond { return conds } -// IsSSPIEnabled returns true if there is at least one activated login -// source of type LoginSSPI -func IsSSPIEnabled(ctx context.Context) bool { - exist, err := db.Exist[Source](ctx, FindSourcesOptions{ - IsActive: optional.Some(true), - LoginType: SSPI, - }.ToConds()) - if err != nil { - log.Error("IsSSPIEnabled: failed to query active SSPI sources: %v", err) - return false - } - return exist -} - // GetSourceByID returns login source by given ID. func GetSourceByID(ctx context.Context, id int64) (*Source, error) { source := new(Source) diff --git a/models/fixtures/PrivateIssueProjects/project.yml b/models/fixtures/PrivateIssueProjects/project.yml index cf63e4e413..8950b33606 100644 --- a/models/fixtures/PrivateIssueProjects/project.yml +++ b/models/fixtures/PrivateIssueProjects/project.yml @@ -1,6 +1,6 @@ - id: 1001 - title: Org project that contains private issues + title: Org project that contains private and public issues owner_id: 3 repo_id: 0 is_closed: false @@ -12,7 +12,7 @@ - id: 1002 - title: User project that contains private issues + title: User project that contains private and public issues owner_id: 2 repo_id: 0 is_closed: false diff --git a/models/fixtures/PrivateIssueProjects/project_issue.yml b/models/fixtures/PrivateIssueProjects/project_issue.yml index 222b2e5f71..0245fb47f3 100644 --- a/models/fixtures/PrivateIssueProjects/project_issue.yml +++ b/models/fixtures/PrivateIssueProjects/project_issue.yml @@ -9,3 +9,15 @@ issue_id: 7 project_id: 1002 project_board_id: 1002 + +- + id: 1003 + issue_id: 16 + project_id: 1001 + project_board_id: 1001 + +- + id: 1004 + issue_id: 1 + project_id: 1002 + project_board_id: 1002 diff --git a/models/forgejo_migrations/v18.go b/models/forgejo_migrations/v18.go index afccfbfe15..e6c1493f0e 100644 --- a/models/forgejo_migrations/v18.go +++ b/models/forgejo_migrations/v18.go @@ -14,5 +14,5 @@ type FollowingRepo struct { } func CreateFollowingRepoTable(x *xorm.Engine) error { - return x.Sync(new(FederatedUser)) + return x.Sync(new(FollowingRepo)) } diff --git a/models/issues/action_aggregator.go b/models/issues/action_aggregator.go new file mode 100644 index 0000000000..722696fbb2 --- /dev/null +++ b/models/issues/action_aggregator.go @@ -0,0 +1,375 @@ +// Copyright 2025 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-or-later + +package issues + +import ( + "slices" + + "code.gitea.io/gitea/models/organization" + user_model "code.gitea.io/gitea/models/user" +) + +type ActionAggregator struct { + StartUnix int64 + AggAge int64 + PosterID int64 + StartInd int + EndInd int + + PrevClosed bool + IsClosed bool + + AddedLabels []*Label + RemovedLabels []*Label + + AddedRequestReview []RequestReviewTarget + RemovedRequestReview []RequestReviewTarget +} + +// Get the time threshold for aggregation of multiple actions together +func (agg *ActionAggregator) timeThreshold() int64 { + if agg.AggAge > (60 * 60 * 24 * 30) { // Age > 1 month, aggregate by day + return 60 * 60 * 24 + } else if agg.AggAge > (60 * 60 * 24) { // Age > 1 day, aggregate by hour + return 60 * 60 + } else if agg.AggAge > (60 * 60) { // Age > 1 hour, aggregate by 10 mins + return 60 * 10 + } + // Else, aggregate by minute + return 60 +} + +// TODO Aggregate also +// - Dependency added / removed +// - Added / Removed due date +// - Milestone Added / Removed +func (agg *ActionAggregator) aggregateAction(c *Comment, index int) { + if agg.StartInd == -1 { + agg.StartInd = index + } + agg.EndInd = index + + if c.Type == CommentTypeClose { + agg.IsClosed = true + } else if c.Type == CommentTypeReopen { + agg.IsClosed = false + } else if c.Type == CommentTypeReviewRequest { + if c.AssigneeID > 0 { + req := RequestReviewTarget{User: c.Assignee} + if c.RemovedAssignee { + agg.delReviewRequest(req) + } else { + agg.addReviewRequest(req) + } + } else if c.AssigneeTeamID > 0 { + req := RequestReviewTarget{Team: c.AssigneeTeam} + if c.RemovedAssignee { + agg.delReviewRequest(req) + } else { + agg.addReviewRequest(req) + } + } + + for _, r := range c.RemovedRequestReview { + agg.delReviewRequest(r) + } + + for _, r := range c.AddedRequestReview { + agg.addReviewRequest(r) + } + } else if c.Type == CommentTypeLabel { + if c.Content == "1" { + agg.addLabel(c.Label) + } else { + agg.delLabel(c.Label) + } + } else if c.Type == CommentTypeAggregator { + agg.Merge(c.Aggregator) + } +} + +// Merge a past CommentAggregator with the next one in the issue comments list +func (agg *ActionAggregator) Merge(next *ActionAggregator) { + agg.IsClosed = next.IsClosed + + for _, l := range next.AddedLabels { + agg.addLabel(l) + } + + for _, l := range next.RemovedLabels { + agg.delLabel(l) + } + + for _, r := range next.AddedRequestReview { + agg.addReviewRequest(r) + } + + for _, r := range next.RemovedRequestReview { + agg.delReviewRequest(r) + } +} + +// Check if a comment can be aggregated or not depending on its type +func (agg *ActionAggregator) IsAggregated(t *CommentType) bool { + switch *t { + case CommentTypeAggregator, CommentTypeClose, CommentTypeReopen, CommentTypeLabel, CommentTypeReviewRequest: + { + return true + } + default: + { + return false + } + } +} + +// Add a label to the aggregated list +func (agg *ActionAggregator) addLabel(lbl *Label) { + for l, agglbl := range agg.RemovedLabels { + if agglbl.ID == lbl.ID { + agg.RemovedLabels = slices.Delete(agg.RemovedLabels, l, l+1) + return + } + } + + if !slices.ContainsFunc(agg.AddedLabels, func(l *Label) bool { return l.ID == lbl.ID }) { + agg.AddedLabels = append(agg.AddedLabels, lbl) + } +} + +// Remove a label from the aggregated list +func (agg *ActionAggregator) delLabel(lbl *Label) { + for l, agglbl := range agg.AddedLabels { + if agglbl.ID == lbl.ID { + agg.AddedLabels = slices.Delete(agg.AddedLabels, l, l+1) + return + } + } + + if !slices.ContainsFunc(agg.RemovedLabels, func(l *Label) bool { return l.ID == lbl.ID }) { + agg.RemovedLabels = append(agg.RemovedLabels, lbl) + } +} + +// Add a review request to the aggregated list +func (agg *ActionAggregator) addReviewRequest(req RequestReviewTarget) { + reqid := req.ID() + reqty := req.Type() + for r, aggreq := range agg.RemovedRequestReview { + if (aggreq.ID() == reqid) && (aggreq.Type() == reqty) { + agg.RemovedRequestReview = slices.Delete(agg.RemovedRequestReview, r, r+1) + return + } + } + + if !slices.ContainsFunc(agg.AddedRequestReview, func(r RequestReviewTarget) bool { return (r.ID() == reqid) && (r.Type() == reqty) }) { + agg.AddedRequestReview = append(agg.AddedRequestReview, req) + } +} + +// Delete a review request from the aggregated list +func (agg *ActionAggregator) delReviewRequest(req RequestReviewTarget) { + reqid := req.ID() + reqty := req.Type() + for r, aggreq := range agg.AddedRequestReview { + if (aggreq.ID() == reqid) && (aggreq.Type() == reqty) { + agg.AddedRequestReview = slices.Delete(agg.AddedRequestReview, r, r+1) + return + } + } + + if !slices.ContainsFunc(agg.RemovedRequestReview, func(r RequestReviewTarget) bool { return (r.ID() == reqid) && (r.Type() == reqty) }) { + agg.RemovedRequestReview = append(agg.RemovedRequestReview, req) + } +} + +// Check if anything has changed with this aggregated list of comments +func (agg *ActionAggregator) Changed() bool { + return (agg.IsClosed != agg.PrevClosed) || + (len(agg.AddedLabels) > 0) || + (len(agg.RemovedLabels) > 0) || + (len(agg.AddedRequestReview) > 0) || + (len(agg.RemovedRequestReview) > 0) +} + +func (agg *ActionAggregator) OnlyLabelsChanged() bool { + return ((len(agg.AddedLabels) > 0) || (len(agg.RemovedLabels) > 0)) && + (len(agg.AddedRequestReview) == 0) && (len(agg.RemovedRequestReview) == 0) && + (agg.PrevClosed == agg.IsClosed) +} + +func (agg *ActionAggregator) OnlyRequestReview() bool { + return ((len(agg.AddedRequestReview) > 0) || (len(agg.RemovedRequestReview) > 0)) && + (len(agg.AddedLabels) == 0) && (len(agg.RemovedLabels) == 0) && + (agg.PrevClosed == agg.IsClosed) +} + +func (agg *ActionAggregator) OnlyClosedReopened() bool { + return (agg.IsClosed != agg.PrevClosed) && + (len(agg.AddedLabels) == 0) && (len(agg.RemovedLabels) == 0) && + (len(agg.AddedRequestReview) == 0) && (len(agg.RemovedRequestReview) == 0) +} + +// Reset the aggregator to start a new aggregating context +func (agg *ActionAggregator) Reset(cur *Comment, now int64) { + agg.StartUnix = int64(cur.CreatedUnix) + agg.AggAge = now - agg.StartUnix + agg.PosterID = cur.PosterID + + agg.PrevClosed = agg.IsClosed + + agg.StartInd = -1 + agg.EndInd = -1 + agg.AddedLabels = []*Label{} + agg.RemovedLabels = []*Label{} + agg.AddedRequestReview = []RequestReviewTarget{} + agg.RemovedRequestReview = []RequestReviewTarget{} +} + +// Function that replaces all the comments aggregated with a single one +// Its CommentType depend on whether multiple type of comments are been aggregated or not +// If nothing has changed, we remove all the comments that get nullified +// +// The function returns how many comments has been removed, in order for the "for" loop +// of the main algorithm to change its index +func (agg *ActionAggregator) createAggregatedComment(issue *Issue, final bool) int { + // If the aggregation of comments make the whole thing null, erase all the comments + if !agg.Changed() { + if final { + issue.Comments = issue.Comments[:agg.StartInd] + } else { + issue.Comments = slices.Replace(issue.Comments, agg.StartInd, agg.EndInd+1) + } + return (agg.EndInd - agg.StartInd) + 1 + } + + newAgg := *agg // Trigger a memory allocation, get a COPY of the aggregator + + // Keep the same author, time, etc... But reset the parts we may want to use + comment := issue.Comments[agg.StartInd] + comment.Content = "" + comment.Label = nil + comment.Aggregator = nil + comment.Assignee = nil + comment.AssigneeID = 0 + comment.AssigneeTeam = nil + comment.AssigneeTeamID = 0 + comment.RemovedAssignee = false + comment.AddedLabels = nil + comment.RemovedLabels = nil + + // In case there's only a single change, create a comment of this type + // instead of an aggregator + if agg.OnlyLabelsChanged() { + comment.Type = CommentTypeLabel + } else if agg.OnlyClosedReopened() { + if agg.IsClosed { + comment.Type = CommentTypeClose + } else { + comment.Type = CommentTypeReopen + } + } else if agg.OnlyRequestReview() { + comment.Type = CommentTypeReviewRequest + } else { + comment.Type = CommentTypeAggregator + comment.Aggregator = &newAgg + } + + if len(newAgg.AddedLabels) > 0 { + comment.AddedLabels = newAgg.AddedLabels + } + + if len(newAgg.RemovedLabels) > 0 { + comment.RemovedLabels = newAgg.RemovedLabels + } + + if len(newAgg.AddedRequestReview) > 0 { + comment.AddedRequestReview = newAgg.AddedRequestReview + } + + if len(newAgg.RemovedRequestReview) > 0 { + comment.RemovedRequestReview = newAgg.RemovedRequestReview + } + + if final { + issue.Comments = append(issue.Comments[:agg.StartInd], comment) + } else { + issue.Comments = slices.Replace(issue.Comments, agg.StartInd, agg.EndInd+1, comment) + } + return agg.EndInd - agg.StartInd +} + +// combineCommentsHistory combines nearby elements in the history as one +func CombineCommentsHistory(issue *Issue, now int64) { + if len(issue.Comments) < 1 { + return + } + + // Initialise a new empty aggregator, ready to combine comments + var agg ActionAggregator + agg.Reset(issue.Comments[0], now) + + for i := 0; i < len(issue.Comments); i++ { + cur := issue.Comments[i] + // If the comment we encounter is not accepted inside an aggregator + if !agg.IsAggregated(&cur.Type) { + // If we aggregated some data, create the resulting comment for it + if agg.StartInd != -1 { + i -= agg.createAggregatedComment(issue, false) + } + + agg.StartInd = -1 + if i+1 < len(issue.Comments) { + agg.Reset(issue.Comments[i+1], now) + } + + // Do not need to continue the aggregation loop, skip to next comment + continue + } + + // If the comment we encounter cannot be aggregated with the current aggregator, + // we create a new empty aggregator + threshold := agg.timeThreshold() + if ((int64(cur.CreatedUnix) - agg.StartUnix) > threshold) || (cur.PosterID != agg.PosterID) { + // First, create the aggregated comment if there's data in it + if agg.StartInd != -1 { + i -= agg.createAggregatedComment(issue, false) + } + agg.Reset(cur, now) + } + + agg.aggregateAction(cur, i) + } + + // Create the aggregated comment if there's data in it + if agg.StartInd != -1 { + agg.createAggregatedComment(issue, true) + } +} + +type RequestReviewTarget struct { + User *user_model.User + Team *organization.Team +} + +func (t *RequestReviewTarget) ID() int64 { + if t.User != nil { + return t.User.ID + } + return t.Team.ID +} + +func (t *RequestReviewTarget) Name() string { + if t.User != nil { + return t.User.GetDisplayName() + } + return t.Team.Name +} + +func (t *RequestReviewTarget) Type() string { + if t.User != nil { + return "user" + } + return "team" +} diff --git a/models/issues/comment.go b/models/issues/comment.go index 0bf53bb4dd..f77b2bcc8d 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -114,6 +114,8 @@ const ( CommentTypePin // 36 pin Issue CommentTypeUnpin // 37 unpin Issue + + CommentTypeAggregator // 38 Aggregator of comments ) var commentStrings = []string{ @@ -155,6 +157,7 @@ var commentStrings = []string{ "pull_cancel_scheduled_merge", "pin", "unpin", + "action_aggregator", } func (t CommentType) String() string { @@ -236,12 +239,6 @@ func (r RoleInRepo) LocaleHelper(lang translation.Locale) string { return lang.TrString("repo.issues.role." + string(r) + "_helper") } -type RequestReviewTarget interface { - ID() int64 - Name() string - Type() string -} - // Comment represents a comment in commit and issue page. type Comment struct { ID int64 `xorm:"pk autoincr"` @@ -254,6 +251,7 @@ type Comment struct { Issue *Issue `xorm:"-"` LabelID int64 Label *Label `xorm:"-"` + Aggregator *ActionAggregator `xorm:"-"` AddedLabels []*Label `xorm:"-"` RemovedLabels []*Label `xorm:"-"` AddedRequestReview []RequestReviewTarget `xorm:"-"` diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index f606b713cf..697ef7fad6 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -56,12 +56,11 @@ func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column, doer *us ProjectID: b.ProjectID, SortType: "project-column-sorting", IsClosed: isClosed, + AllPublic: true, } if doer != nil { issueOpts.User = doer issueOpts.Org = org - } else { - issueOpts.AllPublic = true } issueList, err := Issues(ctx, issueOpts) diff --git a/models/issues/issue_project_test.go b/models/issues/issue_project_test.go index 6ebc803722..e28b52128e 100644 --- a/models/issues/issue_project_test.go +++ b/models/issues/issue_project_test.go @@ -33,12 +33,13 @@ func TestPrivateIssueProjects(t *testing.T) { defer tests.PrintCurrentTest(t)() issueList, err := issues.LoadIssuesFromColumn(db.DefaultContext, column, user2, org, optional.None[bool]()) require.NoError(t, err) - assert.Len(t, issueList, 1) - assert.EqualValues(t, 6, issueList[0].ID) + assert.Len(t, issueList, 2) + assert.EqualValues(t, 16, issueList[0].ID) + assert.EqualValues(t, 6, issueList[1].ID) issuesNum, err := issues.NumIssuesInProject(db.DefaultContext, orgProject, user2, org, optional.None[bool]()) require.NoError(t, err) - assert.EqualValues(t, 1, issuesNum) + assert.EqualValues(t, 2, issuesNum) issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, orgProject, user2, org, optional.Some(true)) require.NoError(t, err) @@ -46,18 +47,27 @@ func TestPrivateIssueProjects(t *testing.T) { issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, orgProject, user2, org, optional.Some(false)) require.NoError(t, err) - assert.EqualValues(t, 1, issuesNum) + assert.EqualValues(t, 2, issuesNum) }) t.Run("Anonymous user", func(t *testing.T) { defer tests.PrintCurrentTest(t)() issueList, err := issues.LoadIssuesFromColumn(db.DefaultContext, column, nil, org, optional.None[bool]()) require.NoError(t, err) - assert.Empty(t, issueList) + assert.Len(t, issueList, 1) + assert.EqualValues(t, 16, issueList[0].ID) issuesNum, err := issues.NumIssuesInProject(db.DefaultContext, orgProject, nil, org, optional.None[bool]()) require.NoError(t, err) + assert.EqualValues(t, 1, issuesNum) + + issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, orgProject, nil, org, optional.Some(true)) + require.NoError(t, err) assert.EqualValues(t, 0, issuesNum) + + issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, orgProject, nil, org, optional.Some(false)) + require.NoError(t, err) + assert.EqualValues(t, 1, issuesNum) }) }) @@ -69,12 +79,13 @@ func TestPrivateIssueProjects(t *testing.T) { defer tests.PrintCurrentTest(t)() issueList, err := issues.LoadIssuesFromColumn(db.DefaultContext, column, user2, nil, optional.None[bool]()) require.NoError(t, err) - assert.Len(t, issueList, 1) + assert.Len(t, issueList, 2) assert.EqualValues(t, 7, issueList[0].ID) + assert.EqualValues(t, 1, issueList[1].ID) issuesNum, err := issues.NumIssuesInProject(db.DefaultContext, userProject, user2, nil, optional.None[bool]()) require.NoError(t, err) - assert.EqualValues(t, 1, issuesNum) + assert.EqualValues(t, 2, issuesNum) issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, userProject, user2, nil, optional.Some(true)) require.NoError(t, err) @@ -82,19 +93,27 @@ func TestPrivateIssueProjects(t *testing.T) { issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, userProject, user2, nil, optional.Some(false)) require.NoError(t, err) - assert.EqualValues(t, 1, issuesNum) + assert.EqualValues(t, 2, issuesNum) }) t.Run("Anonymous user", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - issueList, err := issues.LoadIssuesFromColumn(db.DefaultContext, column, nil, nil, optional.None[bool]()) require.NoError(t, err) - assert.Empty(t, issueList) + assert.Len(t, issueList, 1) + assert.EqualValues(t, 1, issueList[0].ID) issuesNum, err := issues.NumIssuesInProject(db.DefaultContext, userProject, nil, nil, optional.None[bool]()) require.NoError(t, err) + assert.EqualValues(t, 1, issuesNum) + + issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, userProject, nil, nil, optional.Some(true)) + require.NoError(t, err) assert.EqualValues(t, 0, issuesNum) + + issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, userProject, nil, nil, optional.Some(false)) + require.NoError(t, err) + assert.EqualValues(t, 1, issuesNum) }) }) } diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index e9f116bfc6..56c219af39 100644 --- a/models/issues/issue_search.go +++ b/models/issues/issue_search.go @@ -49,9 +49,13 @@ type IssuesOptions struct { //nolint // prioritize issues from this repo PriorityRepoID int64 IsArchived optional.Option[bool] - Org *organization.Organization // issues permission scope - Team *organization.Team // issues permission scope - User *user_model.User // issues permission scope + + // If combined with AllPublic, then private as well as public issues + // that matches the criteria will be returned, if AllPublic is false + // only the private issues will be returned. + Org *organization.Organization // issues permission scope + Team *organization.Team // issues permission scope + User *user_model.User // issues permission scope } // applySorts sort an issues-related session based on the provided @@ -196,7 +200,8 @@ func applyRepoConditions(sess *xorm.Session, opts *IssuesOptions) { } else if len(opts.RepoIDs) > 1 { opts.RepoCond = builder.In("issue.repo_id", opts.RepoIDs) } - if opts.AllPublic { + // If permission scoping is set, then we set this condition at a later stage. + if opts.AllPublic && opts.User == nil { if opts.RepoCond == nil { opts.RepoCond = builder.NewCond() } @@ -268,7 +273,14 @@ func applyConditions(sess *xorm.Session, opts *IssuesOptions) { applyLabelsCondition(sess, opts) if opts.User != nil { - sess.And(issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.Value())) + cond := issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.Value()) + // If AllPublic was set, then also consider all issues in public + // repositories in addition to the private repositories the user has access + // to. + if opts.AllPublic { + cond = cond.Or(builder.In("issue.repo_id", builder.Select("id").From("repository").Where(builder.Eq{"is_private": false}))) + } + sess.And(cond) } } diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index 580be9663b..d121435f0a 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -4,7 +4,6 @@ package issues_test import ( - "context" "fmt" "sort" "sync" @@ -309,7 +308,7 @@ func TestIssue_ResolveMentions(t *testing.T) { func TestResourceIndex(t *testing.T) { require.NoError(t, unittest.PrepareTestDatabase()) - beforeCount, err := issues_model.CountIssues(context.Background(), &issues_model.IssuesOptions{}) + beforeCount, err := issues_model.CountIssues(t.Context(), &issues_model.IssuesOptions{}) require.NoError(t, err) var wg sync.WaitGroup @@ -326,7 +325,7 @@ func TestResourceIndex(t *testing.T) { t.Parallel() wg.Wait() - afterCount, err := issues_model.CountIssues(context.Background(), &issues_model.IssuesOptions{}) + afterCount, err := issues_model.CountIssues(t.Context(), &issues_model.IssuesOptions{}) require.NoError(t, err) assert.EqualValues(t, 100, afterCount-beforeCount) }) @@ -354,7 +353,7 @@ func TestCorrectIssueStats(t *testing.T) { wg.Wait() // Now we will get all issueID's that match the "Bugs are nasty" query. - issues, err := issues_model.Issues(context.TODO(), &issues_model.IssuesOptions{ + issues, err := issues_model.Issues(t.Context(), &issues_model.IssuesOptions{ Paginator: &db.ListOptions{ PageSize: issueAmount, }, diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index 775ebfadad..ad59b767ab 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -64,6 +64,10 @@ func changeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, } func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isMergePull bool) (*Comment, error) { + if user_model.IsBlockedMultiple(ctx, []int64{issue.Repo.OwnerID, issue.PosterID}, doer.ID) { + return nil, user_model.ErrBlockedByUser + } + // Check for open dependencies if issue.IsClosed && issue.Repo.IsDependenciesEnabled(ctx) { // only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies diff --git a/models/migrations/test/tests.go b/models/migrations/test/tests.go index 0e37233471..177e33c56a 100644 --- a/models/migrations/test/tests.go +++ b/models/migrations/test/tests.go @@ -11,7 +11,6 @@ import ( "os" "path" "path/filepath" - "runtime" "strings" "testing" "time" @@ -123,9 +122,6 @@ func MainTest(m *testing.M) { os.Exit(1) } giteaBinary := "gitea" - if runtime.GOOS == "windows" { - giteaBinary += ".exe" - } setting.AppPath = path.Join(giteaRoot, giteaBinary) if _, err := os.Stat(setting.AppPath); err != nil { fmt.Printf("Could not find gitea binary at %s\n", setting.AppPath) diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go index 32c871558a..31ab84fd68 100644 --- a/models/packages/descriptor.go +++ b/models/packages/descriptor.go @@ -110,9 +110,12 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc if err != nil { return nil, err } - repository, err := repo_model.GetRepositoryByID(ctx, p.RepoID) - if err != nil && !repo_model.IsErrRepoNotExist(err) { - return nil, err + var repository *repo_model.Repository + if p.RepoID > 0 { + repository, err = repo_model.GetRepositoryByID(ctx, p.RepoID) + if err != nil && !repo_model.IsErrRepoNotExist(err) { + return nil, err + } } creator, err := user_model.GetUserByID(ctx, pv.CreatorID) if err != nil { diff --git a/models/packages/package.go b/models/packages/package.go index fd408f8bef..874c7c2847 100644 --- a/models/packages/package.go +++ b/models/packages/package.go @@ -242,6 +242,11 @@ func SetRepositoryLink(ctx context.Context, packageID, repoID int64) error { return err } +func UnlinkRepository(ctx context.Context, packageID int64) error { + _, err := db.GetEngine(ctx).ID(packageID).Cols("repo_id").Update(&Package{RepoID: 0}) + return err +} + // UnlinkRepositoryFromAllPackages unlinks every package from the repository func UnlinkRepositoryFromAllPackages(ctx context.Context, repoID int64) error { _, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Cols("repo_id").Update(&Package{}) diff --git a/models/quota/default.go b/models/quota/default.go index 6b553d6f71..e53e47bade 100644 --- a/models/quota/default.go +++ b/models/quota/default.go @@ -7,7 +7,7 @@ import ( "code.gitea.io/gitea/modules/setting" ) -func EvaluateDefault(used Used, forSubject LimitSubject) bool { +func EvaluateDefault(used Used, forSubject LimitSubject) (bool, int64) { groups := GroupList{ &Group{ Name: "builtin-default-group", diff --git a/models/quota/group.go b/models/quota/group.go index 0acb5b255e..50080748a1 100644 --- a/models/quota/group.go +++ b/models/quota/group.go @@ -5,6 +5,7 @@ package quota import ( "context" + "math" "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" @@ -199,15 +200,20 @@ var affectsMap = map[LimitSubject]LimitSubjects{ }, } -func (g *Group) Evaluate(used Used, forSubject LimitSubject) (bool, bool) { +// Evaluate returns whether the size used is acceptable for the topic if a rule +// was found, and returns the smallest limit of all applicable rules or the +// first limit found to be unacceptable for the size used. +func (g *Group) Evaluate(used Used, forSubject LimitSubject) (bool, bool, int64) { var found bool + foundLimit := int64(math.MaxInt64) for _, rule := range g.Rules { ok, has := rule.Evaluate(used, forSubject) if has { - found = true if !ok { - return false, true + return false, true, rule.Limit } + found = true + foundLimit = min(foundLimit, rule.Limit) } } @@ -216,32 +222,35 @@ func (g *Group) Evaluate(used Used, forSubject LimitSubject) (bool, bool) { // subjects below for _, subject := range affectsMap[forSubject] { - ok, has := g.Evaluate(used, subject) + ok, has, limit := g.Evaluate(used, subject) if has { - found = true if !ok { - return false, true + return false, true, limit } + found = true + foundLimit = min(foundLimit, limit) } } } - return true, found + return true, found, foundLimit } -func (gl *GroupList) Evaluate(used Used, forSubject LimitSubject) bool { +// Evaluate returns if the used size is acceptable for the subject and the +// lowest limit that is acceptable for the subject. +func (gl *GroupList) Evaluate(used Used, forSubject LimitSubject) (bool, int64) { // If there are no groups, use the configured defaults: if gl == nil || len(*gl) == 0 { return EvaluateDefault(used, forSubject) } for _, group := range *gl { - ok, has := group.Evaluate(used, forSubject) + ok, has, limit := group.Evaluate(used, forSubject) if has && ok { - return true + return true, limit } } - return false + return false, 0 } func GetGroupByName(ctx context.Context, name string) (*Group, error) { diff --git a/models/quota/quota.go b/models/quota/quota.go index d38bfab3cc..ee3fec6c1a 100644 --- a/models/quota/quota.go +++ b/models/quota/quota.go @@ -32,5 +32,6 @@ func EvaluateForUser(ctx context.Context, userID int64, subject LimitSubject) (b return false, err } - return groups.Evaluate(*used, subject), nil + acceptable, _ := groups.Evaluate(*used, subject) + return acceptable, nil } diff --git a/models/quota/quota_group_test.go b/models/quota/quota_group_test.go index bc258588f9..edbf43fcf5 100644 --- a/models/quota/quota_group_test.go +++ b/models/quota/quota_group_test.go @@ -4,6 +4,7 @@ package quota_test import ( + "math" "testing" quota_model "code.gitea.io/gitea/models/quota" @@ -36,9 +37,10 @@ func TestQuotaGroupAllRulesMustPass(t *testing.T) { // Within a group, *all* rules must pass. Thus, if we have a deny-all rule, // and an unlimited rule, that will always fail. - ok, has := group.Evaluate(used, quota_model.LimitSubjectSizeAll) + ok, has, limit := group.Evaluate(used, quota_model.LimitSubjectSizeAll) assert.True(t, has) assert.False(t, ok) + assert.EqualValues(t, 0, limit) } func TestQuotaGroupRuleScenario1(t *testing.T) { @@ -66,21 +68,25 @@ func TestQuotaGroupRuleScenario1(t *testing.T) { used.Size.Assets.Packages.All = 256 used.Size.Git.LFS = 16 - ok, has := group.Evaluate(used, quota_model.LimitSubjectSizeAssetsAttachmentsReleases) + ok, has, limit := group.Evaluate(used, quota_model.LimitSubjectSizeAssetsAttachmentsReleases) assert.True(t, has, "size:assets:attachments:releases is covered") assert.True(t, ok, "size:assets:attachments:releases passes") + assert.EqualValues(t, 1024, limit) - ok, has = group.Evaluate(used, quota_model.LimitSubjectSizeAssetsPackagesAll) + ok, has, limit = group.Evaluate(used, quota_model.LimitSubjectSizeAssetsPackagesAll) assert.True(t, has, "size:assets:packages:all is covered") assert.True(t, ok, "size:assets:packages:all passes") + assert.EqualValues(t, 1024, limit) - ok, has = group.Evaluate(used, quota_model.LimitSubjectSizeGitLFS) + ok, has, limit = group.Evaluate(used, quota_model.LimitSubjectSizeGitLFS) assert.True(t, has, "size:git:lfs is covered") assert.False(t, ok, "size:git:lfs fails") + assert.EqualValues(t, 0, limit) - ok, has = group.Evaluate(used, quota_model.LimitSubjectSizeAll) + ok, has, limit = group.Evaluate(used, quota_model.LimitSubjectSizeAll) assert.True(t, has, "size:all is covered") assert.False(t, ok, "size:all fails") + assert.EqualValues(t, 0, limit) } func TestQuotaGroupRuleCombination(t *testing.T) { @@ -109,23 +115,27 @@ func TestQuotaGroupRuleCombination(t *testing.T) { } // Git LFS isn't covered by any rule - _, has := group.Evaluate(used, quota_model.LimitSubjectSizeGitLFS) + _, has, limit := group.Evaluate(used, quota_model.LimitSubjectSizeGitLFS) assert.False(t, has) + assert.EqualValues(t, math.MaxInt, limit) // repos:all is covered, and is passing - ok, has := group.Evaluate(used, quota_model.LimitSubjectSizeReposAll) + ok, has, limit := group.Evaluate(used, quota_model.LimitSubjectSizeReposAll) assert.True(t, has) assert.True(t, ok) + assert.EqualValues(t, 4096, limit) // packages:all is covered, and is failing - ok, has = group.Evaluate(used, quota_model.LimitSubjectSizeAssetsPackagesAll) + ok, has, limit = group.Evaluate(used, quota_model.LimitSubjectSizeAssetsPackagesAll) assert.True(t, has) assert.False(t, ok) + assert.EqualValues(t, 0, limit) // size:all is covered, and is failing (due to packages:all being over quota) - ok, has = group.Evaluate(used, quota_model.LimitSubjectSizeAll) + ok, has, limit = group.Evaluate(used, quota_model.LimitSubjectSizeAll) assert.True(t, has, "size:all should be covered") assert.False(t, ok, "size:all should fail") + assert.EqualValues(t, 0, limit) } func TestQuotaGroupListsRequireOnlyOnePassing(t *testing.T) { @@ -159,8 +169,9 @@ func TestQuotaGroupListsRequireOnlyOnePassing(t *testing.T) { used.Size.Repos.Public = 1024 // In a group list, if any group passes, the entire evaluation passes. - ok := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) + ok, limit := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) assert.True(t, ok) + assert.EqualValues(t, -1, limit) } func TestQuotaGroupListAllFailing(t *testing.T) { @@ -193,8 +204,9 @@ func TestQuotaGroupListAllFailing(t *testing.T) { used := quota_model.Used{} used.Size.Repos.Public = 2048 - ok := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) + ok, limit := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) assert.False(t, ok) + assert.EqualValues(t, 0, limit) } func TestQuotaGroupListEmpty(t *testing.T) { @@ -203,6 +215,7 @@ func TestQuotaGroupListEmpty(t *testing.T) { used := quota_model.Used{} used.Size.Repos.Public = 2048 - ok := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) + ok, limit := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) assert.True(t, ok) + assert.EqualValues(t, -1, limit) } diff --git a/models/quota/rule.go b/models/quota/rule.go index b0c6c0f4b6..cb23b74b52 100644 --- a/models/quota/rule.go +++ b/models/quota/rule.go @@ -20,6 +20,22 @@ func (r *Rule) TableName() string { return "quota_rule" } +func (r Rule) Acceptable(used Used) bool { + if r.Limit == -1 { + return true + } + + return r.Sum(used) <= r.Limit +} + +func (r Rule) Sum(used Used) int64 { + var sum int64 + for _, subject := range r.Subjects { + sum += used.CalculateFor(subject) + } + return sum +} + func (r Rule) Evaluate(used Used, forSubject LimitSubject) (bool, bool) { // If there's no limit, short circuit out if r.Limit == -1 { @@ -31,11 +47,7 @@ func (r Rule) Evaluate(used Used, forSubject LimitSubject) (bool, bool) { return false, false } - var sum int64 - for _, subject := range r.Subjects { - sum += used.CalculateFor(subject) - } - return sum <= r.Limit, true + return r.Sum(used) <= r.Limit, true } func (r *Rule) Edit(ctx context.Context, limit *int64, subjects *LimitSubjects) (*Rule, error) { diff --git a/models/user/avatar_test.go b/models/user/avatar_test.go index ea96ab4f97..974a714477 100644 --- a/models/user/avatar_test.go +++ b/models/user/avatar_test.go @@ -4,7 +4,6 @@ package user import ( - "context" "io" "strings" "testing" @@ -37,7 +36,7 @@ func TestUserAvatarGenerate(t *testing.T) { require.NoError(t, unittest.PrepareTestDatabase()) var err error tmpDir := t.TempDir() - storage.Avatars, err = storage.NewLocalStorage(context.Background(), &setting.Storage{Path: tmpDir}) + storage.Avatars, err = storage.NewLocalStorage(t.Context(), &setting.Storage{Path: tmpDir}) require.NoError(t, err) u := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}) diff --git a/models/user/user_test.go b/models/user/user_test.go index 8c554be86c..4f238967c1 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -5,7 +5,6 @@ package user_test import ( - "context" "crypto/rand" "encoding/hex" "fmt" @@ -346,7 +345,7 @@ func TestCreateUserCustomTimestamps(t *testing.T) { err := user_model.CreateUser(db.DefaultContext, user) require.NoError(t, err) - fetched, err := user_model.GetUserByID(context.Background(), user.ID) + fetched, err := user_model.GetUserByID(t.Context(), user.ID) require.NoError(t, err) assert.Equal(t, creationTimestamp, fetched.CreatedUnix) assert.Equal(t, creationTimestamp, fetched.UpdatedUnix) @@ -373,7 +372,7 @@ func TestCreateUserWithoutCustomTimestamps(t *testing.T) { timestampEnd := time.Now().Unix() - fetched, err := user_model.GetUserByID(context.Background(), user.ID) + fetched, err := user_model.GetUserByID(t.Context(), user.ID) require.NoError(t, err) assert.LessOrEqual(t, timestampStart, fetched.CreatedUnix) diff --git a/models/webhook/webhook_test.go b/models/webhook/webhook_test.go index 848440b84a..6af9c26c1c 100644 --- a/models/webhook/webhook_test.go +++ b/models/webhook/webhook_test.go @@ -4,7 +4,6 @@ package webhook import ( - "context" "testing" "time" @@ -262,7 +261,7 @@ func TestCleanupHookTaskTable_PerWebhook_DeletesDelivered(t *testing.T) { require.NoError(t, err) unittest.AssertExistsAndLoadBean(t, hookTask) - require.NoError(t, CleanupHookTaskTable(context.Background(), PerWebhook, 168*time.Hour, 0)) + require.NoError(t, CleanupHookTaskTable(t.Context(), PerWebhook, 168*time.Hour, 0)) unittest.AssertNotExistsBean(t, hookTask) } @@ -278,7 +277,7 @@ func TestCleanupHookTaskTable_PerWebhook_LeavesUndelivered(t *testing.T) { require.NoError(t, err) unittest.AssertExistsAndLoadBean(t, hookTask) - require.NoError(t, CleanupHookTaskTable(context.Background(), PerWebhook, 168*time.Hour, 0)) + require.NoError(t, CleanupHookTaskTable(t.Context(), PerWebhook, 168*time.Hour, 0)) unittest.AssertExistsAndLoadBean(t, hookTask) } @@ -295,7 +294,7 @@ func TestCleanupHookTaskTable_PerWebhook_LeavesMostRecentTask(t *testing.T) { require.NoError(t, err) unittest.AssertExistsAndLoadBean(t, hookTask) - require.NoError(t, CleanupHookTaskTable(context.Background(), PerWebhook, 168*time.Hour, 1)) + require.NoError(t, CleanupHookTaskTable(t.Context(), PerWebhook, 168*time.Hour, 1)) unittest.AssertExistsAndLoadBean(t, hookTask) } @@ -312,7 +311,7 @@ func TestCleanupHookTaskTable_OlderThan_DeletesDelivered(t *testing.T) { require.NoError(t, err) unittest.AssertExistsAndLoadBean(t, hookTask) - require.NoError(t, CleanupHookTaskTable(context.Background(), OlderThan, 168*time.Hour, 0)) + require.NoError(t, CleanupHookTaskTable(t.Context(), OlderThan, 168*time.Hour, 0)) unittest.AssertNotExistsBean(t, hookTask) } @@ -328,7 +327,7 @@ func TestCleanupHookTaskTable_OlderThan_LeavesUndelivered(t *testing.T) { require.NoError(t, err) unittest.AssertExistsAndLoadBean(t, hookTask) - require.NoError(t, CleanupHookTaskTable(context.Background(), OlderThan, 168*time.Hour, 0)) + require.NoError(t, CleanupHookTaskTable(t.Context(), OlderThan, 168*time.Hour, 0)) unittest.AssertExistsAndLoadBean(t, hookTask) } @@ -345,6 +344,6 @@ func TestCleanupHookTaskTable_OlderThan_LeavesTaskEarlierThanAgeToDelete(t *test require.NoError(t, err) unittest.AssertExistsAndLoadBean(t, hookTask) - require.NoError(t, CleanupHookTaskTable(context.Background(), OlderThan, 168*time.Hour, 0)) + require.NoError(t, CleanupHookTaskTable(t.Context(), OlderThan, 168*time.Hour, 0)) unittest.AssertExistsAndLoadBean(t, hookTask) } diff --git a/modules/cache/context_test.go b/modules/cache/context_test.go index 072c39440f..4f0f06f535 100644 --- a/modules/cache/context_test.go +++ b/modules/cache/context_test.go @@ -4,7 +4,6 @@ package cache import ( - "context" "testing" "time" @@ -13,7 +12,7 @@ import ( ) func TestWithCacheContext(t *testing.T) { - ctx := WithCacheContext(context.Background()) + ctx := WithCacheContext(t.Context()) v := GetContextData(ctx, "empty_field", "my_config1") assert.Nil(t, v) @@ -53,7 +52,7 @@ func TestWithCacheContext(t *testing.T) { } func TestWithNoCacheContext(t *testing.T) { - ctx := context.Background() + ctx := t.Context() const field = "system_setting" diff --git a/modules/git/blame.go b/modules/git/blame.go index 69e1b08f93..d62a8ca0a2 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -139,7 +139,7 @@ func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath cmd := NewCommandContextNoGlobals(ctx, "blame", "--porcelain") if ignoreRevsFile != nil { // Possible improvement: use --ignore-revs-file /dev/stdin on unix - // There is no equivalent on Windows. May be implemented if Gitea uses an external git backend. + // This was not done in Gitea because it would not have been compatible with Windows. cmd.AddOptionValues("--ignore-revs-file", *ignoreRevsFile) } cmd.AddDynamicArguments(commit.ID.String()). diff --git a/modules/git/blame_sha256_test.go b/modules/git/blame_sha256_test.go index eeeeb9fdb5..c37f40775b 100644 --- a/modules/git/blame_sha256_test.go +++ b/modules/git/blame_sha256_test.go @@ -14,7 +14,7 @@ import ( func TestReadingBlameOutputSha256(t *testing.T) { skipIfSHA256NotSupported(t) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() t.Run("Without .git-blame-ignore-revs", func(t *testing.T) { diff --git a/modules/git/blame_test.go b/modules/git/blame_test.go index 65320c78c0..b8fc59dd9e 100644 --- a/modules/git/blame_test.go +++ b/modules/git/blame_test.go @@ -12,7 +12,7 @@ import ( ) func TestReadingBlameOutput(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() t.Run("Without .git-blame-ignore-revs", func(t *testing.T) { diff --git a/modules/git/command.go b/modules/git/command.go index 605816b7a2..72640a2a94 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -12,7 +12,6 @@ import ( "io" "os" "os/exec" - "runtime" "runtime/trace" "strings" "time" @@ -359,17 +358,6 @@ func (c *Command) Run(opts *RunOpts) error { log.Debug("slow git.Command.Run: %s (%s)", c, elapsed) } - // We need to check if the context is canceled by the program on Windows. - // This is because Windows does not have signal checking when terminating the process. - // It always returns exit code 1, unlike Linux, which has many exit codes for signals. - if runtime.GOOS == "windows" && - err != nil && - err.Error() == "" && - cmd.ProcessState.ExitCode() == 1 && - ctx.Err() == context.Canceled { - return ctx.Err() - } - if err != nil && ctx.Err() != context.DeadlineExceeded { return err } diff --git a/modules/git/command_test.go b/modules/git/command_test.go index d3b8338d02..ace43598fc 100644 --- a/modules/git/command_test.go +++ b/modules/git/command_test.go @@ -4,7 +4,6 @@ package git import ( - "context" "testing" "github.com/stretchr/testify/assert" @@ -12,13 +11,13 @@ import ( ) func TestRunWithContextStd(t *testing.T) { - cmd := NewCommand(context.Background(), "--version") + cmd := NewCommand(t.Context(), "--version") stdout, stderr, err := cmd.RunStdString(&RunOpts{}) require.NoError(t, err) assert.Empty(t, stderr) assert.Contains(t, stdout, "git version") - cmd = NewCommand(context.Background(), "--no-such-arg") + cmd = NewCommand(t.Context(), "--no-such-arg") stdout, stderr, err = cmd.RunStdString(&RunOpts{}) if assert.Error(t, err) { assert.Equal(t, stderr, err.Stderr()) @@ -27,16 +26,16 @@ func TestRunWithContextStd(t *testing.T) { assert.Empty(t, stdout) } - cmd = NewCommand(context.Background()) + cmd = NewCommand(t.Context()) cmd.AddDynamicArguments("-test") require.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand) - cmd = NewCommand(context.Background()) + cmd = NewCommand(t.Context()) cmd.AddDynamicArguments("--test") require.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand) subCmd := "version" - cmd = NewCommand(context.Background()).AddDynamicArguments(subCmd) // for test purpose only, the sub-command should never be dynamic for production + cmd = NewCommand(t.Context()).AddDynamicArguments(subCmd) // for test purpose only, the sub-command should never be dynamic for production stdout, stderr, err = cmd.RunStdString(&RunOpts{}) require.NoError(t, err) assert.Empty(t, stderr) @@ -55,15 +54,15 @@ func TestGitArgument(t *testing.T) { } func TestCommandString(t *testing.T) { - cmd := NewCommandContextNoGlobals(context.Background(), "a", "-m msg", "it's a test", `say "hello"`) + cmd := NewCommandContextNoGlobals(t.Context(), "a", "-m msg", "it's a test", `say "hello"`) assert.EqualValues(t, cmd.prog+` a "-m msg" "it's a test" "say \"hello\""`, cmd.String()) - cmd = NewCommandContextNoGlobals(context.Background(), "url: https://a:b@c/") + cmd = NewCommandContextNoGlobals(t.Context(), "url: https://a:b@c/") assert.EqualValues(t, cmd.prog+` "url: https://sanitized-credential@c/"`, cmd.toString(true)) } func TestGrepOnlyFunction(t *testing.T) { - cmd := NewCommand(context.Background(), "anything-but-grep") + cmd := NewCommand(t.Context(), "anything-but-grep") assert.Panics(t, func() { cmd.AddGitGrepExpression("whatever") }) diff --git a/modules/git/commit_info_test.go b/modules/git/commit_info_test.go index dbe9ab547d..898ac6b13a 100644 --- a/modules/git/commit_info_test.go +++ b/modules/git/commit_info_test.go @@ -4,7 +4,6 @@ package git import ( - "context" "path/filepath" "testing" "time" @@ -84,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(context.TODO(), commit, testCase.Path) + commitsInfo, treeCommit, err := entries.GetCommitsInfo(t.Context(), commit, testCase.Path) require.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() @@ -161,7 +160,7 @@ func BenchmarkEntries_GetCommitsInfo(b *testing.B) { b.ResetTimer() b.Run(benchmark.name, func(b *testing.B) { for i := 0; i < b.N; i++ { - _, _, err := entries.GetCommitsInfo(context.Background(), commit, "") + _, _, err := entries.GetCommitsInfo(b.Context(), commit, "") if err != nil { b.Fatal(err) } diff --git a/modules/git/git.go b/modules/git/git.go index f1174e67b9..576609068a 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -59,15 +59,7 @@ func loadGitVersion() error { return fmt.Errorf("invalid git version output: %s", stdout) } - var versionString string - - // Handle special case on Windows. - i := strings.Index(fields[2], "windows") - if i >= 1 { - versionString = fields[2][:i-1] - } else { - versionString = fields[2] - } + versionString := fields[2] var err error gitVersion, err = version.NewVersion(versionString) @@ -280,24 +272,11 @@ func syncGitConfig() (err error) { // Thus the owner uid/gid for files on these filesystems will be marked as root. // As Gitea now always use its internal git config file, and access to the git repositories is managed through Gitea, // it is now safe to set "safe.directory=*" for internal usage only. - // Please note: the wildcard "*" is only supported by Git 2.30.4/2.31.3/2.32.2/2.33.3/2.34.3/2.35.3/2.36 and later - // Although only supported by Git 2.30.4/2.31.3/2.32.2/2.33.3/2.34.3/2.35.3/2.36 and later - this setting is tolerated by earlier versions + // Please note: the wildcard "*" is only supported by Git 2.30.4/2.31.3/2.32.2/2.33.3/2.34.3/2.35.3/2.36 and later, + // but is tolerated by earlier versions if err := configAddNonExist("safe.directory", "*"); err != nil { return err } - if runtime.GOOS == "windows" { - if err := configSet("core.longpaths", "true"); err != nil { - return err - } - if setting.Git.DisableCoreProtectNTFS { - err = configSet("core.protectNTFS", "false") - } else { - err = configUnsetAll("core.protectNTFS", "false") - } - if err != nil { - return err - } - } // By default partial clones are disabled, enable them from git v2.22 if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil { diff --git a/modules/git/grep_test.go b/modules/git/grep_test.go index c40b33664a..534468e268 100644 --- a/modules/git/grep_test.go +++ b/modules/git/grep_test.go @@ -5,7 +5,6 @@ package git import ( "bytes" - "context" "os" "path" "path/filepath" @@ -20,7 +19,7 @@ func TestGrepSearch(t *testing.T) { require.NoError(t, err) defer repo.Close() - res, err := GrepSearch(context.Background(), repo, "public", GrepOptions{}) + res, err := GrepSearch(t.Context(), repo, "public", GrepOptions{}) require.NoError(t, err) assert.Equal(t, []*GrepResult{ { @@ -43,7 +42,7 @@ func TestGrepSearch(t *testing.T) { }, }, res) - res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{MaxResultLimit: 1, ContextLineNumber: 2}) + res, err = GrepSearch(t.Context(), repo, "void", GrepOptions{MaxResultLimit: 1, ContextLineNumber: 2}) require.NoError(t, err) assert.Equal(t, []*GrepResult{ { @@ -60,7 +59,7 @@ func TestGrepSearch(t *testing.T) { }, }, res) - res, err = GrepSearch(context.Background(), repo, "world", GrepOptions{MatchesPerFile: 1}) + res, err = GrepSearch(t.Context(), repo, "world", GrepOptions{MatchesPerFile: 1}) require.NoError(t, err) assert.Equal(t, []*GrepResult{ { @@ -89,7 +88,7 @@ func TestGrepSearch(t *testing.T) { }, }, res) - res, err = GrepSearch(context.Background(), repo, "world", GrepOptions{ + res, err = GrepSearch(t.Context(), repo, "world", GrepOptions{ MatchesPerFile: 1, Filename: "java-hello/", }) @@ -103,11 +102,11 @@ func TestGrepSearch(t *testing.T) { }, }, res) - res, err = GrepSearch(context.Background(), repo, "no-such-content", GrepOptions{}) + res, err = GrepSearch(t.Context(), repo, "no-such-content", GrepOptions{}) require.NoError(t, err) assert.Empty(t, res) - res, err = GrepSearch(context.Background(), &Repository{Path: "no-such-git-repo"}, "no-such-content", GrepOptions{}) + res, err = GrepSearch(t.Context(), &Repository{Path: "no-such-git-repo"}, "no-such-content", GrepOptions{}) require.Error(t, err) assert.Empty(t, res) } @@ -131,7 +130,7 @@ func TestGrepDashesAreFine(t *testing.T) { err = CommitChanges(tmpDir, CommitChangesOptions{Message: "Dashes are cool sometimes"}) require.NoError(t, err) - res, err := GrepSearch(context.Background(), gitRepo, "--", GrepOptions{}) + res, err := GrepSearch(t.Context(), gitRepo, "--", GrepOptions{}) require.NoError(t, err) assert.Len(t, res, 1) assert.Equal(t, "with-dashes", res[0].Filename) @@ -156,7 +155,7 @@ func TestGrepNoBinary(t *testing.T) { err = CommitChanges(tmpDir, CommitChangesOptions{Message: "Binary and text files"}) require.NoError(t, err) - res, err := GrepSearch(context.Background(), gitRepo, "BINARY", GrepOptions{}) + res, err := GrepSearch(t.Context(), gitRepo, "BINARY", GrepOptions{}) require.NoError(t, err) assert.Len(t, res, 1) assert.Equal(t, "TEXT", res[0].Filename) @@ -180,7 +179,7 @@ func TestGrepLongFiles(t *testing.T) { err = CommitChanges(tmpDir, CommitChangesOptions{Message: "Long file"}) require.NoError(t, err) - res, err := GrepSearch(context.Background(), gitRepo, "a", GrepOptions{}) + res, err := GrepSearch(t.Context(), gitRepo, "a", GrepOptions{}) require.NoError(t, err) assert.Len(t, res, 1) assert.Len(t, res[0].LineCodes[0], 65*1024) @@ -210,7 +209,7 @@ func TestGrepRefs(t *testing.T) { err = CommitChanges(tmpDir, CommitChangesOptions{Message: "add BCD"}) require.NoError(t, err) - res, err := GrepSearch(context.Background(), gitRepo, "a", GrepOptions{RefName: "v1"}) + res, err := GrepSearch(t.Context(), gitRepo, "a", GrepOptions{RefName: "v1"}) require.NoError(t, err) assert.Len(t, res, 1) assert.Equal(t, "A", res[0].LineCodes[0]) @@ -236,12 +235,12 @@ func TestGrepCanHazRegexOnDemand(t *testing.T) { require.NoError(t, err) // should find nothing by default... - res, err := GrepSearch(context.Background(), gitRepo, "\\bmatch\\b", GrepOptions{}) + res, err := GrepSearch(t.Context(), gitRepo, "\\bmatch\\b", GrepOptions{}) require.NoError(t, err) assert.Empty(t, res) // ... unless configured explicitly - res, err = GrepSearch(context.Background(), gitRepo, "\\bmatch\\b", GrepOptions{Mode: RegExpGrepMode}) + res, err = GrepSearch(t.Context(), gitRepo, "\\bmatch\\b", GrepOptions{Mode: RegExpGrepMode}) require.NoError(t, err) assert.Len(t, res, 1) assert.Equal(t, "matching", res[0].Filename) diff --git a/modules/git/notes_test.go b/modules/git/notes_test.go index cb9f39b93a..69ed3b8a6a 100644 --- a/modules/git/notes_test.go +++ b/modules/git/notes_test.go @@ -4,8 +4,6 @@ package git_test import ( - "context" - "os" "path/filepath" "testing" @@ -32,7 +30,7 @@ func TestGetNotes(t *testing.T) { defer bareRepo1.Close() note := git.Note{} - err = git.GetNote(context.Background(), bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653", ¬e) + err = git.GetNote(t.Context(), bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653", ¬e) require.NoError(t, err) assert.Equal(t, []byte("Note contents\n"), note.Message) assert.Equal(t, "Vladimir Panteleev", note.Commit.Author.Name) @@ -45,10 +43,10 @@ func TestGetNestedNotes(t *testing.T) { defer repo.Close() note := git.Note{} - err = git.GetNote(context.Background(), repo, "3e668dbfac39cbc80a9ff9c61eb565d944453ba4", ¬e) + err = git.GetNote(t.Context(), repo, "3e668dbfac39cbc80a9ff9c61eb565d944453ba4", ¬e) require.NoError(t, err) assert.Equal(t, []byte("Note 2"), note.Message) - err = git.GetNote(context.Background(), repo, "ba0a96fa63532d6c5087ecef070b0250ed72fa47", ¬e) + err = git.GetNote(t.Context(), repo, "ba0a96fa63532d6c5087ecef070b0250ed72fa47", ¬e) require.NoError(t, err) assert.Equal(t, []byte("Note 1"), note.Message) } @@ -60,7 +58,7 @@ func TestGetNonExistentNotes(t *testing.T) { defer bareRepo1.Close() note := git.Note{} - err = git.GetNote(context.Background(), bareRepo1, "non_existent_sha", ¬e) + err = git.GetNote(t.Context(), bareRepo1, "non_existent_sha", ¬e) require.Error(t, err) assert.IsType(t, git.ErrNotExist{}, err) } @@ -68,19 +66,17 @@ func TestGetNonExistentNotes(t *testing.T) { func TestSetNote(t *testing.T) { bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") - tempDir, err := os.MkdirTemp("", "") - require.NoError(t, err) - defer os.RemoveAll(tempDir) + tempDir := t.TempDir() require.NoError(t, unittest.CopyDir(bareRepo1Path, filepath.Join(tempDir, "repo1"))) bareRepo1, err := openRepositoryWithDefaultContext(filepath.Join(tempDir, "repo1")) require.NoError(t, err) defer bareRepo1.Close() - require.NoError(t, git.SetNote(context.Background(), bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653", "This is a new note", "Test", "test@test.com")) + require.NoError(t, git.SetNote(t.Context(), bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653", "This is a new note", "Test", "test@test.com")) note := git.Note{} - err = git.GetNote(context.Background(), bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653", ¬e) + err = git.GetNote(t.Context(), bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653", ¬e) require.NoError(t, err) assert.Equal(t, []byte("This is a new note\n"), note.Message) assert.Equal(t, "Test", note.Commit.Author.Name) @@ -97,10 +93,10 @@ func TestRemoveNote(t *testing.T) { require.NoError(t, err) defer bareRepo1.Close() - require.NoError(t, git.RemoveNote(context.Background(), bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653")) + require.NoError(t, git.RemoveNote(t.Context(), bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653")) note := git.Note{} - err = git.GetNote(context.Background(), bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653", ¬e) + err = git.GetNote(t.Context(), bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653", ¬e) require.Error(t, err) assert.IsType(t, git.ErrNotExist{}, err) } diff --git a/modules/git/repo_base_test.go b/modules/git/repo_base_test.go index 323b28f476..c9ac6a8559 100644 --- a/modules/git/repo_base_test.go +++ b/modules/git/repo_base_test.go @@ -14,7 +14,7 @@ import ( // This unit test relies on the implementation detail of CatFileBatch. func TestCatFileBatch(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() repo, err := OpenRepository(ctx, "./tests/repos/repo1_bare") @@ -89,7 +89,7 @@ func TestCatFileBatch(t *testing.T) { // This unit test relies on the implementation detail of CatFileBatchCheck. func TestCatFileBatchCheck(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() repo, err := OpenRepository(ctx, "./tests/repos/repo1_bare") diff --git a/modules/git/repo_test.go b/modules/git/repo_test.go index 8fb19a5043..c4ef9dbe96 100644 --- a/modules/git/repo_test.go +++ b/modules/git/repo_test.go @@ -4,7 +4,6 @@ package git import ( - "context" "path/filepath" "testing" @@ -34,21 +33,21 @@ func TestRepoIsEmpty(t *testing.T) { func TestRepoGetDivergingCommits(t *testing.T) { bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") - do, err := GetDivergingCommits(context.Background(), bareRepo1Path, "master", "branch2") + do, err := GetDivergingCommits(t.Context(), bareRepo1Path, "master", "branch2") require.NoError(t, err) assert.Equal(t, DivergeObject{ Ahead: 1, Behind: 5, }, do) - do, err = GetDivergingCommits(context.Background(), bareRepo1Path, "master", "master") + do, err = GetDivergingCommits(t.Context(), bareRepo1Path, "master", "master") require.NoError(t, err) assert.Equal(t, DivergeObject{ Ahead: 0, Behind: 0, }, do) - do, err = GetDivergingCommits(context.Background(), bareRepo1Path, "master", "test") + do, err = GetDivergingCommits(t.Context(), bareRepo1Path, "master", "test") require.NoError(t, err) assert.Equal(t, DivergeObject{ Ahead: 0, diff --git a/modules/graceful/manager_unix.go b/modules/graceful/manager_unix.go index 931b0f1b62..8147743f79 100644 --- a/modules/graceful/manager_unix.go +++ b/modules/graceful/manager_unix.go @@ -1,8 +1,6 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -//go:build !windows - package graceful import ( diff --git a/modules/graceful/net_unix.go b/modules/graceful/net_unix.go index 796e00507c..320904db17 100644 --- a/modules/graceful/net_unix.go +++ b/modules/graceful/net_unix.go @@ -3,14 +3,13 @@ // This code is heavily inspired by the archived gofacebook/gracenet/net.go handler -//go:build !windows - package graceful import ( "fmt" "net" "os" + "path/filepath" "strconv" "strings" "sync" @@ -237,9 +236,11 @@ func GetListenerUnix(network string, address *net.UnixAddr) (*net.UnixListener, return nil, err } - fileMode := os.FileMode(setting.UnixSocketPermission) - if err = os.Chmod(address.Name, fileMode); err != nil { - return nil, fmt.Errorf("Failed to set permission of unix socket to %s: %w", fileMode.String(), err) + if filepath.IsAbs(address.Name) { + fileMode := os.FileMode(setting.UnixSocketPermission) + if err = os.Chmod(address.Name, fileMode); err != nil { + return nil, fmt.Errorf("Failed to set permission of unix socket to %s: %w", fileMode.String(), err) + } } activeListeners = append(activeListeners, l) diff --git a/modules/graceful/net_unix_linux_test.go b/modules/graceful/net_unix_linux_test.go new file mode 100644 index 0000000000..144e5a4881 --- /dev/null +++ b/modules/graceful/net_unix_linux_test.go @@ -0,0 +1,15 @@ +// Copyright 2025 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-or-later + +package graceful + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAbstractUnixSocket(t *testing.T) { + _, err := DefaultGetListener("unix", "@abc") + require.NoError(t, err) +} diff --git a/modules/graceful/restart_unix.go b/modules/graceful/restart_unix.go index 98d5c5cc20..a0f3147ec6 100644 --- a/modules/graceful/restart_unix.go +++ b/modules/graceful/restart_unix.go @@ -3,8 +3,6 @@ // This code is heavily inspired by the archived gofacebook/gracenet/net.go handler -//go:build !windows - package graceful import ( diff --git a/modules/indexer/code/indexer_test.go b/modules/indexer/code/indexer_test.go index 9ef16f3412..559b85626f 100644 --- a/modules/indexer/code/indexer_test.go +++ b/modules/indexer/code/indexer_test.go @@ -4,7 +4,6 @@ package code import ( - "context" "os" "testing" @@ -94,7 +93,7 @@ func testIndexer(name string, t *testing.T, indexer internal.Indexer) { for _, kw := range keywords { t.Run(kw.Keyword, func(t *testing.T) { - total, res, langs, err := indexer.Search(context.TODO(), &internal.SearchOptions{ + total, res, langs, err := indexer.Search(t.Context(), &internal.SearchOptions{ RepoIDs: kw.RepoIDs, Keyword: kw.Keyword, Paginator: &db.ListOptions{ @@ -117,7 +116,7 @@ func testIndexer(name string, t *testing.T, indexer internal.Indexer) { }) } - require.NoError(t, indexer.Delete(context.Background(), repoID)) + require.NoError(t, indexer.Delete(t.Context(), repoID)) }) } @@ -127,7 +126,7 @@ func TestBleveIndexAndSearch(t *testing.T) { dir := t.TempDir() idx := bleve.NewIndexer(dir) - _, err := idx.Init(context.Background()) + _, err := idx.Init(t.Context()) if err != nil { if idx != nil { idx.Close() @@ -149,7 +148,7 @@ func TestESIndexAndSearch(t *testing.T) { } indexer := elasticsearch.NewIndexer(u, "gitea_codes") - if _, err := indexer.Init(context.Background()); err != nil { + if _, err := indexer.Init(t.Context()); err != nil { if indexer != nil { indexer.Close() } diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go index b96fecc6bc..9f80d70696 100644 --- a/modules/indexer/issues/indexer_test.go +++ b/modules/indexer/issues/indexer_test.go @@ -4,7 +4,6 @@ package issues import ( - "context" "testing" "code.gitea.io/gitea/models/db" @@ -82,7 +81,7 @@ func searchIssueWithKeyword(t *testing.T) { } for _, test := range tests { - issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) @@ -127,7 +126,7 @@ func searchIssueInRepo(t *testing.T) { } for _, test := range tests { - issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) @@ -198,7 +197,7 @@ func searchIssueByID(t *testing.T) { } for _, test := range tests { - issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) } @@ -223,7 +222,7 @@ func searchIssueIsPull(t *testing.T) { }, } for _, test := range tests { - issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) @@ -249,7 +248,7 @@ func searchIssueIsClosed(t *testing.T) { }, } for _, test := range tests { - issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) } @@ -274,7 +273,7 @@ func searchIssueByMilestoneID(t *testing.T) { }, } for _, test := range tests { - issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) @@ -306,7 +305,7 @@ func searchIssueByLabelID(t *testing.T) { }, } for _, test := range tests { - issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) @@ -326,7 +325,7 @@ func searchIssueByTime(t *testing.T) { }, } for _, test := range tests { - issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) @@ -346,7 +345,7 @@ func searchIssueWithOrder(t *testing.T) { }, } for _, test := range tests { - issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) @@ -378,7 +377,7 @@ func searchIssueInProject(t *testing.T) { }, } for _, test := range tests { - issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) @@ -402,7 +401,7 @@ func searchIssueWithPaginator(t *testing.T) { }, } for _, test := range tests { - issueIDs, total, err := SearchIssues(context.TODO(), &test.opts) + issueIDs, total, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) assert.Equal(t, test.expectedIDs, issueIDs) diff --git a/modules/indexer/issues/internal/tests/tests.go b/modules/indexer/issues/internal/tests/tests.go index 0763cd1297..80ff34713e 100644 --- a/modules/indexer/issues/internal/tests/tests.go +++ b/modules/indexer/issues/internal/tests/tests.go @@ -24,10 +24,10 @@ import ( ) func TestIndexer(t *testing.T, indexer internal.Indexer) { - _, err := indexer.Init(context.Background()) + _, err := indexer.Init(t.Context()) require.NoError(t, err) - require.NoError(t, indexer.Ping(context.Background())) + require.NoError(t, indexer.Ping(t.Context())) var ( ids []int64 @@ -39,32 +39,32 @@ func TestIndexer(t *testing.T, indexer internal.Indexer) { ids = append(ids, v.ID) data[v.ID] = v } - require.NoError(t, indexer.Index(context.Background(), d...)) + require.NoError(t, indexer.Index(t.Context(), d...)) require.NoError(t, waitData(indexer, int64(len(data)))) } defer func() { - require.NoError(t, indexer.Delete(context.Background(), ids...)) + require.NoError(t, indexer.Delete(t.Context(), ids...)) }() for _, c := range cases { t.Run(c.Name, func(t *testing.T) { if len(c.ExtraData) > 0 { - require.NoError(t, indexer.Index(context.Background(), c.ExtraData...)) + require.NoError(t, indexer.Index(t.Context(), c.ExtraData...)) for _, v := range c.ExtraData { data[v.ID] = v } require.NoError(t, waitData(indexer, int64(len(data)))) defer func() { for _, v := range c.ExtraData { - require.NoError(t, indexer.Delete(context.Background(), v.ID)) + require.NoError(t, indexer.Delete(t.Context(), v.ID)) delete(data, v.ID) } require.NoError(t, waitData(indexer, int64(len(data)))) }() } - result, err := indexer.Search(context.Background(), c.SearchOptions) + result, err := indexer.Search(t.Context(), c.SearchOptions) require.NoError(t, err) if c.Expected != nil { @@ -80,7 +80,7 @@ func TestIndexer(t *testing.T, indexer internal.Indexer) { // test counting c.SearchOptions.Paginator = &db.ListOptions{PageSize: 0} - countResult, err := indexer.Search(context.Background(), c.SearchOptions) + countResult, err := indexer.Search(t.Context(), c.SearchOptions) require.NoError(t, err) assert.Empty(t, countResult.Hits) assert.Equal(t, result.Total, countResult.Total) diff --git a/modules/indexer/stats/indexer_test.go b/modules/indexer/stats/indexer_test.go index b7e66f937c..781bb72eaa 100644 --- a/modules/indexer/stats/indexer_test.go +++ b/modules/indexer/stats/indexer_test.go @@ -4,7 +4,6 @@ package stats import ( - "context" "testing" "time" @@ -42,7 +41,7 @@ func TestRepoStatsIndex(t *testing.T) { err = UpdateRepoIndexer(repo) require.NoError(t, err) - require.NoError(t, queue.GetManager().FlushAll(context.Background(), 5*time.Second)) + require.NoError(t, queue.GetManager().FlushAll(t.Context(), 5*time.Second)) status, err := repo_model.GetIndexerStatus(db.DefaultContext, repo, repo_model.RepoIndexerTypeStats) require.NoError(t, err) diff --git a/modules/lfs/http_client_test.go b/modules/lfs/http_client_test.go index d78224a806..e80e4847f8 100644 --- a/modules/lfs/http_client_test.go +++ b/modules/lfs/http_client_test.go @@ -249,7 +249,7 @@ func TestHTTPClientDownload(t *testing.T) { }, } - err := client.Download(context.Background(), []Pointer{p}, func(p Pointer, content io.ReadCloser, objectError error) error { + err := client.Download(t.Context(), []Pointer{p}, func(p Pointer, content io.ReadCloser, objectError error) error { if objectError != nil { return objectError } @@ -349,7 +349,7 @@ func TestHTTPClientUpload(t *testing.T) { }, } - err := client.Upload(context.Background(), []Pointer{p}, func(p Pointer, objectError error) (io.ReadCloser, error) { + err := client.Upload(t.Context(), []Pointer{p}, func(p Pointer, objectError error) (io.ReadCloser, error) { return io.NopCloser(new(bytes.Buffer)), objectError }) if c.expectedError != "" { diff --git a/modules/lfs/transferadapter_test.go b/modules/lfs/transferadapter_test.go index 0d663d71f6..a90ee5c6c0 100644 --- a/modules/lfs/transferadapter_test.go +++ b/modules/lfs/transferadapter_test.go @@ -5,7 +5,6 @@ package lfs import ( "bytes" - "context" "io" "net/http" "strings" @@ -95,7 +94,7 @@ func TestBasicTransferAdapter(t *testing.T) { } for n, c := range cases { - _, err := a.Download(context.Background(), c.link) + _, err := a.Download(t.Context(), c.link) if len(c.expectederror) > 0 { assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) } else { @@ -128,7 +127,7 @@ func TestBasicTransferAdapter(t *testing.T) { } for n, c := range cases { - err := a.Upload(context.Background(), c.link, p, bytes.NewBufferString("dummy")) + err := a.Upload(t.Context(), c.link, p, bytes.NewBufferString("dummy")) if len(c.expectederror) > 0 { assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) } else { @@ -161,7 +160,7 @@ func TestBasicTransferAdapter(t *testing.T) { } for n, c := range cases { - err := a.Verify(context.Background(), c.link, p) + err := a.Verify(t.Context(), c.link, p) if len(c.expectederror) > 0 { assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) } else { diff --git a/modules/log/color_console_other.go b/modules/log/color_console_other.go index c08b38c674..6573d093a5 100644 --- a/modules/log/color_console_other.go +++ b/modules/log/color_console_other.go @@ -1,8 +1,6 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -//go:build !windows - package log import ( diff --git a/modules/log/color_console_windows.go b/modules/log/color_console_windows.go deleted file mode 100644 index 3f59e934da..0000000000 --- a/modules/log/color_console_windows.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package log - -import ( - "os" - - "github.com/mattn/go-isatty" - "golang.org/x/sys/windows" -) - -func enableVTMode(console windows.Handle) bool { - mode := uint32(0) - err := windows.GetConsoleMode(console, &mode) - if err != nil { - return false - } - - // EnableVirtualTerminalProcessing is the console mode to allow ANSI code - // interpretation on the console. See: - // https://docs.microsoft.com/en-us/windows/console/setconsolemode - // It only works on Windows 10. Earlier terminals will fail with an err which we will - // handle to say don't color - mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING - err = windows.SetConsoleMode(console, mode) - return err == nil -} - -func init() { - if isatty.IsTerminal(os.Stdout.Fd()) { - CanColorStdout = enableVTMode(windows.Stdout) - } else { - CanColorStdout = isatty.IsCygwinTerminal(os.Stderr.Fd()) - } - - if isatty.IsTerminal(os.Stderr.Fd()) { - CanColorStderr = enableVTMode(windows.Stderr) - } else { - CanColorStderr = isatty.IsCygwinTerminal(os.Stderr.Fd()) - } -} diff --git a/modules/log/event_writer_buffer_test.go b/modules/log/event_writer_buffer_test.go index 5c0343b8a8..58c6be1399 100644 --- a/modules/log/event_writer_buffer_test.go +++ b/modules/log/event_writer_buffer_test.go @@ -4,7 +4,6 @@ package log_test import ( - "context" "testing" "code.gitea.io/gitea/modules/log" @@ -23,7 +22,7 @@ func TestBufferLogger(t *testing.T) { Expression: expected, }) - logger := log.NewLoggerWithWriters(context.Background(), "test", bufferWriter) + logger := log.NewLoggerWithWriters(t.Context(), "test", bufferWriter) logger.SendLogEvent(&log.Event{ Level: log.INFO, diff --git a/modules/log/event_writer_conn_test.go b/modules/log/event_writer_conn_test.go index de8694f2c5..0cf447149a 100644 --- a/modules/log/event_writer_conn_test.go +++ b/modules/log/event_writer_conn_test.go @@ -4,7 +4,6 @@ package log import ( - "context" "fmt" "io" "net" @@ -41,7 +40,7 @@ func TestConnLogger(t *testing.T) { level := INFO flags := LstdFlags | LUTC | Lfuncname - logger := NewLoggerWithWriters(context.Background(), "test", NewEventWriterConn("test-conn", WriterMode{ + logger := NewLoggerWithWriters(t.Context(), "test", NewEventWriterConn("test-conn", WriterMode{ Level: level, Prefix: prefix, Flags: FlagsFromBits(flags), diff --git a/modules/log/groutinelabel_test.go b/modules/log/groutinelabel_test.go index 34e99653d6..df8c1e9259 100644 --- a/modules/log/groutinelabel_test.go +++ b/modules/log/groutinelabel_test.go @@ -12,7 +12,7 @@ import ( ) func Test_getGoroutineLabels(t *testing.T) { - pprof.Do(context.Background(), pprof.Labels(), func(ctx context.Context) { + pprof.Do(t.Context(), pprof.Labels(), func(ctx context.Context) { currentLabels := getGoroutineLabels() pprof.ForLabels(ctx, func(key, value string) bool { assert.EqualValues(t, value, currentLabels[key]) diff --git a/modules/log/logger_impl.go b/modules/log/logger_impl.go index d38c6516ed..77e7edf6aa 100644 --- a/modules/log/logger_impl.go +++ b/modules/log/logger_impl.go @@ -191,7 +191,7 @@ func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) { if ok { fn := runtime.FuncForPC(pc) if fn != nil { - event.Caller = fn.Name() + "()" + event.Caller = strings.TrimSuffix(fn.Name(), "[...]") + "()" } } event.Filename, event.Line = strings.TrimPrefix(filename, projectPackagePrefix), line diff --git a/modules/log/logger_impl_test.go b/modules/log/logger_impl_test.go new file mode 100644 index 0000000000..59276a83f4 --- /dev/null +++ b/modules/log/logger_impl_test.go @@ -0,0 +1,27 @@ +// Copyright 2025 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-or-later + +package log + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func testGeneric[T any](log *LoggerImpl, t T) { + log.Log(0, INFO, "Just testing the logging of a generic function %v", t) +} + +func TestLog(t *testing.T) { + bufferWriter := NewEventWriterBuffer("test-buffer", WriterMode{ + Level: INFO, + }) + + logger := NewLoggerWithWriters(t.Context(), "test", bufferWriter) + + testGeneric(logger, "I'm the generic value!") + logger.Close() + + assert.Contains(t, bufferWriter.Buffer.String(), ".../logger_impl_test.go:13:testGeneric() [I] Just testing the logging of a generic function I'm the generic value!") +} diff --git a/modules/log/logger_test.go b/modules/log/logger_test.go index 0de14eb411..e04c9da8b0 100644 --- a/modules/log/logger_test.go +++ b/modules/log/logger_test.go @@ -4,7 +4,6 @@ package log import ( - "context" "sync" "testing" "time" @@ -53,7 +52,7 @@ func newDummyWriter(name string, level Level, delay time.Duration) *dummyWriter } func TestLogger(t *testing.T) { - logger := NewLoggerWithWriters(context.Background(), "test") + logger := NewLoggerWithWriters(t.Context(), "test") dump := logger.DumpWriters() assert.Empty(t, dump) @@ -88,7 +87,7 @@ func TestLogger(t *testing.T) { } func TestLoggerPause(t *testing.T) { - logger := NewLoggerWithWriters(context.Background(), "test") + logger := NewLoggerWithWriters(t.Context(), "test") w1 := newDummyWriter("dummy-1", DEBUG, 0) logger.AddWriters(w1) @@ -117,7 +116,7 @@ func (t testLogString) LogString() string { } func TestLoggerLogString(t *testing.T) { - logger := NewLoggerWithWriters(context.Background(), "test") + logger := NewLoggerWithWriters(t.Context(), "test") w1 := newDummyWriter("dummy-1", DEBUG, 0) w1.Mode.Colorize = true @@ -130,7 +129,7 @@ func TestLoggerLogString(t *testing.T) { } func TestLoggerExpressionFilter(t *testing.T) { - logger := NewLoggerWithWriters(context.Background(), "test") + logger := NewLoggerWithWriters(t.Context(), "test") w1 := newDummyWriter("dummy-1", DEBUG, 0) w1.Mode.Expression = "foo.*" diff --git a/modules/markup/external/external.go b/modules/markup/external/external.go index 122517ed11..59f0397515 100644 --- a/modules/markup/external/external.go +++ b/modules/markup/external/external.go @@ -9,7 +9,6 @@ import ( "io" "os" "os/exec" - "runtime" "strings" "code.gitea.io/gitea/modules/graceful" @@ -70,9 +69,6 @@ func (p *Renderer) DisplayInIFrame() bool { } func envMark(envName string) string { - if runtime.GOOS == "windows" { - return "%" + envName + "%" - } return "$" + envName } diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 7d954d2a16..905a10c58c 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -680,7 +680,7 @@ func TestRender_FilePreview(t *testing.T) { defer test.MockVariableValue(&setting.StaticRootPath, "../../")() defer test.MockVariableValue(&setting.Names, []string{"english"})() defer test.MockVariableValue(&setting.Langs, []string{"en-US"})() - translation.InitLocales(context.Background()) + translation.InitLocales(t.Context()) setting.AppURL = markup.TestAppURL markup.Init(&markup.ProcessorHelper{ diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index eb69cd4eec..bb59d72957 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -1190,7 +1190,7 @@ space
} for i, c := range cases { - result, err := markdown.RenderString(&markup.RenderContext{Ctx: context.Background(), Links: c.Links, IsWiki: c.IsWiki}, input) + result, err := markdown.RenderString(&markup.RenderContext{Ctx: t.Context(), Links: c.Links, IsWiki: c.IsWiki}, input) require.NoError(t, err, "Unexpected error in testcase: %v", i) assert.Equal(t, template.HTML(c.Expected), result, "Unexpected result in testcase %v", i) } diff --git a/modules/packages/nuget/metadata.go b/modules/packages/nuget/metadata.go index 1e98ddffde..dfb81baf4e 100644 --- a/modules/packages/nuget/metadata.go +++ b/modules/packages/nuget/metadata.go @@ -57,12 +57,21 @@ type Package struct { // Metadata represents the metadata of a Nuget package type Metadata struct { + Title string `json:"title,omitempty"` + Language string `json:"language,omitempty"` Description string `json:"description,omitempty"` ReleaseNotes string `json:"release_notes,omitempty"` Readme string `json:"readme,omitempty"` Authors string `json:"authors,omitempty"` + Owners string `json:"owners,omitempty"` + Copyright string `json:"copyright,omitempty"` ProjectURL string `json:"project_url,omitempty"` RepositoryURL string `json:"repository_url,omitempty"` + LicenseURL string `json:"license_url,omitempty"` + IconURL string `json:"icon_url,omitempty"` + MinClientVersion string `json:"min_client_version,omitempty"` + Tags string `json:"tags,omitempty"` + DevelopmentDependency bool `json:"development_dependency,omitempty"` RequireLicenseAcceptance bool `json:"require_license_acceptance"` Dependencies map[string][]Dependency `json:"dependencies,omitempty"` } @@ -77,13 +86,22 @@ type Dependency struct { type nuspecPackage struct { Metadata struct { ID string `xml:"id"` + Title string `xml:"title"` + Language string `xml:"language"` Version string `xml:"version"` Authors string `xml:"authors"` + Owners string `xml:"owners"` + Copyright string `xml:"copyright"` + DevelopmentDependency bool `xml:"developmentDependency"` RequireLicenseAcceptance bool `xml:"requireLicenseAcceptance"` ProjectURL string `xml:"projectUrl"` + LicenseURL string `xml:"licenseUrl"` + IconURL string `xml:"iconUrl"` Description string `xml:"description"` ReleaseNotes string `xml:"releaseNotes"` Readme string `xml:"readme"` + Tags string `xml:"tags"` + MinClientVersion string `xml:"minClientVersion,attr"` PackageTypes struct { PackageType []struct { Name string `xml:"name,attr"` @@ -167,11 +185,20 @@ func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) { } m := &Metadata{ + Title: p.Metadata.Title, + Language: p.Metadata.Language, Description: p.Metadata.Description, ReleaseNotes: p.Metadata.ReleaseNotes, Authors: p.Metadata.Authors, + Owners: p.Metadata.Owners, + Copyright: p.Metadata.Copyright, ProjectURL: p.Metadata.ProjectURL, RepositoryURL: p.Metadata.Repository.URL, + LicenseURL: p.Metadata.LicenseURL, + IconURL: p.Metadata.IconURL, + MinClientVersion: p.Metadata.MinClientVersion, + Tags: p.Metadata.Tags, + DevelopmentDependency: p.Metadata.DevelopmentDependency, RequireLicenseAcceptance: p.Metadata.RequireLicenseAcceptance, Dependencies: make(map[string][]Dependency), } diff --git a/modules/packages/nuget/metadata_test.go b/modules/packages/nuget/metadata_test.go index ecce052be4..8a34f1a5ae 100644 --- a/modules/packages/nuget/metadata_test.go +++ b/modules/packages/nuget/metadata_test.go @@ -13,14 +13,22 @@ import ( ) const ( - id = "System.Gitea" + id = "System.Forgejo" + title = "Package Title" + language = "Package Language" semver = "1.0.1" - authors = "Gitea Authors" - projectURL = "https://gitea.io" + authors = "Forgejo Authors" + owners = "Package Owners" + copyright = "Package Copyright" + projectURL = "https://forgejo.org" + licenseURL = "https://forgejo.org/docs/latest/license/" + iconURL = "https://codeberg.org/forgejo/governance/raw/branch/main/branding/logo/forgejo.png" description = "Package Description" releaseNotes = "Package Release Notes" readme = "Readme" - repositoryURL = "https://gitea.io/gitea/gitea" + tags = "tag_1 tag_2 tag_3" + minClientVersion = "1.0.0.0" + repositoryURL = "https://codeberg.org/forgejo" targetFramework = ".NETStandard2.1" dependencyID = "System.Text.Json" dependencyVersion = "5.0.0" @@ -28,16 +36,24 @@ const ( const nuspecContent = `@mention-user's comment
\n"), rendered) } func TestNonExistantUserMention(t *testing.T) { - rendered := RenderMarkdownToHtml(context.Background(), "@ThisUserDoesNotExist @mention-user") + rendered := RenderMarkdownToHtml(t.Context(), "@ThisUserDoesNotExist @mention-user") assert.EqualValues(t, template.HTML("@ThisUserDoesNotExist @mention-user
\n"), rendered) } @@ -69,7 +69,7 @@ func TestRenderCommitBody(t *testing.T) { { name: "multiple lines", args: args{ - ctx: context.Background(), + ctx: t.Context(), msg: "first line\nsecond line", }, want: "second line", @@ -77,7 +77,7 @@ func TestRenderCommitBody(t *testing.T) { { name: "multiple lines with leading newlines", args: args{ - ctx: context.Background(), + ctx: t.Context(), msg: "\n\n\n\nfirst line\nsecond line", }, want: "second line", @@ -85,7 +85,7 @@ func TestRenderCommitBody(t *testing.T) { { name: "multiple lines with trailing newlines", args: args{ - ctx: context.Background(), + ctx: t.Context(), msg: "first line\nsecond line\n\n\n", }, want: "second line", @@ -117,19 +117,19 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit #123 space ` + "`code 👍 #123 code`" - assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas)) + assert.EqualValues(t, expected, RenderCommitBody(t.Context(), testInput, testMetas)) } func TestRenderCommitMessage(t *testing.T) { expected := `space @mention-user ` - assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas)) + assert.EqualValues(t, expected, RenderCommitMessage(t.Context(), testInput, testMetas)) } func TestRenderCommitMessageLinkSubject(t *testing.T) { expected := `space @mention-user` - assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput, "https://example.com/link", testMetas)) + assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(t.Context(), testInput, "https://example.com/link", testMetas)) } func TestRenderIssueTitle(t *testing.T) { @@ -155,7 +155,7 @@ mail@domain.com spacecode :+1: #123 code
`
- assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas))
+ assert.EqualValues(t, expected, RenderIssueTitle(t.Context(), testInput, testMetas))
}
func TestRenderRefIssueTitle(t *testing.T) {
@@ -181,7 +181,7 @@ mail@domain.com
space
code :+1: #123 code
`
- assert.EqualValues(t, expected, RenderRefIssueTitle(context.Background(), testInput))
+ assert.EqualValues(t, expected, RenderRefIssueTitle(t.Context(), testInput))
}
func TestRenderMarkdownToHtml(t *testing.T) {
@@ -207,7 +207,7 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
space
code :+1: #123 code
`
- assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput))
+ assert.EqualValues(t, expected, RenderMarkdownToHtml(t.Context(), testInput))
}
func TestRenderLabels(t *testing.T) {
diff --git a/modules/test/distant_federation_server_mock.go b/modules/test/distant_federation_server_mock.go
new file mode 100644
index 0000000000..fd68c88a40
--- /dev/null
+++ b/modules/test/distant_federation_server_mock.go
@@ -0,0 +1,117 @@
+// Copyright 2025 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package test
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+)
+
+type FederationServerMockPerson struct {
+ ID int64
+ Name string
+ PubKey string
+}
+type FederationServerMockRepository struct {
+ ID int64
+}
+type FederationServerMock struct {
+ Persons []FederationServerMockPerson
+ Repositories []FederationServerMockRepository
+ LastPost string
+}
+
+func NewFederationServerMockPerson(id int64, name string) FederationServerMockPerson {
+ return FederationServerMockPerson{
+ ID: id,
+ Name: name,
+ PubKey: `"-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA18H5s7N6ItZUAh9tneII\nIuZdTTa3cZlLa/9ejWAHTkcp3WLW+/zbsumlMrWYfBy2/yTm56qasWt38iY4D6ul\n` +
+ `CPiwhAqX3REvVq8tM79a2CEqZn9ka6vuXoDgBg/sBf/BUWqf7orkjUXwk/U0Egjf\nk5jcurF4vqf1u+rlAHH37dvSBaDjNj6Qnj4OP12bjfaY/yvs7+jue/eNXFHjzN4E\n` +
+ `T2H4B/yeKTJ4UuAwTlLaNbZJul2baLlHelJPAsxiYaziVuV5P+IGWckY6RSerRaZ\nAkc4mmGGtjAyfN9aewe+lNVfwS7ElFx546PlLgdQgjmeSwLX8FWxbPE5A/PmaXCs\n` +
+ `nx+nou+3dD7NluULLtdd7K+2x02trObKXCAzmi5/Dc+yKTzpFqEz+hLNCz7TImP/\ncK//NV9Q+X67J9O27baH9R9ZF4zMw8rv2Pg0WLSw1z7lLXwlgIsDapeMCsrxkVO4\n` +
+ `LXX5AQ1xQNtlssnVoUBqBrvZsX2jUUKUocvZqMGuE4hfAgMBAAE=\n-----END PUBLIC KEY-----\n"`,
+ }
+}
+
+func NewFederationServerMockRepository(id int64) FederationServerMockRepository {
+ return FederationServerMockRepository{
+ ID: id,
+ }
+}
+
+func (p FederationServerMockPerson) marshal(host string) string {
+ return fmt.Sprintf(`{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],`+
+ `"id":"http://%[1]v/api/activitypub/user-id/%[2]v",`+
+ `"type":"Person",`+
+ `"icon":{"type":"Image","mediaType":"image/png","url":"http://%[1]v/avatars/1bb05d9a5f6675ed0272af9ea193063c"},`+
+ `"url":"http://%[1]v/%[2]v",`+
+ `"inbox":"http://%[1]v/api/activitypub/user-id/%[2]v/inbox",`+
+ `"outbox":"http://%[1]v/api/activitypub/user-id/%[2]v/outbox",`+
+ `"preferredUsername":"%[3]v",`+
+ `"publicKey":{"id":"http://%[1]v/api/activitypub/user-id/%[2]v#main-key",`+
+ `"owner":"http://%[1]v/api/activitypub/user-id/%[2]v",`+
+ `"publicKeyPem":%[4]v}}`, host, p.ID, p.Name, p.PubKey)
+}
+
+func NewFederationServerMock() *FederationServerMock {
+ return &FederationServerMock{
+ Persons: []FederationServerMockPerson{
+ NewFederationServerMockPerson(15, "stargoose1"),
+ NewFederationServerMockPerson(30, "stargoose2"),
+ },
+ Repositories: []FederationServerMockRepository{
+ NewFederationServerMockRepository(1),
+ },
+ LastPost: "",
+ }
+}
+
+func (mock *FederationServerMock) DistantServer(t *testing.T) *httptest.Server {
+ federatedRoutes := http.NewServeMux()
+ federatedRoutes.HandleFunc("/.well-known/nodeinfo",
+ func(res http.ResponseWriter, req *http.Request) {
+ // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/.well-known/nodeinfo
+ // TODO: as soon as content-type will become important: content-type: application/json;charset=utf-8
+ fmt.Fprintf(res, `{"links":[{"href":"http://%s/api/v1/nodeinfo","rel":"http://nodeinfo.diaspora.software/ns/schema/2.1"}]}`, req.Host)
+ })
+ federatedRoutes.HandleFunc("/api/v1/nodeinfo",
+ func(res http.ResponseWriter, req *http.Request) {
+ // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/nodeinfo
+ fmt.Fprint(res, `{"version":"2.1","software":{"name":"forgejo","version":"1.20.0+dev-3183-g976d79044",`+
+ `"repository":"https://codeberg.org/forgejo/forgejo.git","homepage":"https://forgejo.org/"},`+
+ `"protocols":["activitypub"],"services":{"inbound":[],"outbound":["rss2.0"]},`+
+ `"openRegistrations":true,"usage":{"users":{"total":14,"activeHalfyear":2}},"metadata":{}}`)
+ })
+ for _, person := range mock.Persons {
+ federatedRoutes.HandleFunc(fmt.Sprintf("/api/v1/activitypub/user-id/%v", person.ID),
+ func(res http.ResponseWriter, req *http.Request) {
+ // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/2
+ fmt.Fprint(res, person.marshal(req.Host))
+ })
+ }
+ for _, repository := range mock.Repositories {
+ federatedRoutes.HandleFunc(fmt.Sprintf("/api/v1/activitypub/repository-id/%v/inbox/", repository.ID),
+ func(res http.ResponseWriter, req *http.Request) {
+ if req.Method != "POST" {
+ t.Errorf("POST expected at: %q", req.URL.EscapedPath())
+ }
+ buf := new(strings.Builder)
+ _, err := io.Copy(buf, req.Body)
+ if err != nil {
+ t.Errorf("Error reading body: %q", err)
+ }
+ mock.LastPost = buf.String()
+ })
+ }
+ federatedRoutes.HandleFunc("/",
+ func(res http.ResponseWriter, req *http.Request) {
+ t.Errorf("Unhandled request: %q", req.URL.EscapedPath())
+ })
+ federatedSrv := httptest.NewServer(federatedRoutes)
+ return federatedSrv
+}
diff --git a/modules/testlogger/testlogger.go b/modules/testlogger/testlogger.go
index d176ab9e4a..caa8abd07b 100644
--- a/modules/testlogger/testlogger.go
+++ b/modules/testlogger/testlogger.go
@@ -471,7 +471,7 @@ func PrintCurrentTest(t testing.TB, skip ...int) func() {
_, _ = fmt.Fprintf(os.Stdout, "+++ %s ... still flushing after %v ...\n", t.Name(), SlowFlush)
}
})
- if err := queue.GetManager().FlushAll(context.Background(), time.Minute); err != nil {
+ if err := queue.GetManager().FlushAll(t.Context(), time.Minute); err != nil {
t.Errorf("Flushing queues failed with error %v", err)
}
timer.Stop()
diff --git a/modules/translation/i18n/i18n_test.go b/modules/translation/i18n/i18n_test.go
index 66f5d5c402..a0458f0b8e 100644
--- a/modules/translation/i18n/i18n_test.go
+++ b/modules/translation/i18n/i18n_test.go
@@ -156,7 +156,15 @@ commits = fallback value for commits
assert.ElementsMatch(t, []string{"lang1", "lang2"}, langs)
assert.ElementsMatch(t, []string{"Lang1", "Lang2"}, descs)
- found := lang1.HasKey("no-such")
+ // Test HasKey for JSON
+ found := lang2.HasKey("section.json")
+ assert.True(t, found)
+
+ // Test HasKey for INI
+ found = lang2.HasKey("section.sub")
+ assert.True(t, found)
+
+ found = lang1.HasKey("no-such")
assert.False(t, found)
assert.EqualValues(t, "no-such", lang1.TrString("no-such"))
require.NoError(t, ls.Close())
diff --git a/modules/translation/i18n/localestore.go b/modules/translation/i18n/localestore.go
index a38e967838..0cfa96810e 100644
--- a/modules/translation/i18n/localestore.go
+++ b/modules/translation/i18n/localestore.go
@@ -303,6 +303,10 @@ func (l *locale) TrPluralString(count any, trKey string, trArgs ...any) template
// HasKey returns whether a key is present in this locale or not
func (l *locale) HasKey(trKey string) bool {
+ _, ok := l.newStyleMessages[trKey]
+ if ok {
+ return true
+ }
idx, ok := l.store.trKeyToIdxMap[trKey]
if !ok {
return false
diff --git a/modules/translation/mock.go b/modules/translation/mock.go
index 4d9acce26f..72a15b7438 100644
--- a/modules/translation/mock.go
+++ b/modules/translation/mock.go
@@ -39,6 +39,10 @@ func (l MockLocale) TrSize(s int64) ReadableSize {
return ReadableSize{fmt.Sprint(s), ""}
}
+func (l MockLocale) HasKey(key string) bool {
+ return true
+}
+
func (l MockLocale) PrettyNumber(v any) string {
return fmt.Sprint(v)
}
diff --git a/modules/translation/translation.go b/modules/translation/translation.go
index 7d1c627c84..7be77536ca 100644
--- a/modules/translation/translation.go
+++ b/modules/translation/translation.go
@@ -39,6 +39,8 @@ type Locale interface {
TrSize(size int64) ReadableSize
+ HasKey(trKey string) bool
+
PrettyNumber(v any) string
}
diff --git a/modules/user/user.go b/modules/user/user.go
index eee401a23f..d153413c70 100644
--- a/modules/user/user.go
+++ b/modules/user/user.go
@@ -6,8 +6,6 @@ package user
import (
"os"
"os/user"
- "runtime"
- "strings"
)
// CurrentUsername return current login OS user name
@@ -16,12 +14,7 @@ func CurrentUsername() string {
if err != nil {
return fallbackCurrentUsername()
}
- username := userinfo.Username
- if runtime.GOOS == "windows" {
- parts := strings.Split(username, "\\")
- username = parts[len(parts)-1]
- }
- return username
+ return userinfo.Username
}
// Old method, used if new method doesn't work on your OS for some reason
diff --git a/modules/user/user_test.go b/modules/user/user_test.go
index 372a675d34..c7eff85c90 100644
--- a/modules/user/user_test.go
+++ b/modules/user/user_test.go
@@ -5,7 +5,6 @@ package user
import (
"os/exec"
- "runtime"
"strings"
"testing"
)
@@ -23,10 +22,6 @@ func TestCurrentUsername(t *testing.T) {
if len(user) == 0 {
t.Errorf("expected non-empty user, got: %s", user)
}
- // Windows whoami is weird, so just skip remaining tests
- if runtime.GOOS == "windows" {
- t.Skip("skipped test because of weird whoami on Windows")
- }
whoami, err := getWhoamiOutput()
if err != nil {
t.Errorf("failed to run whoami to test current user: %f", err)
diff --git a/modules/util/file_unix.go b/modules/util/file_unix.go
index 79a29c8b3b..b722eee97d 100644
--- a/modules/util/file_unix.go
+++ b/modules/util/file_unix.go
@@ -1,8 +1,6 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-//go:build !windows
-
package util
import (
diff --git a/modules/util/file_unix_test.go b/modules/util/file_unix_test.go
index d60082a034..228c64f980 100644
--- a/modules/util/file_unix_test.go
+++ b/modules/util/file_unix_test.go
@@ -1,8 +1,6 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-//go:build !windows
-
package util
import (
diff --git a/modules/util/path.go b/modules/util/path.go
index 185e7cf882..9039f27cbf 100644
--- a/modules/util/path.go
+++ b/modules/util/path.go
@@ -10,8 +10,6 @@ import (
"os"
"path"
"path/filepath"
- "regexp"
- "runtime"
"strings"
)
@@ -78,11 +76,7 @@ func FilePathJoinAbs(base string, sub ...string) string {
// POSIX filesystem can have `\` in file names. Windows: `\` and `/` are both used for path separators
// to keep the behavior consistent, we do not allow `\` in file names, replace all `\` with `/`
- if isOSWindows() {
- elems[0] = filepath.Clean(base)
- } else {
- elems[0] = filepath.Clean(strings.ReplaceAll(base, "\\", pathSeparator))
- }
+ elems[0] = filepath.Clean(strings.ReplaceAll(base, "\\", pathSeparator))
if !filepath.IsAbs(elems[0]) {
// This shouldn't happen. If there is really necessary to pass in relative path, return the full path with filepath.Abs() instead
panic(fmt.Sprintf("FilePathJoinAbs: %q (for path %v) is not absolute, do not guess a relative path based on current working directory", elems[0], elems))
@@ -91,11 +85,7 @@ func FilePathJoinAbs(base string, sub ...string) string {
if s == "" {
continue
}
- if isOSWindows() {
- elems = append(elems, filepath.Clean(pathSeparator+s))
- } else {
- elems = append(elems, filepath.Clean(pathSeparator+strings.ReplaceAll(s, "\\", pathSeparator)))
- }
+ elems = append(elems, filepath.Clean(pathSeparator+strings.ReplaceAll(s, "\\", pathSeparator)))
}
// the elems[0] must be an absolute path, just join them together
return filepath.Join(elems...)
@@ -217,12 +207,6 @@ func StatDir(rootPath string, includeDir ...bool) ([]string, error) {
return statDir(rootPath, "", isIncludeDir, false, false)
}
-func isOSWindows() bool {
- return runtime.GOOS == "windows"
-}
-
-var driveLetterRegexp = regexp.MustCompile("/[A-Za-z]:/")
-
// FileURLToPath extracts the path information from a file://... url.
// It returns an error only if the URL is not a file URL.
func FileURLToPath(u *url.URL) (string, error) {
@@ -230,17 +214,7 @@ func FileURLToPath(u *url.URL) (string, error) {
return "", errors.New("URL scheme is not 'file': " + u.String())
}
- path := u.Path
-
- if !isOSWindows() {
- return path, nil
- }
-
- // If it looks like there's a Windows drive letter at the beginning, strip off the leading slash.
- if driveLetterRegexp.MatchString(path) {
- return path[1:], nil
- }
- return path, nil
+ return u.Path, nil
}
// HomeDir returns path of '~'(in Linux) on Windows,
@@ -249,14 +223,7 @@ func HomeDir() (home string, err error) {
// TODO: some users run Gitea with mismatched uid and "HOME=xxx" (they set HOME=xxx by environment manually)
// TODO: when running gitea as a sub command inside git, the HOME directory is not the user's home directory
// so at the moment we can not use `user.Current().HomeDir`
- if isOSWindows() {
- home = os.Getenv("USERPROFILE")
- if home == "" {
- home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
- }
- } else {
- home = os.Getenv("HOME")
- }
+ home = os.Getenv("HOME")
if home == "" {
return "", errors.New("cannot get home directory")
diff --git a/modules/util/path_test.go b/modules/util/path_test.go
index 3699f052d1..b912b76f6e 100644
--- a/modules/util/path_test.go
+++ b/modules/util/path_test.go
@@ -5,7 +5,6 @@ package util
import (
"net/url"
- "runtime"
"testing"
"github.com/stretchr/testify/assert"
@@ -17,7 +16,6 @@ func TestFileURLToPath(t *testing.T) {
url string
expected string
haserror bool
- windows bool
}{
// case 0
{
@@ -34,18 +32,9 @@ func TestFileURLToPath(t *testing.T) {
url: "file:///path",
expected: "/path",
},
- // case 3
- {
- url: "file:///C:/path",
- expected: "C:/path",
- windows: true,
- },
}
for n, c := range cases {
- if c.windows && runtime.GOOS != "windows" {
- continue
- }
u, _ := url.Parse(c.url)
p, err := FileURLToPath(u)
if c.haserror {
@@ -177,35 +166,18 @@ func TestCleanPath(t *testing.T) {
assert.Equal(t, c.expected, PathJoinRelX(c.elems...), "case: %v", c.elems)
}
- // for POSIX only, but the result is similar on Windows, because the first element must be an absolute path
- if isOSWindows() {
- cases = []struct {
- elems []string
- expected string
- }{
- {[]string{`C:\..`}, `C:\`},
- {[]string{`C:\a`}, `C:\a`},
- {[]string{`C:\a/`}, `C:\a`},
- {[]string{`C:\..\a\`, `../b`, `c\..`, `d`}, `C:\a\b\d`},
- {[]string{`C:\a/..\b`}, `C:\b`},
- {[]string{`C:\a`, ``, `b`}, `C:\a\b`},
- {[]string{`C:\a`, `..`, `b`}, `C:\a\b`},
- {[]string{`C:\lfs`, `repo/..`, `user/../path`}, `C:\lfs\path`},
- }
- } else {
- cases = []struct {
- elems []string
- expected string
- }{
- {[]string{`/..`}, `/`},
- {[]string{`/a`}, `/a`},
- {[]string{`/a/`}, `/a`},
- {[]string{`/../a/`, `../b`, `c/..`, `d`}, `/a/b/d`},
- {[]string{`/a\..\b`}, `/b`},
- {[]string{`/a`, ``, `b`}, `/a/b`},
- {[]string{`/a`, `..`, `b`}, `/a/b`},
- {[]string{`/lfs`, `repo/..`, `user/../path`}, `/lfs/path`},
- }
+ cases = []struct {
+ elems []string
+ expected string
+ }{
+ {[]string{`/..`}, `/`},
+ {[]string{`/a`}, `/a`},
+ {[]string{`/a/`}, `/a`},
+ {[]string{`/../a/`, `../b`, `c/..`, `d`}, `/a/b/d`},
+ {[]string{`/a\..\b`}, `/b`},
+ {[]string{`/a`, ``, `b`}, `/a/b`},
+ {[]string{`/a`, `..`, `b`}, `/a/b`},
+ {[]string{`/lfs`, `repo/..`, `user/../path`}, `/lfs/path`},
}
for _, c := range cases {
assert.Equal(t, c.expected, FilePathJoinAbs(c.elems[0], c.elems[1:]...), "case: %v", c.elems)
diff --git a/modules/util/remove.go b/modules/util/remove.go
index d1e38faf5f..2a65a6b0aa 100644
--- a/modules/util/remove.go
+++ b/modules/util/remove.go
@@ -5,13 +5,10 @@ package util
import (
"os"
- "runtime"
"syscall"
"time"
)
-const windowsSharingViolationError syscall.Errno = 32
-
// Remove removes the named file or (empty) directory with at most 5 attempts.
func Remove(name string) error {
var err error
@@ -27,12 +24,6 @@ func Remove(name string) error {
continue
}
- if unwrapped == windowsSharingViolationError && runtime.GOOS == "windows" {
- // try again
- <-time.After(100 * time.Millisecond)
- continue
- }
-
if unwrapped == syscall.ENOENT {
// it's already gone
return nil
@@ -56,12 +47,6 @@ func RemoveAll(name string) error {
continue
}
- if unwrapped == windowsSharingViolationError && runtime.GOOS == "windows" {
- // try again
- <-time.After(100 * time.Millisecond)
- continue
- }
-
if unwrapped == syscall.ENOENT {
// it's already gone
return nil
@@ -85,12 +70,6 @@ func Rename(oldpath, newpath string) error {
continue
}
- if unwrapped == windowsSharingViolationError && runtime.GOOS == "windows" {
- // try again
- <-time.After(100 * time.Millisecond)
- continue
- }
-
if i == 0 && os.IsNotExist(err) {
return err
}
diff --git a/options/locale/locale_ca.ini b/options/locale/locale_ca.ini
index 4231a68e8a..9cb7d5e50c 100644
--- a/options/locale/locale_ca.ini
+++ b/options/locale/locale_ca.ini
@@ -115,7 +115,7 @@ write = Escriure
preview = Previsualitzar
loading = Carregant…
error = Error
-error404 = La pàgina a la que estàs intentant arribar no existeix o no estàs autoritzat a veure-la.
+error404 = La pàgina a la qual estàs intentant arribar no existeix, ha sigut eliminada o no estàs autoritzat a veure-la.
go_back = Tornar Enrere
invalid_data = Dades invalides: %v
unknown = Desconegut
@@ -173,7 +173,7 @@ pull_kind = Cerca "pulls"...
exact = Exacte
exact_tooltip = Inclou només resultats que són exactament el terme de cerca
issue_kind = Cerca problemes...
-regexp = Expressió regular
+regexp = RegExp
regexp_tooltip = Interpreta el terme de cerca com una expressió regular
[heatmap]
@@ -213,7 +213,7 @@ reinstall_error = Estas intentant instaŀlar sobre una base de dades existent de
reinstall_confirm_message = Reinstaŀlar amb una base de dades existent de Forgejo pot causar diferents problemes. En la majoria de casos, s'hauria d'utilitzar l'"app.ini" existent per executar Forgejo. Si saps el que estàs fent, confirma el seguent:
no_admin_and_disable_registration = No pot deshabilitar l'autoregistre d'usuaris sense crear un compte d'administrador.
err_admin_name_is_reserved = El nom d'usuari "Administrador" no es vàlid: està reservat
-smtp_addr = Hoste SMPT
+smtp_addr = Hoste SMTP
smtp_port = Port SMPT
smtp_from = Enviar correu com a
mailer_user = Nom d'usuari SMTP
@@ -410,6 +410,9 @@ oauth_signin_tab = Vincular a un compte existent
oauth.signin.error = Hi ha hagut un error processant la sol·licitud d'autorització. Si persisteix, poseu-vos en contacte amb l'administrador del lloc.
disable_forgot_password_mail_admin = La recuperació de comptes només està disponible quan s'ha configurat el correu electrònic. Si us plau, configureu el correu electrònic per a habilitar la recuperació de comptes.
non_local_account = Els usuaris no locals no poden actualitzar la seva contrasenya mitjançant l'interfície web de Forgejo
+openid_register_desc = No s'ha reconegut la URI OpenID. Vinculeu-la amb un compte nou aquí.
+openid_connect_desc = No s'ha reconegut la URI OpenID. Vinculeu-la amb un compte nou aquí.
+sign_in_openid = Accediu amb OpenID
[editor]
buttons.indent.tooltip = Aniua els elements un nivell
@@ -434,6 +437,10 @@ table_modal.placeholder.header = Capçalera
table_modal.placeholder.content = Contingut
table_modal.label.rows = Files
table_modal.label.columns = Columnes
+link_modal.header = Afegeix un enllaç
+link_modal.url = URL
+link_modal.description = Descripció
+link_modal.paste_reminder = Pista: Amb un enllaç en el teu porta-retalls, pots enganxar-la directament a l'editor per a crear un enllaç.
[home]
my_orgs = Organitzacions
@@ -472,4 +479,8 @@ reply = o responeu directament a aquest correu
activate_account.text_1 = Hola %[1]s, gràcies per registrar-te a %[2]s!
register_notify = Benvinguts a %s
admin.new_user.text = Si us plau, cliqueu aui per administrar aquest usuari des del panell d'administració.
-admin.new_user.user_info = Informació d'usuari
\ No newline at end of file
+admin.new_user.user_info = Informació d'usuari
+admin.new_user.subject = Nou usuari %s s'acaba d'enregistrar
+activate_email.text = Si us plau, cliqueu el següent enllaç per verificar la vostra adreça de correu electrònic en %s
+activate_email = Verifica la teva adreça de correu electrònic
+activate_account.text_2 = Si us plau, cliqueu l'enllaç següent per activar el vostre compte en %s:
\ No newline at end of file
diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini
index f4f1190948..7fc4d1c7aa 100644
--- a/options/locale/locale_cs-CZ.ini
+++ b/options/locale/locale_cs-CZ.ini
@@ -112,7 +112,7 @@ preview=Náhled
loading=Načítání…
error=Chyba
-error404=Stránka, kterou se snažíte zobrazit, buď neexistuje, nebo nemáte oprávnění ji zobrazit.
+error404=Stránka, kterou se snažíte zobrazit, buď neexistuje, byla odstraněna nebo nemáte oprávnění ji zobrazit.
go_back=Zpět
never=Nikdy
@@ -205,6 +205,10 @@ table_modal.placeholder.header = Záhlaví
table_modal.placeholder.content = Obsah
table_modal.label.rows = Řádky
table_modal.label.columns = Sloupce
+link_modal.header = Přidat odkaz
+link_modal.url = URL
+link_modal.description = Popis
+link_modal.paste_reminder = Tip: pokud máte adresu zkopírovanou ve schránce, můžete vytvořit odkaz jejím vložením přímo do editoru.
[filter]
string.asc=A – Z
@@ -1062,6 +1066,26 @@ change_username_redirect_prompt.with_cooldown.few = Staré uživatelské jméno
change_username_redirect_prompt.with_cooldown.one = Staré uživatelské jméno bude dostupné ostatním po %[1]d dni. Do té doby budete moci své staré uživatelské jméno znovu získat.
keep_pronouns_private = Zobrazovat zájmena pouze přihlášeným uživatelům
keep_pronouns_private.description = Toto nastavení skryje vaše zájmena před návštěvníky, kteří nejsou přihlášeni.
+quota = Kvóta
+quota.applies_to_org = Následující pravidla kvóty se vztahují na tuto organizaci
+quota.rule.exceeded = Překročeno
+quota.rule.no_limit = Neomezená
+quota.sizes.all = Vše
+quota.sizes.repos.all = Repozitáře
+quota.sizes.repos.public = Veřejné repozitáře
+quota.sizes.repos.private = Soukromé repozitáře
+quota.sizes.git.all = Obsah gitu
+quota.sizes.git.lfs = Git LFS
+quota.sizes.assets.all = Prostředky
+quota.sizes.assets.attachments.all = Přílohy
+quota.sizes.assets.attachments.issues = Přílohy problémů
+quota.sizes.assets.artifacts = Artefakty
+quota.sizes.assets.packages.all = Balíčky
+quota.sizes.wiki = Wiki
+storage_overview = Přehled úložiště
+quota.applies_to_user = Následující pravidla kvóty se vztahují na váš účet
+quota.rule.exceeded.helper = Celková velikost objektů pro toto pravidlo přesáhla kvótu.
+quota.sizes.assets.attachments.releases = Přílohy vydání
[repo]
new_repo_helper=Repozitář obsahuje všechny soubory projektu, včetně historie revizí. Už jej hostujete jinde? Migrovat repozitář.
@@ -2697,7 +2721,7 @@ error.csv.unexpected=Tento soubor nelze vykreslit, protože obsahuje neočekáva
error.csv.invalid_field_count=Soubor nelze vykreslit, protože má nesprávný počet polí na řádku %d.
pulls.made_using_agit = AGit
settings.confirm_wiki_branch_rename = Přejmenovat větev wiki
-issues.comment.blocked_by_user = U tohoto problému nemůžete vytvořit komentář, protože jste byl/a zablokován/a majitelem repozitáře nebo autorem problému.
+issues.comment.blocked_by_user = Tento problém nemůžete okomentovat, protože jste byli zablokováni majitelem repozitáře nebo autorem problému.
contributors.contribution_type.additions = Přidání
admin.manage_flags = Spravovat vlajky
admin.enabled_flags = Vlajky povolené v repozitáři:
@@ -2710,7 +2734,7 @@ clone_in_vscodium = Klonovat do VSCodium
settings.wiki_rename_branch_main_notices_1 = Tato operace je NEVRATNÁ.
settings.wiki_branch_rename_success = Název větve wiki repozitáře byl úspěšně normalizován.
rss.must_be_on_branch = Abyste mohli mít zdroj RSS, musíte se nacházet ve větvi.
-issues.blocked_by_user = V tomto repozitáři nemůžete vytvořit problém, protože jste byl/a jeho majitelem zablokován/a.
+issues.blocked_by_user = V tomto repozitáři nemůžete vytvářet problémy, protože jste byl/a jeho majitelem zablokován/a.
migrate.forgejo.description = Migrovat data z codeberg.org nebo jiných instancí Forgejo.
mirror_sync = synchronizováno
blame.ignore_revs = Ignorování revizí v souboru .git-blame-ignore-revs. Klikněte sem pro udělení výjimky a zobrazení normálního přehledu blame.
@@ -2877,6 +2901,10 @@ editor.commit_email = E-mail revize
commits.view_single_diff = Zobrazit změny tohoto souboru provedené v této revizi
pulls.editable = Upravitelné
pulls.editable_explanation = Tato žádost o sloučení umožňuje úpravy správci. Můžete přispět přímo do ní.
+issues.reopen.blocked_by_user = Tento problém nemůžete znovu otevřít, protože jste byli zablokováni majitelem repozitáře nebo autorem tohoto problému.
+pulls.comment.blocked_by_user = Tuto žádost o sloučení nemůžete okomentovat, protože jste byli zablokováni majitelem repozitáře nebo autorem žádosti.
+issues.filter_no_results_placeholder = Zkuste upravit filtry vyhledávání.
+issues.filter_no_results = Žádné výsledky
[graphs]
component_loading_info = Tohle může chvíli trvat…
diff --git a/options/locale/locale_da.ini b/options/locale/locale_da.ini
index 0950138651..5a79004acb 100644
--- a/options/locale/locale_da.ini
+++ b/options/locale/locale_da.ini
@@ -123,7 +123,7 @@ webauthn_error_timeout = Timeout nået, før din nøgle kunne læses. Genindlæs
enabled = Aktiveret
locked = Låst
copy_hash = Kopiér hash
-error404 = Den side, du forsøger at nå, enten findes ikke eller du er ikke autoriseret til at se den.
+error404 = Den side, du forsøger at nå, enten findes ikke , er blevet slettet eller du er ikke autoriseret til at se den.
confirm_delete_artifact = Er du sikker på, at du vil slette artefakten "%s"?
new_migrate.title = Ny migration
copy_type_unsupported = Denne filtype kan ikke kopieres
@@ -152,7 +152,7 @@ type_tooltip = Søge type
fuzzy = Fuzzy
fuzzy_tooltip = Medtag resultater, der også matcher søgeordet tæt
union = Almindelig
-union_tooltip = Inkluder resultater, der matcher et hvilket som helst af de mellemrumsadskilte søgeord
+union_tooltip = Inkluder resultater, der matcher et hvilket som helst af de mellemrums-adskilte søgeord
exact = Nøjagtig
exact_tooltip = Medtag kun resultater, der matcher den nøjagtige søgeterm
regexp = RegExp
@@ -213,6 +213,10 @@ table_modal.label.columns = Kolonner
buttons.unindent.tooltip = Udsortere genstande med ét niveau
buttons.indent.tooltip = Indlejring af genstande med ét niveau
buttons.switch_to_legacy.tooltip = Brug den gamle editor i stedet
+link_modal.header = Tilføj et link
+link_modal.url = Url
+link_modal.description = Beskrivelse
+link_modal.paste_reminder = Tip: Med en URL i dit udklipsholder kan du indsætte direkte i editoren for at oprette et link.
[filter]
string.asc = A - Z
@@ -978,6 +982,26 @@ change_username_redirect_prompt.with_cooldown.one = Det gamle brugernavn vil væ
change_username_redirect_prompt.with_cooldown.few = Det gamle brugernavn vil være tilgængeligt for alle efter en nedkølingsperiode på %[1]d dage, du kan stadig kræve det gamle brugernavn tilbage i nedkølingsperioden.
keep_pronouns_private = Vis kun stedord til godkendte brugere
keep_pronouns_private.description = Dette vil skjule dine stedord for besøgende, der ikke er logget ind.
+quota.applies_to_user = Følgende kvoteregler gælder for din konto
+quota.rule.exceeded.helper = Den samlede størrelse af objekter for denne regel har overskredet kvoten.
+storage_overview = Opbevaringsoversigt
+quota = Kvote
+quota.applies_to_org = Følgende kontingentregler gælder for denne organisation
+quota.rule.exceeded = Oversteget
+quota.rule.no_limit = Ubegrænset
+quota.sizes.all = Alle
+quota.sizes.repos.all = Depoter
+quota.sizes.repos.public = Offentlige depoter
+quota.sizes.repos.private = Private depoter
+quota.sizes.git.all = Git indhold
+quota.sizes.git.lfs = Git LFS
+quota.sizes.assets.all = Aktiver
+quota.sizes.assets.attachments.all = Vedhæftede filer
+quota.sizes.assets.attachments.issues = Problemets vedhæftede filer
+quota.sizes.assets.attachments.releases = Udgivelsens vedhæftede filer
+quota.sizes.assets.artifacts = Artefakter
+quota.sizes.assets.packages.all = Pakker
+quota.sizes.wiki = Wiki
[repo]
rss.must_be_on_branch = Du skal være på en gren for at have et RSS-feed.
@@ -1755,8 +1779,8 @@ issues.review.un_resolve_conversation = Uafklaret samtale
issues.content_history.delete_from_history = Slet fra historikken
issues.content_history.delete_from_history_confirm = Slet fra historikken?
issues.content_history.options = Valgmuligheder
-issues.blocked_by_user = Du kan ikke oprette et problem på dette depot, fordi du er blokeret af depotes ejer.
-issues.comment.blocked_by_user = Du kan ikke oprette en kommentar til dette problem, fordi du er blokeret af depotes ejer eller anmelder af problemet.
+issues.blocked_by_user = Du kan ikke oprette problemer på dette depot, fordi du er blokeret af depotes ejer.
+issues.comment.blocked_by_user = Du kan ikke kommentere til dette problem, fordi du er blokeret af depotes ejer eller anmelder af problemet.
issues.reference_link = Reference: %s
compare.compare_base = base
compare.compare_head = sammenlign
@@ -1856,8 +1880,66 @@ pulls.rebase_merge_pull_request = Rebaser og spole derefter frem
pulls.rebase_merge_commit_pull_request = Rebase og opret derefter flet commit
pulls.waiting_count_1 = %d venter på gennemgang
pulls.invalid_merge_option = Du kan ikke bruge denne fletteindstilling til denne pull-anmodning.
-pulls.merge_conflict = Sammenfletning mislykkedes: Der var en konflikt under sammenlægningen. Tip: Prøv en anden strategi
+pulls.merge_conflict = Fletning mislykkedes: Der var en konflikt under sammenlægningen. Tip: Prøv en anden strategi
pulls.merge_conflict_summary = Fejl besked
+pulls.rebase_conflict_summary = Fejl besked
+pulls.unrelated_histories = Fletning mislykkedes: Sammenfletnings-hovedet og -basen deler ikke en fælles historie. Tip: Prøv en anden strategi
+pulls.head_out_of_date = Fletning mislykkedes: Under genereringen af fletningen blev hovedet opdateret. Tip: Prøv igen.
+pulls.has_merged = Mislykkedes: Pull-anmodningen er blevet flettet, du kan ikke flette igen eller ændre målgrenen.
+pulls.rebase_conflict = Fletning mislykkedes: Der var en konflikt under re-basering af commit: %[1]s. Tip: Prøv en anden strategi
+pulls.merge_out_of_date = Fletning mislykkedes: Under genereringen af fletningen blev basen opdateret. Tip: Prøv igen.
+pulls.push_rejected_summary = Fuld afvisningsmeddelelse
+pulls.push_rejected = Push mislykkedes: Pushet blev afvist. Gennemgå Git-hooks for dette depot.
+pulls.push_rejected_no_message = Push mislykkedes: Pushet blev afvist, men der var ingen fjernmeddelelse. Gennemgå Git-hooks for dette depot
+pulls.status_checks_failure = Nogle kontroller mislykkedes
+issues.reopen.blocked_by_user = Du kan ikke genåbne dette problem, fordi du er blokeret af depotes ejer eller aflæggeren af dette problem.
+pulls.comment.blocked_by_user = Du kan ikke kommentere denne pull-anmodning, fordi du er blokeret af depotes ejer eller plakaten for pull-anmodningen.
+pulls.open_unmerged_pull_exists = `Du kan ikke udføre en genåbnings handling, fordi der er en afventende pull-anmodning (#%d) med identiske egenskaber.`
+pulls.status_checking = Nogle kontroller afventer
+pulls.status_checks_warning = Nogle kontroller rapporterede advarsler
+pulls.status_checks_error = Nogle kontroller rapporterede fejl
+pulls.cmd_instruction_merge_desc = Flet ændringerne og opdater på Forgejo.
+pulls.clear_merge_message = Ryd flettemeddelelse
+pulls.cmd_instruction_merge_warning = Advarsel: Indstillingen "Autofind manuel fletning" er ikke aktiveret for dette depot. Du skal efterfølgende markere denne pull-anmodning som manuelt flettet.
+pulls.clear_merge_message_hint = Rydning af flettemeddelelsen vil kun fjerne commit-meddelelsens indhold og beholde genererede git-trailere såsom "Co-Authored-By ...".
+pulls.reopen_failed.head_branch = Pull-anmodningen kan ikke genåbnes, fordi hovedgrenen ikke eksisterer længere.
+pulls.editable_explanation = Denne pull-anmodning tillader redigeringer fra vedligeholdere. Du kan bidrage direkte til det.
+pulls.auto_merge_button_when_succeed = (Når kontroller lykkes)
+pulls.status_checks_requested = Påkrævet
+pulls.close = Luk pull anmodning
+pulls.commit_ref_at = `henviste til denne pull-anmodning fra en commit %[2]s`
+pulls.cmd_instruction_hint = Se instruktionerne på kommandolinjen
+pulls.reopened_at = `genåbnede denne pull-anmodning %[2]s`
+pulls.closed_at = `lukkede denne pull-anmodning %[2]s`
+pulls.cmd_instruction_checkout_desc = Fra dit projektdepot, tjek en ny gren og test ændringerne.
+pulls.editable = Redigerbar
+pulls.made_using_agit = AGit
+pulls.agit_explanation = Oprettet ved hjælp af AGit-arbejdsgangen. AGit lader bidragydere foreslå ændringer ved hjælp af "git push" uden at oprette en fork eller en ny gren.
+pulls.status_checks_success = Alle kontroller lykkedes
+pulls.cmd_instruction_merge_title = Flet
+pulls.reopen_failed.base_branch = Pull-anmodningen kan ikke genåbnes, fordi basisgrenen ikke eksisterer længere.
+pulls.cmd_instruction_checkout_title = Checkout
+pulls.outdated_with_base_branch = Denne gren er forældet med basisgrenen
+pulls.status_checks_details = Detaljer
+pulls.status_checks_hide_all = Skjul alle kontroller
+pulls.status_checks_show_all = Vis alle kontroller
+pulls.update_branch = Opdater gren ved fletning
+pulls.update_branch_rebase = Opdel gren ved genbase
+pulls.update_branch_success = Grenopdatering var vellykket
+pulls.update_not_allowed = Du har ikke tilladelse til at opdatere grenen
+pulls.auto_merge_has_pending_schedule = %[1]s planlagde denne pull-anmodning til automatisk at flette, når alle kontroller lykkes %[2]s.
+pulls.auto_merge_cancel_schedule = Annuller automatisk fletning
+pulls.auto_merge_not_scheduled = Denne pull-anmodning er ikke planlagt til automatisk fletning.
+pulls.auto_merge_canceled_schedule = Den automatiske fletning blev annulleret for denne pull-anmodning.
+pulls.auto_merge_newly_scheduled_comment = `planlagde denne pull-anmodning til automatisk at flette, når alle kontroller lykkes %[1]s.`
+pulls.auto_merge_canceled_schedule_comment = `annullerede automatisk fletning af denne pull-anmodning, når alle kontroller lykkes %[1]s`
+pulls.delete_after_merge.head_branch.is_default = Den hovedgren, du vil slette, er standardgrenen og kan ikke slettes.
+pulls.delete_after_merge.head_branch.is_protected = Den hovedgren, du vil slette, er en beskyttet gren og kan ikke slettes.
+pulls.delete_after_merge.head_branch.insufficient_branch = Du har ikke tilladelse til at slette hovedgrenen.
+pulls.delete.title = Vil du slette denne pull-anmodning?
+pulls.delete.text = Vil du virkelig slette denne pull-anmodning? (Dette fjerner alt indhold permanent. Overvej at lukke det i stedet, hvis du har til hensigt at beholde det arkiveret)
+pulls.auto_merge_newly_scheduled = Pull-anmodningen var planlagt til at flette, når alle kontroller lykkes.
+pulls.auto_merge_when_succeed = Automatisk fletning, når alle kontroller lykkes
[notification]
watching = Overvåger
diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini
index 34a69202b0..ccd50d0718 100644
--- a/options/locale/locale_de-DE.ini
+++ b/options/locale/locale_de-DE.ini
@@ -206,6 +206,10 @@ table_modal.placeholder.content = Inhalt
table_modal.placeholder.header = Kopfzeile
table_modal.label.rows = Zeilen
table_modal.label.columns = Spalten
+link_modal.header = Einen Link hinzufügen
+link_modal.url = URL
+link_modal.description = Beschreibung
+link_modal.paste_reminder = Hinweis: Wenn du einen URL in der Zwischenablage hast, kannst du durch einfügen im Editor direkt einen Link erstellen.
[filter]
string.asc=A–Z
@@ -1064,6 +1068,26 @@ change_username_redirect_prompt.with_cooldown.one = Der alte Benutzername ist na
change_username_redirect_prompt.with_cooldown.few = Der alte Benutzername ist nach einer Schutzzeit von %[1]d Tagen wieder für alle Verfügbar. Du kannst den alten Benutzername während dieser Schutzzeit erneut beanspruchen.
keep_pronouns_private = Pronomen nur angemeldeten Nutzern anzeigen
keep_pronouns_private.description = Dies verbirgt deine Pronomen von Besuchern die nicht angemeldet sind.
+quota.sizes.assets.artifacts = Artefakte
+quota.applies_to_user = Die folgenden Quota-Regeln greifen für deinen Account
+quota.sizes.assets.attachments.issues = Issue-Anhänge
+quota.rule.exceeded.helper = Die Gesamtgröße der Objekte für diese Regel hat die Quota überschritten.
+storage_overview = Speicherübersicht
+quota = Quota
+quota.sizes.assets.attachments.releases = Release-Anhänge
+quota.applies_to_org = Die folgenden Quota-Regeln greifen für diese Organisation
+quota.rule.exceeded = Überschritten
+quota.rule.no_limit = Unbegrenzt
+quota.sizes.all = Alle
+quota.sizes.repos.all = Repositorys
+quota.sizes.repos.public = Öffentliche Repositorys
+quota.sizes.repos.private = Private Repositorys
+quota.sizes.git.all = Git-Inhalte
+quota.sizes.git.lfs = Git-LFS
+quota.sizes.assets.all = Assets
+quota.sizes.assets.attachments.all = Anhänge
+quota.sizes.assets.packages.all = Pakete
+quota.sizes.wiki = Wiki
[repo]
owner=Besitzer
@@ -1185,8 +1209,8 @@ template.issue_labels=Issue-Labels
template.one_item=Es muss mindestens ein Vorlagenelement ausgewählt werden
template.invalid=Es muss ein Vorlagen-Repository ausgewählt werden
-archive.title=Dieses Repository ist archiviert. Du kannst Dateien ansehen und es klonen, kannst aber du kannst den Status des Repositorys nicht verändern, zum Beispiel nichts pushen, und keine Issues eröffnen, oder Pull-Requests oder Kommentare erstellen.
-archive.title_date=Dieses Repository wurde am %s archiviert. Du kannst Dateien ansehen und es klonen, kannst aber den Status des Repositorys nicht verändern, zum Beispiel nichts pushen, und keine Issues eröffnen, oder Pull-Requests oder Kommentare erstellen.
+archive.title=Dieses Repository ist archiviert. Du kannst Dateien ansehen und es klonen, kannst aber du kannst seinen Status nicht verändern, zum Beispiel nichts pushen, und keine Issues eröffnen, oder Pull-Requests oder Kommentare erstellen.
+archive.title_date=Dieses Repository wurde am %s archiviert. Du kannst Dateien ansehen und es klonen, kannst aber seinen Status nicht verändern, zum Beispiel nichts pushen, und keine Issues eröffnen, oder Pull-Requests oder Kommentare erstellen.
archive.issue.nocomment=Dieses Repository ist archiviert. Du kannst Issues nicht kommentieren.
archive.pull.nocomment=Dieses Repository ist archiviert. Du kannst Pull-Requests nicht kommentieren.
@@ -2699,7 +2723,7 @@ error.csv.unexpected=Diese Datei kann nicht gerendert werden, da sie ein unerwar
error.csv.invalid_field_count=Diese Datei kann nicht gerendert werden, da sie eine falsche Anzahl an Feldern in Zeile %d hat.
rss.must_be_on_branch = Du musst auf einem Branch sein, um einen RSS-Feed zu haben.
new_repo_helper = Ein Repository enthält alle Projektdateien inklusive der Revisionshistorie. Bereits woanders gehostet? Repository migrieren.
-issues.comment.blocked_by_user = Du kannst kein Kommentar für dieses Issue erstellen, weil du vom Repository-Besitzer oder dem Autoren des Issues blockiert wurdest.
+issues.comment.blocked_by_user = Du kannst dieses Issue nicht kommentieren, weil du vom Repository-Besitzer oder dem Autoren des Issues blockiert wurdest.
clone_in_vscodium = In VSCodium klonen
settings.units.add_more = Mehr aktivieren
settings.wiki_rename_branch_main_desc = Den Branch, der intern vom Wiki benutzt wird, zu „%s“ umbenennen. Dies ist permanent und kann nicht rückgängig gemacht werden.
@@ -2715,7 +2739,7 @@ settings.wiki_branch_rename_success = Der Branch-Name des Repository-Wikis wurde
settings.archive.mirrors_unavailable = Spiegel sind nicht verfügbar in archivierten Repos.
pulls.blocked_by_user = Du kannst keinen Pull-Request in diesem Repository erstellen, weil du vom Repository-Besitzer blockiert wurdest.
settings.add_collaborator_blocked_our = Der Mitarbeiter konnte nicht hinzugefügt werden, weil der Repository-Besitzer ihn blockiert hat.
-issues.blocked_by_user = Du kannst kein Issue in diesem Repository erstellen, weil du vom Repository-Besitzer blockiert wurdest.
+issues.blocked_by_user = Du kannst keine Issues in diesem Repository erstellen, weil du vom Repository-Besitzer blockiert wurdest.
admin.manage_flags = Flags verwalten
admin.enabled_flags = Vom Repository aktivierte Flags:
admin.update_flags = Flags aktualisieren
@@ -2879,6 +2903,8 @@ editor.commit_email = Commit-E-Mail
commits.view_single_diff = Änderungen an dieser Datei, die in diesem Commit eingeführt wurden, betrachten
pulls.editable = Bearbeitbar
pulls.editable_explanation = Dieser Pull-Request erlaubt Bearbeitungen durch Maintainer. Du kannst direkt dazu beitragen.
+issues.reopen.blocked_by_user = Du kannst dieses Issue nicht wieder eröffnen, weil du vom Repository-Besitzer oder Ersteller des Issues blockiert wurdest.
+pulls.comment.blocked_by_user = Du kannst diesen Pull-Request nicht kommentieren, da du vom Repository-Besitzer oder Ersteller des Pull-Requests blockiert wurdest.
[graphs]
component_loading_failed = Konnte %s nicht laden
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index bd7b91cd5a..2a8c789385 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -166,7 +166,7 @@ filter.public = Public
filter.private = Private
[search]
-search = Search...
+search = Search…
type_tooltip = Search type
fuzzy = Fuzzy
fuzzy_tooltip = Include results that also match the search term closely
@@ -176,20 +176,20 @@ exact = Exact
exact_tooltip = Include only results that match the exact search term
regexp = RegExp
regexp_tooltip = Interpret the search term as a regular expression
-repo_kind = Search repos...
-user_kind = Search users...
-org_kind = Search orgs...
-team_kind = Search teams...
-code_kind = Search code...
+repo_kind = Search repos…
+user_kind = Search users…
+org_kind = Search orgs…
+team_kind = Search teams…
+code_kind = Search code…
code_search_unavailable = Code search is currently not available. Please contact the site administrator.
-package_kind = Search packages...
-project_kind = Search projects...
-branch_kind = Search branches...
-commit_kind = Search commits...
-runner_kind = Search runners...
+package_kind = Search packages…
+project_kind = Search projects…
+branch_kind = Search branches…
+commit_kind = Search commits…
+runner_kind = Search runners…
no_results = No matching results found.
-issue_kind = Search issues...
-pull_kind = Search pulls...
+issue_kind = Search issues…
+pull_kind = Search pulls…
keyword_search_unavailable = Searching by keyword is currently not available. Please contact the site administrator.
[aria]
@@ -232,6 +232,11 @@ table_modal.placeholder.content = Content
table_modal.label.rows = Rows
table_modal.label.columns = Columns
+link_modal.header = Add a link
+link_modal.url = Url
+link_modal.description = Description
+link_modal.paste_reminder = Hint: With a URL in your clipboard, you can paste directly into the editor to create a link.
+
[filter]
string.asc = A - Z
string.desc = Z - A
@@ -604,9 +609,6 @@ CommitChoice = Commit choice
TreeName = File path
Content = Content
-SSPISeparatorReplacement = Separator
-SSPIDefaultLanguage = Default language
-
require_error = ` cannot be empty.`
alpha_dash_error = ` should contain only alphanumeric, dash ("-") and underscore ("_") characters.`
alpha_dash_dot_error = ` should contain only alphanumeric, dash ("-"), underscore ("_") and dot (".") characters.`
@@ -744,6 +746,8 @@ organization = Organizations
uid = UID
webauthn = Two-factor authentication (Security keys)
blocked_users = Blocked users
+storage_overview = Storage overview
+quota = Quota
public_profile = Public profile
biography_placeholder = Tell others a little bit about yourself! (Markdown is supported)
@@ -754,8 +758,6 @@ full_name = Full name
website = Website
location = Location
pronouns = Pronouns
-pronouns_custom = Custom
-pronouns_custom_label = Custom pronouns
pronouns_unspecified = Unspecified
update_theme = Change theme
update_profile = Update profile
@@ -941,6 +943,10 @@ delete_token = Delete
access_token_deletion = Delete access token
access_token_deletion_desc = Deleting a token will revoke access to your account for applications using it. This cannot be undone. Continue?
delete_token_success = The token has been deleted. Applications using it no longer have access to your account.
+regenerate_token = Regenerate
+access_token_regeneration = Regenerate access token
+access_token_regeneration_desc = Regenerating a token will revoke access to your account for applications using it. This cannot be undone. Continue?
+regenerate_token_success = The token has been regenerated. Applications that use it no longer have access to your account and must be updated with the new token.
repo_and_org_access = Repository and Organization Access
permissions_public_only = Public only
permissions_access_all = All (public, private, and limited)
@@ -1049,6 +1055,25 @@ user_unblock_success = The user has been unblocked successfully.
user_block_success = The user has been blocked successfully.
user_block_yourself = You cannot block yourself.
+quota.applies_to_user = The following quota rules apply to your account
+quota.applies_to_org = The following quota rules apply to this organisation
+quota.rule.exceeded = Exceeded
+quota.rule.exceeded.helper = The total size of objects for this rule has exceeded the quota.
+quota.rule.no_limit = Unlimited
+quota.sizes.all = All
+quota.sizes.repos.all = Repositories
+quota.sizes.repos.public = Public repositories
+quota.sizes.repos.private = Private repositories
+quota.sizes.git.all = Git content
+quota.sizes.git.lfs = Git LFS
+quota.sizes.assets.all = Assets
+quota.sizes.assets.attachments.all = Attachments
+quota.sizes.assets.attachments.issues = Issue attachments
+quota.sizes.assets.attachments.releases = Release attachments
+quota.sizes.assets.artifacts = Artifacts
+quota.sizes.assets.packages.all = Packages
+quota.sizes.wiki = Wiki
+
[repo]
rss.must_be_on_branch = You must be on a branch to have an RSS feed.
@@ -1146,7 +1171,7 @@ stars = Stars
reactions_more = and %d more
unit_disabled = The site administrator has disabled this repository section.
language_other = Other
-adopt_search = Enter username to search for unadopted repositories... (leave blank to find all)
+adopt_search = Enter username to search for unadopted repositories… (leave blank to find all)
adopt_preexisting_label = Adopt files
adopt_preexisting = Adopt pre-existing files
adopt_preexisting_content = Create repository from %s
@@ -1233,7 +1258,7 @@ migrate.migrate_items_options = Access token is required to migrate additional i
migrated_from = Migrated from %[2]s
migrated_from_fake = Migrated from %[1]s
migrate.migrate = Migrate from %s
-migrate.migrating = Migrating from %s ...
+migrate.migrating = Migrating from %s …
migrate.migrating_failed = Migrating from %s failed.
migrate.migrating_failed.error = Failed to migrate: %s
migrate.migrating_failed_no_addr = Migration failed.
@@ -1516,6 +1541,8 @@ issues.filter_milestones = Filter Milestone
issues.filter_projects = Filter Project
issues.filter_labels = Filter Label
issues.filter_reviewers = Filter Reviewer
+issues.filter_no_results = No results
+issues.filter_no_results_placeholder = Try adjusting your search filters.
issues.new = New issue
issues.new.title_empty = Title cannot be empty
issues.new.labels = Labels
@@ -1853,8 +1880,9 @@ issues.content_history.delete_from_history = Delete from history
issues.content_history.delete_from_history_confirm = Delete from history?
issues.content_history.options = Options
issues.reference_link = Reference: %s
-issues.blocked_by_user = You cannot create a issue on this repository because you are blocked by the repository owner.
-issues.comment.blocked_by_user = You cannot create a comment on this issue because you are blocked by the repository owner or the poster of the issue.
+issues.blocked_by_user = You cannot create issues in this repository because you are blocked by the repository owner.
+issues.comment.blocked_by_user = You cannot comment on this issue because you are blocked by the repository owner or the poster of the issue.
+issues.reopen.blocked_by_user = You cannot reopen this issue because you are blocked by the repository owner or the poster of this issue.
issues.summary_card_alt = Summary card of an issue titled "%s" in repository %s
compare.compare_base = base
@@ -1938,6 +1966,7 @@ pulls.waiting_count_1 = %d waiting review
pulls.waiting_count_n = %d waiting reviews
pulls.wrong_commit_id = commit id must be a commit id on the target branch
pulls.blocked_by_user = You cannot create a pull request on this repository because you are blocked by the repository owner.
+pulls.comment.blocked_by_user = You cannot comment on this pull request because you are blocked by the repository owner or the poster of the pull request.
pulls.no_merge_desc = This pull request cannot be merged because all repository merge options are disabled.
pulls.no_merge_helper = Enable merge options in the repository settings or merge the pull request manually.
@@ -2627,7 +2656,7 @@ settings.lfs_invalid_locking_path=Invalid path: %s
settings.lfs_invalid_lock_directory=Cannot lock directory: %s
settings.lfs_lock_already_exists=Lock already exists: %s
settings.lfs_lock=Lock
-settings.lfs_lock_path=Filepath to lock...
+settings.lfs_lock_path=Filepath to lock…
settings.lfs_locks_no_locks=No locks
settings.lfs_lock_file_no_exist=Locked file does not exist in default branch
settings.lfs_force_unlock=Force unlock
@@ -2837,7 +2866,7 @@ ext_issues = Access the link to an external issue tracker. The permissions are m
ext_wiki = Access the link to an external wiki. The permissions are managed externally.
[graphs]
-component_loading = Loading %s...
+component_loading = Loading %s…
component_loading_failed = Could not load %s
component_loading_info = This might take a bit…
component_failed_to_load = An unexpected error happened.
@@ -3272,16 +3301,6 @@ auths.oauth2_admin_group = Group claim value for administrator users. (Optional
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)
auths.oauth2_map_group_to_team_removal = Remove users from synchronized teams if user does not belong to corresponding group.
-auths.sspi_auto_create_users = Automatically create users
-auths.sspi_auto_create_users_helper = Allow SSPI auth method to automatically create new accounts for users that login for the first time
-auths.sspi_auto_activate_users = Automatically activate users
-auths.sspi_auto_activate_users_helper = Allow SSPI auth method to automatically activate new users
-auths.sspi_strip_domain_names = Remove domain names from usernames
-auths.sspi_strip_domain_names_helper = If checked, domain names will be removed from logon names (eg. "DOMAIN\user" and "user@example.org" both will become just "user").
-auths.sspi_separator_replacement = Separator to use instead of \, / and @
-auths.sspi_separator_replacement_helper = The character to use to replace the separators of down-level logon names (eg. the \ in "DOMAIN\user") and user principal names (eg. the @ in "user@example.org").
-auths.sspi_default_language = Default user language
-auths.sspi_default_language_helper = Default language for users automatically created by SSPI auth method. Leave empty if you prefer language to be automatically detected.
auths.tips = Tips
auths.tips.gmail_settings = Gmail settings:
auths.tips.oauth2.general = OAuth2 authentication
@@ -3739,7 +3758,7 @@ rpm.repository.multiple_groups = This package is available in multiple groups.
alt.registry = Setup this registry from the command line:
alt.registry.install = To install the package, run the following command:
alt.install = Install package
-alt.setup = Add a repository to the list of connected repositories (choose the necessary architecture instead of '_arch_'):
+alt.setup = Add a repository to the list of connected repositories (choose the necessary architecture instead of "_arch_"):
alt.repository = Repository info
alt.repository.architectures = Architectures
alt.repository.multiple_groups = This package is available in multiple groups.
diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini
index 4ade0821a1..8b29ef0f4a 100644
--- a/options/locale/locale_es-ES.ini
+++ b/options/locale/locale_es-ES.ini
@@ -110,7 +110,7 @@ preview=Vista previa
loading=Cargando…
error=Error
-error404=La página a la que está intentando acceder o no existe o no está autorizado para verla.
+error404=La página a la que está intentando acceder no existe,ha sido eliminada o no está autorizado a verla.
go_back=Volver
never=Nunca
@@ -206,6 +206,9 @@ table_modal.placeholder.header = Cabecera
table_modal.label.rows = Filas
table_modal.label.columns = Columnas
table_modal.placeholder.content = Contenido
+link_modal.header = Añadir enlace
+link_modal.description = Descripción
+link_modal.paste_reminder = Pista: Con una URL en tu portapapeles, puedes pegar directamente en el editor para crear un enlace.
[filter]
string.asc=A - Z
@@ -678,6 +681,8 @@ Biography = Biografía
Location = Ubicación
To = Nombre de rama
Website = Sitio web
+username_claiming_cooldown = El nombre de usuario no se puede reclamar, debido a que su periodo de protección no ha terminado aún. Puede ser reclamado el %[1]s.
+email_domain_is_not_allowed = El dominio de la dirección de correo electrónico del usuario %s entra en conflicto con EMAL_DOMAIN_ALLOWLIST o EMAIL_DOMAIN_BLOCKLIST. Asegúrese de que ha establecido la dirección de correo electrónico correctamente.
[user]
@@ -1055,6 +1060,7 @@ language.description = Este idioma se guardará en tu cuenta y se utilizará com
language.localization_project = ¡Ayúdanos a traducir Forgejo a tu idioma! Más información.
pronouns_custom_label = Pronombres personalizados
user_block_yourself = No puedes bloquearte a tí mismo.
+quota = Cuota
[repo]
owner=Propietario
diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini
index 4045495f10..804b48b2b2 100644
--- a/options/locale/locale_fa-IR.ini
+++ b/options/locale/locale_fa-IR.ini
@@ -85,7 +85,7 @@ preview=پیش نمایش
loading=بارگذاری…
error=خطا
-error404=صفحه موردنظر شما یا وجود ندارد یا شما دسترسی کافی برای مشاهده آن را ندارید.
+error404=صفحه موردنظر که شما تلاش دارید به آن دسترسی پیدا کنید وجود ندارد یا حذف شده است یا شما دسترسی کافی برای مشاهده آن را ندارید.
never=هرگز
@@ -112,7 +112,7 @@ new_project_column = ستون جدید
retry = سعی دوباره
rerun = اجرای دوباره
rerun_all = اجرای دوباره تمام کارها
-rss_feed = خوراک RSS
+rss_feed = خوراک آراساس
pin = سنجاق
unpin = برداشتن سنجاق
locked = قفل شده
@@ -170,15 +170,59 @@ remove_label_str = حذف مورد "%s"
view = نما
[aria]
+footer.software = درباره این نرمافزار
+navbar = نوار ناوبری
+footer.links = پیوندها
+footer = پاورقی
[heatmap]
+contributions_zero = بدون همکاری
+contributions_format = {همکاری} در {روز}{ماه}{سال}
+contributions_one = همکاری
+contributions_few = همکاریها
+number_of_contributions_in_the_last_12_months = %s همکاری در ۱۲ ماه گذشته
+less = کمتر
+more = بیشتر
[editor]
+buttons.list.ordered.tooltip = افزودن یک فهرست شمارهدار
+buttons.ref.tooltip = اشاره به مشکلی یا درخواست واکشی
+table_modal.header = افزودن جدول
+table_modal.placeholder.header = سرآیند
+table_modal.placeholder.content = محتوا
+table_modal.label.rows = ردیفها
+table_modal.label.columns = ستونها
+buttons.unindent.tooltip = اجزا را با یک سطح گروهبندی نکن
+buttons.indent.tooltip = اجزا را با یک سطح گروهبندی کن
+buttons.bold.tooltip = افزودن متن درشت
+buttons.quote.tooltip = افزودن نقلقول
+buttons.link.tooltip = افزودن یک پیوند
+buttons.list.unordered.tooltip = افزودن یک فهرست نقطهای
+buttons.heading.tooltip = افزودن سرصفحه
+buttons.italic.tooltip = افزودن متن کج
+buttons.disable_monospace_font = فونت یکپارچه را غیرفعال کن
+buttons.enable_monospace_font = فونت یکپارچه را فعال کن
+buttons.list.task.tooltip = افزودن یک فهرست کارها
+buttons.new_table.tooltip = افزودن جدول
+buttons.mention.tooltip = یادکردن از کاربر یا گروهی
+buttons.switch_to_legacy.tooltip = به جای آن از ویرایشگر کهنهتر استفاده کن
+buttons.code.tooltip = افزودن کد
+link_modal.header = افزودن پیوند
+link_modal.url = یوآرال
+link_modal.paste_reminder = راهنمایی: با داشتن یک یوآرال در بریدهدان، میتوانید با رونوشت مستقیم آن در ویرایشگرتان یک پیوند بسازید.
+link_modal.description = دیباچه
[filter]
+string.asc = آ - ی
+string.desc = ی - آ
[error]
missing_csrf=درخواست بد: بلیط CSRF ندارد
+not_found = هدف را نمیتوان یافت.
+network_error = خطای شبکه
+report_message = اگر گمان میبرید این اشکال از فورججو است، لطفا در مشکلات در کدبرگ را بگردید یا اگر لازم است یک مشکل باز کنید.
+occurred = خطایی رخ داد
+server_internal = خطای درونی کارساز
[startpage]
app_desc=یک سرویس گیت بیدرد سر و راحت
@@ -188,17 +232,19 @@ lightweight=ابزارک سبک
lightweight_desc=گیتی با حداقل منابع میتوانید برای روی دستگاه Raspberry Pi اجرا شود و مصرف انرژی شما را کاهش دهد!
license=متن باز
license_desc=برو به Forgejo! به ملحق شوید با مشارکت کردن برای این که این پروژه بهتر شود. برای مشارکت کردن خجالت نکشید!
+platform_desc = فورججو برای اجرا بر روی سامانهعاملهای آزاد مانند گنو/لینوکس و بیاسدی آزاد و همچنین معماریهای گوناگون پردازنده ثبات دارد. هر چی میلتان هست انتخاب کنید!
+install_desc = به آسانی اعداد دو دویی را برای سکوی خود اجرا کنید. با داکر آن را ارسال کنید، یا بستهبندی تحویل بگیرید.
[install]
install=نصب و راه اندازی
-title=تنظیمات اولیه
+title=پیکربندی اولیه
docker_helper=اگر گیتی را با داکر اجرا کردهاید، لطفا قبل از هر تغییری مستندات را مطالعه نمایید.
-db_title=تنظیمات پایگاه داده
-db_type=نوع پایگاه داده
+db_title=تنظیمات پایگاهداده
+db_type=گونه پایگاهداده
host=میزبان
user=نام کاربری
password=رمز عبور
-db_name=نام پایگاه داده
+db_name=نام پایگاهداده
db_schema=قالب
db_schema_helper=برای مقدار پیش فرض پایگاه داده خالی بگذارید ("public").
ssl_mode=SSL
@@ -213,24 +259,24 @@ err_empty_db_path=مسیر دیتابیس SQLite3 نمیتواند خالی با
no_admin_and_disable_registration=شما بدون ایجاد حساب کاربری مدیر نمیتوانید عضویت را غیر فعال کنید.
err_empty_admin_password=کلمه عبور حساب مدیر نمی تواند خالی باشد.
err_empty_admin_email=رایانامه (ایمیل) مدیر نمی تواند خالی باشد.
-err_admin_name_is_reserved=نام کاربری مدیر اشتباه است. نام کاربری قبلا استفاده شده است
+err_admin_name_is_reserved=نامکاربری مدیر اشتباه است، نامکاربری قبلا استفاده شده است
err_admin_name_pattern_not_allowed=نام کاربری مدیر اشتباه است. نام کاربری قبلا استفاده شده است
err_admin_name_is_invalid=نام کابری مدیر اشتباه است
general_title=تنظیمات عمومی
-app_name=عنوان سایت
-app_name_helper=شما می توانید نام شرکت خود را در اینجا وارد کنید.
+app_name=تیتر نمونه
+app_name_helper=شما می توانید نام نمونه خود را در اینجا وارد کنید. آن در همه برگهها به نمایش در خواهد آمد.
repo_path=مسیر ریشه مخزن
repo_path_helper=تمام مخازن کد راه دور در این پوشه ذخیره میشوند.
-lfs_path=مسیر Git LFS
+lfs_path=مسیر ریشه ذخیرهسازی پرونده بزرگ گیت
lfs_path_helper=فایل هایی که توسط Git LFS دنبال میشوند در این پوشه ذخیره خواهند شد. درصورت خالی بودن فیلد این قابلیت غیرفعال خواهد بود.
-run_user=اجرا به عنوان نام کاربری
-domain=دامنه سرور
+run_user=اجرای کاربر به عنوان
+domain=دامنه کارساز
domain_helper=آدرس میزبان یا دامنه برای سرور.
-ssh_port=پورت SSH سرور
-ssh_port_helper=شماره درگاهی که سرور SSH گوش می دهد. برای غیر فعال کردن خالی بگذارید.
-http_port=پورت HTTP گیتی
-http_port_helper=پورت سرور وب گیتی.
+ssh_port=درگاه کارساز پوستهامن
+ssh_port_helper=شماره درگاهی که سرور پوستهامن استفاده میکند. برای غیر فعال کردن خالی بگذارید.
+http_port=درگاه شنونده اچتیتیپی
+http_port_helper=شماره درگاهی که توسط کارساز وب فرججو استفاده میشود.
app_url=آدرس پایه گیتی
app_url_helper=آدرس پایه برای URLهای اجماع HTTP(S) و هشدار های رایانامه (ایمیل).
log_root_path=مسیر گزارشها
@@ -290,6 +336,10 @@ default_enable_timetracking.description=فعالسازی پیگیری زمان
no_reply_address=مخفی کردن دامنه ایمیل
no_reply_address_helper=نام دامنه برای کاربران دارای آدرس ایمیل پنهان است. به عنوان مثال ، اگر نام دامنه ایمیل مخفی روی "noreply.example.org" تنظیم شده باشد ، نام کاربری "joe" در Git به عنوان "joe@noreply.example.org" وارد می شود
password_algorithm=الگوریتم درهمساز گذرواژه
+require_db_desc = فروججو به مایاسکیوال، پستگریاسکیوال،اسکیولایت۳ یا تیدیبی نیاز دارد.
+run_user_helper = نامکاربری سامانهعامل که با عنوان فرججو اجرا میشود. به یادداشته باشید که کاربر باید دسترسی به مسیر ریشه مخازن داشته باشد.
+app_slogan_helper = شعار نمونه خود را اینجا وارد کنید. برای غیرفعال شدن خالی بگذارید.
+app_slogan = شعار نمونه
[home]
uname_holder=نام کاربری یا نشانی ایمیل
@@ -2715,3 +2765,24 @@ type_tooltip = جستجو گونه
search = جستجو...
fuzzy = درهم
fuzzy_tooltip = پیامدهایی را درج کنید که دقیقا با عبارت جستجو همخوانی داشته باشند
+regexp = عبارات باقاعده
+pull_kind = جستجو واکشیها...
+no_results = نتیجه درخوری یافت نشد.
+runner_kind = جستجو دوندهها...
+keyword_search_unavailable = جستجو کلیدواژه اکنون در درسترس نیست. لطفا با مدیر سایت در میان بگذارید.
+repo_kind = جستجو مخازن...
+regexp_tooltip = اصطلاح جستجو شده را با عبارات باقاعده تفسیر کن
+user_kind = جستجو کاربران...
+org_kind = جستجو سازمانها...
+team_kind = جستجو گروهها...
+package_kind = جستجو بستهها...
+project_kind = جستجو پروژهها...
+code_search_unavailable = جستجوی کد اکنون در دسترس نیست. لطفا با مدیر سایت درمیان بگذارید.
+code_kind = جستجو کدها...
+union = بهم پیوستگی
+union_tooltip = نتایجی را در بر بگیر که با هر یک از کلیدواژههای جدا شده از فضایخالی مطابقت دارد
+branch_kind = جستجو شاخهها...
+commit_kind = جستجو سپردهها...
+issue_kind = جستجو مشکلات...
+exact = مو به مو
+exact_tooltip = نتایجی را در بر بگیر که مو به مو با اصطلاح جستجو شده یکی باشد
diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini
index 6dae1bd947..9c011b7fd1 100644
--- a/options/locale/locale_fi-FI.ini
+++ b/options/locale/locale_fi-FI.ini
@@ -98,7 +98,7 @@ preview=Esikatselu
loading=Ladataan…
error=Virhe
-error404=Sivu, jota yrität nähdä, joko ei löydy tai et ole oikeutettu katsomaan sitä.
+error404=Sivu, jota yrität nähdä, joko ei löydy, on poistettu tai et ole oikeutettu katsomaan sitä.
never=Ei koskaan
@@ -206,6 +206,10 @@ table_modal.placeholder.content = Sisältö
table_modal.label.rows = Rivit
table_modal.label.columns = Sarakkeet
buttons.unindent.tooltip = Vähennä sisennystä yhden tason verran
+link_modal.header = Lisää linkki
+link_modal.url = Osoite
+link_modal.description = Kuvaus
+link_modal.paste_reminder = Vihje: Jos leikepöydällä on URL-osoite, voit liittää suoraan editoriin luodaksesi linkin.
[filter]
string.asc = A - Ö
@@ -535,6 +539,8 @@ admin.new_user.text = Napsauta tästä hallitaksesi tätä käy
repo.collaborator.added.text = Sinut on lisätty avustajaksi repoon:
primary_mail_change.text_1 = Tilisi ensisijaiseksi sähköpostiosoitteeksi asetettiin %[1]s. Se tarkoittaa, että tämä sähköpostiosoite ei enää vastaanota tilisi ilmoituksia sähköpostitse.
team_invite.text_1 = %[1]s on kutsunut sinut liittymään tiimiin %[2]s organisaatiossa %[3]s.
+issue_assigned.pull = @%[1]s osoitti sinulle vetopyynnön %[2]s repossa %[3]s.
+issue_assigned.issue = @%[1]s osoitti sinulle ongelman %[2]s repossa %[3]s.
@@ -618,6 +624,8 @@ unable_verify_ssh_key = SSH-avainta ei voi vahvistaa, tarkista se mahdollisten v
url_error = `"%s" ei ole kelvollinen URL-osoite.`
must_use_public_key = Antamasi avain on yksityinen avain. Älä lähetä yksityistä avaintasi mihinkään. Käytä sen sijaan julkista avaintasi.
still_own_packages = Tilisi omistaa yhden tai useamman paketin, poista ne ensin.
+AccessToken = Pääsypoletti
+enterred_invalid_owner_name = Uuden omistajan nimi ei ole kelvollinen.
[user]
@@ -945,6 +953,21 @@ openid_deletion_desc = Tämän OpenID-osoitteen poistaminen tililtäsi estää k
generate_token_name_duplicate = Nimeä %s on jo käytetty sovelluksen nimenä. Käytä eri nimeä.
ssh_signonly = SSH on tällä hetkellä poistettu käytöstä, joten näitä avaimia käytetään vain kommittien allekirjoituksen vahvistamiseen.
oauth2_applications_desc = OAuth2-sovellukset mahdollistavat käyttämäsi kolmannen osapuolen sovelluksen todentaa turvallisesti käyttäjiä tähän Forgejo-instanssiin.
+quota.sizes.assets.attachments.all = Liitteet
+quota.applies_to_user = Seuraavia kiintiösääntöjä sovelletaan tiliisi
+user_block_yourself = Et voi estää itseäsi.
+quota = Kiintiö
+storage_overview = Tallennustilan yleisnäkymä
+quota.applies_to_org = Seuraavia kiintiösääntöjä sovelletaan tähän organisaatioon
+quota.rule.exceeded = Ylitetty
+quota.rule.no_limit = Rajoittamaton
+quota.sizes.all = Kaikki
+quota.sizes.repos.all = Repot
+quota.sizes.repos.public = Julkiset repot
+quota.sizes.repos.private = Yksityiset repot
+quota.sizes.git.all = Git-sisältö
+quota.sizes.assets.packages.all = Paketit
+quota.sizes.wiki = Wiki
[repo]
owner=Omistaja
@@ -2091,6 +2114,16 @@ template_description = Repojen mallipohjat mahdollistavat uusien repojen luomise
settings.enter_repo_name = Kirjoita omistajan ja repon nimi täsmälleen kuten esitetty:
settings.confirmation_string = Vahvistusteksti
settings.delete_notices_2 = - Tämä toiminto poistaa pysyvästi repon %s mukaan lukien koodin, ongelmat, kommentit, wikidatan ja avustaja-asetukset.
+issues.filter_assginee_no_select = Kaikki käsittelijät
+issues.new.assign_to_me = Osoita itselle
+pulls.closed_at = `sulki tämän vetopyynnön %[2]s`
+tree_path_not_found_branch = Polkua %[1]s ei ole olemassa haarassa %[2]s
+transfer.no_permission_to_reject = Sinulla ei ole oikeutta hylätä tätä siirtoa.
+generate_repo = Luo repo
+tree_path_not_found_commit = Polkua %[1]s ei ole olemassa kommitissa %[2]s
+archive.pull.noreview = Tämä repo on arkistoitu. Et voi katselmoida vetopyyntöjä.
+tree_path_not_found_tag = Polkua %[1]s ei ole olemassa tagissa %[2]s
+transfer.no_permission_to_accept = Sinulla ei ole oikeutta hyväksyä tätä siirtoa.
diff --git a/options/locale/locale_fil.ini b/options/locale/locale_fil.ini
index e35cadb261..12b43f93e9 100644
--- a/options/locale/locale_fil.ini
+++ b/options/locale/locale_fil.ini
@@ -29,7 +29,7 @@ twofa_scratch = Scratch code ng two-factor
sources = Mga Source
collaborative = Pagtutulungan
copy_type_unsupported = Hindi makokopya ang itong uri ng file
-error404 = Ang pahina na sinusubukan mong bisitahin ay alinman hindi umiiral o wala kang pahintulot para itignan.
+error404 = Ang pahina na sinusubukan mong bisitahin ay alinman hindi umiiral, tinanggal o wala kang pahintulot para itignan.
version = Bersyon
powered_by = Pinapatakbo ng %s
explore = Tuklasin
@@ -231,10 +231,10 @@ ssl_mode = SSL
path = Daanan
sqlite_helper = File path para sa SQLite3 database.scope/item
up
issues.archived_label_description = (Naka-archive) %s
issues.label.filter_sort.alphabetically = Ayon sa alpabeto
issues.subscribe = Mag-subscribe
-issues.max_pinned = Hindi ka maaring mag-pin ng higit pang mga isyu
+issues.max_pinned = Hindi ka maaaring mag-pin ng higit pang mga isyu
issues.pin_comment = na-pin ito %s
issues.unpin_comment = na-unpin ito %s
issues.lock = I-lock ang usapan
@@ -1792,7 +1816,7 @@ wiki.last_commit_info = Binago ni %s ang pahinang ito %s
issues.content_history.edited = binago
issues.ref_pull_from = `isinangguni ang hiling sa paghila na ito %[4]s %[2]s`
pulls.merged_title_desc_few = isinali ang %[1]d mga commit mula sa %[2]s
patungong %[3]s
%[4]s
-settings.org_not_allowed_to_be_collaborator = Hindi maaring idagdag ang mga organizasyon bilang tagatulong.
+settings.org_not_allowed_to_be_collaborator = Hindi maaaring idagdag ang mga organisasyon bilang tagatulong.
settings.add_collaborator_success = Naidagdag ang tagatulong.
settings.federation_following_repos = Mga URL ng Mga Sinusundang Repositoryo. Hinihiwalay ng ";", walang whitespace.
diff.comment.reply = Tumugon
@@ -1891,8 +1915,8 @@ issues.dependency.remove_info = Tanggalin ang dependency na ito
issues.dependency.added_dependency = `nagdagdag ng bagong dependency %s`
issues.review.dismissed_label = Nadismiss
issues.review.dismissed = nadismiss ang pagsuri ni %s %s
-issues.review.self.approval = Hindi mo maaring aprubahan ang sarili mong hiling sa paghila.
-issues.review.self.rejection = Hindi mo maaring humiling ng pagbabago sa sarili mong hiling sa paghila.
+issues.review.self.approval = Hindi mo maaaring aprubahan ang sarili mong hiling sa paghila.
+issues.review.self.rejection = Hindi mo maaaring humiling ng pagbabago sa sarili mong hiling sa paghila.
pulls.nothing_to_compare_have_tag = Magkapareho ang mga piniling branch/tag.
issues.dependency.no_permission_1 = Wala kang pahintulot na basahin ang dependency na %d
issues.dependency.no_permission_n = Wala kang pahintulot na basahin ang mga %d dependency
@@ -1926,7 +1950,7 @@ activity.active_prs_count_n = %d aktibong mga hiling sa paghila
issues.author.tooltip.issue = May-akda ng iysung ito ang user.
issues.author.tooltip.pr = May-akda ng hiling sa paghila na ito ang user na ito.
issues.dependency.add_error_dep_exists = Umiiral na and dependency.
-issues.dependency.add_error_cannot_create_circular = Hindi ka maaring gumawa ng dependency na may dalawang isyu na humaharang sa isa't isa.
+issues.dependency.add_error_cannot_create_circular = Hindi ka maaaring gumawa ng dependency na may dalawang isyu na humaharang sa isa't isa.
issues.dependency.add_error_same_issue = Hindi mo magagwang dumepende ang isyu sa sarili.
issues.dependency.add_error_dep_not_same_repo = Dapat nasa katulad na repositoryo ang mga isyu.
issues.dependency.add_error_dep_issue_not_exist = Hindi umiiral ang dumedependeng isyu.
@@ -1945,7 +1969,7 @@ issues.review.show_resolved = Ipakita ang naresolba
issues.review.hide_resolved = Itago ang naresolba
issues.review.resolve_conversation = Iresolba ang paguusap
issues.review.un_resolve_conversation = I-unresolve ang paguusap
-issues.blocked_by_user = Hindi ka maaring gumawa ng isyu sa repositoryo na ito dahil hinarang ka ng may-ari ng repositoryo.
+issues.blocked_by_user = Hindi ka maaaring gumawa ng mga isyu sa repositoryong ito dahil hinarang ka ng may-ari ng repositoryo.
issues.review.show_outdated = Ipakita ang luma
issues.review.hide_outdated = Itago ang luma
issues.review.resolved_by = minarkahan ang paguusap na ito bilang naresolba
@@ -1963,7 +1987,7 @@ wiki.wiki_page_revisions = Mga rebisyon ng pahina
settings.federation_not_enabled = Hindi naka-enable ang federation sa instansya na ito.
pulls.filter_changes_by_commit = I-filter ayon sa commit
settings.githooks = Mga Git hook
-issues.comment.blocked_by_user = Hindi ka makakagawa ng komento sa isyu na ito dahil hinarang ka ng may-ari ng repositoryo o ng gumawa ng isyu.
+issues.comment.blocked_by_user = Hindi ka maaaring gumawa ng komento sa isyu na ito dahil hinarang ka ng may-ari ng repositoryo o ng gumawa ng isyu.
pulls.view = Tignan ang hiling sa paghila
activity.navbar.contributors = Mga contributor
activity.navbar.recent_commits = Mga kamakailang commit
@@ -2042,7 +2066,7 @@ pulls.wrong_commit_id = ang commit id ay dapat ang commit id sa patutunguhan na
pulls.blocked_by_changed_protected_files_1 = Hinarangan ang hiling sa paghila na ito dahil nagbabago ito ng isang nakaprotektang file:
pulls.blocked_by_changed_protected_files_n = Hinarangan ang hiling sa paghila na ito dahil nagbabago ito ng mga nakaprotektang file:
pulls.blocked_by_official_review_requests = Hinarangan ang hiling sa paghila na ito dahil may nawawalang pag-apruba mula sa isa o higit pang mga opisyal na tagasuri.
-pulls.can_auto_merge_desc = Maaring isama ng awtomatiko ang hiling sa paghila na ito.
+pulls.can_auto_merge_desc = Maaaring isama ng awtomatiko ang hiling sa paghila na ito.
pulls.num_conflicting_files_n = %d mga magkasalungat na file
pulls.num_conflicting_files_1 = %d magkasalungat na file
issues.review.add_review_requests = humiling ng mga pagsuri mula sa %[1]s %[2]s
@@ -2322,7 +2346,7 @@ settings.convert_confirm = I-convert ang repositoryo
settings.webhook.replay.description_disabled = Para i-replay ang webhook na ito, i-activate ito.
settings.tracker_issue_style.regexp = Regular na Ekspresyon
settings.admin_stats_indexer = Taga-index ng istatistika ng code
-pulls.open_unmerged_pull_exists = `Hindi ka maaring gumawa ng pagbukas-muli na operasyon dahil may nakabinbin na hiling sa paghila (#%d) na may magkatulad na katangian.`
+pulls.open_unmerged_pull_exists = `Hindi ka maaaring gumawa ng pagbukas-muli na operasyon dahil may nakabinbin na hiling sa paghila (#%d) na may magkatulad na katangian.`
milestones.deletion_success = Binura na ang milestone.
pulls.auto_merge_has_pending_schedule = Naiskedyul ni %[1]s na awtomatiko na isama ang hiling sa paghila na ito kapag magtagumpay ang lahat ng mga pagsusuri %[2]s.
issues.summary_card_alt = Pangkalahatang-ideyang card ng isyu na tawag na "%s" sa repositoryong %s
@@ -2390,9 +2414,9 @@ settings.external_wiki_url_desc = Ire-redirect ang mga bisita sa URL ng panlabas
settings.use_external_issue_tracker = Gumamit ng panlabas na tagasubaybay na isyu
settings.wiki_desc = I-enable ang wiki ng repositoryo
settings.trust_model.default.desc = Gamitin ang default na modelo ng pagkatiwala ng repositoryo para sa installation na ito.
-settings.add_webhook.invalid_path = Hindi maaring maglaman ang path ng parte na "." o ".." o walang laman na string. Hindi maaring magsimula o magtapos sa slash.
+settings.add_webhook.invalid_path = Hindi maaaring maglaman ang path ng parte na "." o ".." o walang laman na string. Hindi maaaring magsimula o magtapos sa slash.
settings.webhook_deletion = Tanggalin ang webhook
-settings.add_webhook.invalid_channel_name = Hindi maaring walang laman ang pangalan ng channel ng webhook at hindi maaring maglaman lang ng # na character.
+settings.add_webhook.invalid_channel_name = Hindi maaaring walang laman ang pangalan ng channel ng webhook at hindi maaaring maglaman lang ng # na character.
pulls.update_branch = I-update ang branch sa pamamagitan ng pagsama
pulls.status_checks_show_all = Ipakita ang lahat ng mga pagsusuri
pulls.cmd_instruction_checkout_title = I-checkout
@@ -2445,8 +2469,8 @@ settings.mirror_settings.docs.doc_link_title = Paano ako mag-mirror ng mga repos
settings.pull_mirror_sync_quota_exceeded = Nalagpasan ang quota, hindi hihila ng mga pagbabago.
settings.mirror_settings.push_mirror.none_ssh = Wala
settings.mirror_settings.push_mirror.copy_public_key = Kopyahin ang publikong key
-pulls.delete_after_merge.head_branch.is_protected = Ang head branch na gusto mong burahin ay isang pinoprotektahang branch at hindi maaring burahin.
-pulls.delete_after_merge.head_branch.is_default = Ang head branch na gusto mong burahin ay ang default branch at hindi maaring burahin.
+pulls.delete_after_merge.head_branch.is_protected = Ang head branch na gusto mong burahin ay isang pinoprotektahang branch at hindi maaaring burahin.
+pulls.delete_after_merge.head_branch.is_default = Ang head branch na gusto mong burahin ay ang default branch at hindi maaaring burahin.
issues.num_reviews_few = %d mga pagsusuri
issues.num_reviews_one = %d pagsusuri
diff.image.swipe = I-swipe
@@ -2469,7 +2493,7 @@ diff.comment.add_single_comment = Magdagdag ng iisang komento
diff.comment.placeholder = Mag-iwan ng komento
release.detail = Mga detalye sa release
release.tags = Mga tag
-release.title_empty = Hindi maaring walang laman ang paksa.
+release.title_empty = Hindi maaaring walang laman ang paksa.
branch.included_desc = Ang branch na ito ay kabilang ng default branch
release.source_code = Source code
release.edit_subheader = Inaayos ng mga release ang mga bersyon ng proyekto.
@@ -2512,8 +2536,8 @@ settings.block_outdated_branch_desc = Hindi magiging posible ang pagsasama kung
settings.block_rejected_reviews_desc = Hindi magiging posible ang pagsasama kapag may mga hiniling ng pagbabago ang mga opisyal na tagasuri, kahit na may sapat na pagapruba.
settings.block_on_official_review_requests = Harangan ang merge sa opisyal na hiling sa pagsuri
settings.tags.protection.allowed = Pinapayagan
-settings.lfs_delete_warning = Ang pagbura ng LFS file ay maaring magdulot ng mga "object does not exist" na error sa checkout. Sigurado ka ba?
-settings.protected_branch_required_approvals_min = Hindi maaring negatibo ang mga kinakailangang pagapruba.
+settings.lfs_delete_warning = Ang pagbura ng LFS file ay maaaring magdulot ng mga "object does not exist" na error sa checkout. Sigurado ka ba?
+settings.protected_branch_required_approvals_min = Hindi maaaring negatibo ang mga kinakailangang pagapruba.
settings.lfs_lock_path = File path na kakandaduhin…
settings.lfs_force_unlock = Pilitin ang pag-unlock
settings.lfs_pointers.accessible = Naa-access ng user
@@ -2524,7 +2548,7 @@ settings.protect_merge_whitelist_users = Mga naka-whitelist na user para sa pags
settings.protect_merge_whitelist_teams = Mga naka-whitelist na koponan para sa pagsasama
settings.protect_check_status_contexts = I-enable ang pagsusuri ng estado
settings.protect_status_check_patterns = Mga pattern sa pagsusuri ng estado
-settings.protect_status_check_patterns_desc = Ilagay ang mga pattern para i-specify kung aling mga pagsusuri ng estado na kailangang magpasa bago maisama ang mga branch sa isang branch na tumutugma sa rule na ito. Nagse-specify ang bawat linya ng pattern. Hindi maaring walang laman ang mga pattern.
+settings.protect_status_check_patterns_desc = Ilagay ang mga pattern para i-specify kung aling mga pagsusuri ng estado na kailangang magpasa bago maisama ang mga branch sa isang branch na tumutugma sa rule na ito. Nagse-specify ang bawat linya ng pattern. Hindi maaaring walang laman ang mga pattern.
settings.protect_check_status_contexts_list = Mga pagsusuri ng estado na nahanap sa huling linggo para sa repositoryo na ito
diff.generated = na-generate
branch.confirm_create_branch = Gumawa ng branch
@@ -2674,9 +2698,9 @@ settings.protected_branch_deletion_desc = Ang pag-disable ng branch protection a
settings.rename_branch_failed_protected = Hindi mababago ang pangalan ng branch na %s dahil ito ay isang nakaprotektang branch.
editor.add_tmpl.filename = Pangalan ng file
settings.protect_approvals_whitelist_users = Mga naka-whitelist na tagasuri
-settings.protect_protected_file_patterns_desc = Ang mga nakaprotektang file ay hindi pinapayagan na direktang mabago kahit na may karapatan ang user na magdagdag, i-edit, o burahin ang mga file sa branch na ito. Ang mga maraming pattern ay maaring mahiwalay gamit ng semicolon (";"). Tignan ang %[2]s na dokumentasyon para sa pattern syntax. Mga halimbawa: .drone.yml
, /docs/**/*.txt
.
-branch.delete_branch_has_new_commits = Hindi maaring burahin ang branch na "%s" dahil may mga bagong commit na nadagdag matapos ang pagsasama.
-settings.protect_unprotected_file_patterns_desc = Ang mga hindi nakaprotektang file ay pinapayagan na direktang mabago kung may write access ang user, bina-bypass ang restriction ng pagtulak. Ang mga maraming pattern ay maaring mahiwalay gamit ng semicolon (";"). Tignan ang %[2]s na dokumentasyon para sa pattern syntax. Mga halimbawa: .drone.yml
, /docs/**/*.txt
.
+settings.protect_protected_file_patterns_desc = Ang mga nakaprotektang file ay hindi pinapayagan na direktang mabago kahit na may karapatan ang user na magdagdag, i-edit, o burahin ang mga file sa branch na ito. Ang mga maraming pattern ay maaaring mahiwalay gamit ng semicolon (";"). Tignan ang %[2]s na dokumentasyon para sa pattern syntax. Mga halimbawa: .drone.yml
, /docs/**/*.txt
.
+branch.delete_branch_has_new_commits = Hindi maaaring burahin ang branch na "%s" dahil may mga bagong commit na nadagdag matapos ang pagsasama.
+settings.protect_unprotected_file_patterns_desc = Ang mga hindi nakaprotektang file ay pinapayagan na direktang mabago kung may write access ang user, bina-bypass ang restriction ng pagtulak. Ang mga maraming pattern ay maaaring mahiwalay gamit ng semicolon (";"). Tignan ang %[2]s na dokumentasyon para sa pattern syntax. Mga halimbawa: .drone.yml
, /docs/**/*.txt
.
settings.no_protected_branch = Walang mga nakaprotekta na branch.
settings.protected_branch_required_rule_name = Kinakailangan na pangalan ng rule
settings.protected_branch_duplicate_rule_name = Mayroon nang rule para sa set ng mga branch na ito
@@ -2692,7 +2716,7 @@ branch.branch_name_conflict = Sumasalungat ang pangalan ng branch na "%s" sa umi
branch.protected_deletion_failed = Nakaprotekta ang branch na "%s". Hindi ito mabubura.
diff.file_after = Pagkatapos
release.deletion_tag_desc = Buburahin ang tag na ito sa repositoryo. Mapapanatiling hindi nabago ang nilalaman at kasaysayan ng repositoryo. Magpatuloy?
-topic.format_prompt = Dapat magsimula ang mga topic ng numero o letra, maaring magsama ng mga dash ("-") at dot ("."), maaring hanggang sa 35 na character na haba. Kailangang lowercase ang mga character.
+topic.format_prompt = Dapat magsimula ang mga topic ng numero o letra, maaaring magsama ng mga dash ("-") at dot ("."), maaaring hanggang sa 35 na character na haba. Kailangang lowercase ang mga character.
branch.new_branch_from = Gumawa ng bagong branch mula sa "%s"
error.csv.unexpected = Hindi ma-render ang file na ito dahil naglalaman ito ng hindi inaasahang character sa linyang %d at column %d.
settings.ignore_stale_approvals_desc = Huwag ibilang ang mga pagapruba na ginawa sa mga lumang commit (mga lipas na pagsusuri) sa kung gaano karaming pagapruba ang mayroon sa PR na ito. Walang kinalaman kung ang mga lipas na pagsusuri ay na-dismiss na.
@@ -2735,6 +2759,10 @@ archive.pull.noreview = Naka-archive ang repositoryong ito. Hindi ka makakasuri
commits.view_single_diff = Tignan ang mga pagbabago sa file na ito na ipinakilala sa commit na ito
pulls.editable = Nababago
pulls.editable_explanation = Pinapayagan ng hiling sa paghila na ito ang mga pagbabago mula sa mga tagapangasiwa. Maaari kang direktang mag-ambag dito.
+issues.reopen.blocked_by_user = Hindi mo maaaring buksan muli ang isyung ito dahil hinarang ka ng may-ari ng repositoryo o ng may-akda ng isyung ito.
+pulls.comment.blocked_by_user = Hindi ka maaaring magkomento sa hiling sa paghila na ito dahil hinarang ka ng may-ari ng repositoryo o ng may-akda ng hiling sa paghila.
+issues.filter_no_results = Walang mga resulta
+issues.filter_no_results_placeholder = Subukang ayusin ang iyong mga filter sa paghahanap.
[search]
commit_kind = Maghanap ng mga commit…
@@ -2845,11 +2873,11 @@ users.repos = Mga Repo
users.send_register_notify = Abisuhan tungkol sa pagrehistro sa pamamagitan ng email
users.is_admin = Tagapangasiwa na account
users.is_restricted = Pinaghihigpitang account
-users.allow_import_local = Maaring mag-import ng mga lokal na repositoryo
+users.allow_import_local = Maaaring mag-import ng mga lokal na repositoryo
users.allow_create_organization = Makakagawa ng mga organisasyon
users.update_profile = I-update ang user account
users.delete_account = Burahin ang user account
-users.cannot_delete_self = Hindi mo maaring burahin ang sarili mo
+users.cannot_delete_self = Hindi mo maaaring burahin ang sarili mo
users.still_own_repo = Ang user na ito ay nagmamay-ari pa ng isa o higit pang mga repositoryo. Burahin o ilipat sila muna.
users.list_status_filter.is_active = Aktibo
users.list_status_filter.not_active = Hindi aktibo
@@ -3120,7 +3148,7 @@ config.allow_dots_in_usernames = Payagan ang mga user na gumamit ng mga dot sa k
config.https_only = HTTPS lamang
auths.tip.github = Magrehistro ng bagong OAuth application sa %s
auths.tip.gitlab_new = Magrehistro ng bagong application sa %s
-emails.delete_primary_email_error = Hindi mo maaring burahin ang pangunahing email.
+emails.delete_primary_email_error = Hindi mo maaaring burahin ang pangunahing email.
config.provider_config = Config ng provider
config.cache_test_slow = Matagumpay ang pagsubok ng cache, ngunit mabagal ang tugon: %s.
config.picture_config = Configuration ng larawan at avatar
@@ -3271,7 +3299,7 @@ config.cookie_name = Pangalan ng cookie
config.gc_interval_time = Oras ng pagitan ng GC
config.cookie_life_time = Lifetime ng cookie
config.git_clone_timeout = Timeout ng operasyon na pag-clone
-monitor.process.cancel_desc = Ang pagkansela ng proseso ay maaring magdulot ng pagkawalan ng data
+monitor.process.cancel_desc = Ang pagkansela ng proseso ay maaaring magdulot ng pagkawalan ng data
monitor.queue.name = Pangalan
auths.oauth2_required_claim_value_helper = Itakda ang value na ito upang i-restrict ang pag-login mula sa pinagmulang ito sa mga user na may claim na may ganitong pangalan at value
auths.tip.bitbucket = Magrehistro ng bagong OAuth consumer sa %s at idagdag ang pahintulot na "Account" - "Read"
@@ -3358,7 +3386,7 @@ members.member = Miyembro
members.private_helper = Gawing visible
settings.location = Lokasyon
settings.update_setting_success = Nabago na ang mga setting ng organisasyon.
-teams.can_create_org_repo_helper = Maaring gumawa ang mga miyembro ng mga bagong repositoryo sa organisasyon. Magkakaroon ng tagapangasiwa na access ang tagagawa sa bagong repositoryo.
+teams.can_create_org_repo_helper = Maaaring gumawa ang mga miyembro ng mga bagong repositoryo sa organisasyon. Magkakaroon ng tagapangasiwa na access ang tagagawa sa bagong repositoryo.
settings.change_orgname_prompt = Tandaan: Ang pagpalit ng pangalan ng organisasyon ay papalitan din ang URL ng organisasyon at mapapalaya ang lumang pangalan.
settings.labels_desc = Magdagdag ng mga label na magagamit sa mga isyu para sa lahat ng mga repositoryo sa ilalim ng organisasyon.
members.public_helper = Gawing nakatago
@@ -3583,7 +3611,7 @@ search_in_external_registry = Maghanap sa %s
alt.registry = I-setup ang registry na ito mula sa command line:
alt.registry.install = Para i-install ang package na ito, patakbuhin ang sumusunod na command:
alt.install = I-install ang package
-alt.setup = Idagdag ang repositoryo sa listahan ng mga nakakonektang repositoryo (piliin ang kinakailangang architechture sa halip ng '_arch_'):
+alt.setup = Idagdag ang repositoryo sa listahan ng mga nakakonektang repositoryo (piliin ang kinakailangang architechture sa halip ng "_arch_"):
alt.repository = Info ng repositoryo
alt.repository.architectures = Mga architechture
alt.repository.multiple_groups = Available ang package na ito sa iba't ibang grupo.
@@ -3641,7 +3669,7 @@ variables.deletion.description = Permanente ang pagtanggal ng isang variable at
status.running = Tumatakbo
runners.new_notice = Paano magsimula ng runner
runners.update_runner_success = Matagumpay na na-update ang runner
-runners.delete_runner_notice = Kapag may trabaho na tumatakbo sa runner na ito, titigilan ito at mamarkahan bilang nabigo. Maaring sirain ang building workflow.
+runners.delete_runner_notice = Kapag may trabaho na tumatakbo sa runner na ito, titigilan ito at mamarkahan bilang nabigo. Maaaring sirain ang building workflow.
runners.none = Walang mga available na runner
runs.status_no_select = Lahat ng status
runs.empty_commit_message = (walang laman na mensahe ng commit)
@@ -3781,7 +3809,7 @@ error.unit_not_allowed = Hindi ka pinapayagang ma-access ang seksyon ng reposito
[dropzone]
default_message = I-drop ang mga file o mag-click dito para mag-upload.
-invalid_input_type = Hindi ka maaring mag-upload ng mga file sa uri na ito.
+invalid_input_type = Hindi ka maaaring mag-upload ng mga file sa uri na ito.
file_too_big = Ang laki ng file ({{filesize}}) MB) ay lumalagpas sa pinakamataas na size na ({{maxFilesize}} MB).
remove_file = Tanggalin ang file
diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini
index bdc30e57d7..42f05bb0c7 100644
--- a/options/locale/locale_fr-FR.ini
+++ b/options/locale/locale_fr-FR.ini
@@ -112,7 +112,7 @@ preview=Aperçu
loading=Chargement…
error=Erreur
-error404=La page que vous essayez d'atteindre n'existe pas ou vous n'êtes pas autorisé à la voir.
+error404=La page que vous essayez d'atteindre n'existe pas, a été supprimé ou vous n'êtes pas autorisé à la voir.
go_back=Retour
never=Jamais
@@ -205,6 +205,8 @@ table_modal.placeholder.header = Entête
table_modal.placeholder.content = Contenu
table_modal.label.rows = Lignes
table_modal.label.columns = Colonnes
+link_modal.header = Ajouter un lien
+link_modal.url = Url
[filter]
string.asc=A - Z
@@ -3836,7 +3838,7 @@ alt.registry = Configurez ce registre à partir d'un terminal :
alt.registry.install = Pour installer le paquet, exécutez la commande suivante :
alt.install = Installer le paquet
alt.repository.multiple_groups = Ce paquet est disponible dans plusieurs groupes.
-alt.setup = Ajouter un dépôt à la liste des dépôts connectés (choisir l'architecture nécessaire au lieu de '_arch_') :
+alt.setup = Ajouter un dépôt à la liste des dépôts connecté (choisissez l'architecture nécessaire à la place de '_arch') :
[secrets]
secrets=Secrets
diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini
index b7372e12f2..d2d960b627 100644
--- a/options/locale/locale_ga-IE.ini
+++ b/options/locale/locale_ga-IE.ini
@@ -19,8 +19,8 @@ language = Teanga
notifications = Fógraí
active_stopwatch = Rianaitheoir Ama Gníomhach
tracked_time_summary = Achoimre ar an am rianaithe bunaithe ar scagairí an liosta eisiúna
-create_new = Cruthaigh...
-user_profile_and_more = Próifíl agus Socruithe...
+create_new = Cruthaigh…
+user_profile_and_more = Próifíl agus Socruithe…
signed_in_as = Sínithe isteach mar
enable_javascript = Éilíonn JavaScript ar an suíomh Gréasáin seo.
toc = Tábla na nÁbhar
diff --git a/options/locale/locale_gl.ini b/options/locale/locale_gl.ini
index 6583eca499..75763775eb 100644
--- a/options/locale/locale_gl.ini
+++ b/options/locale/locale_gl.ini
@@ -187,6 +187,9 @@ buttons.switch_to_legacy.tooltip = Utilizar o editor herdado
buttons.new_table.tooltip = Engadir táboa
table_modal.header = Engadir táboa
table_modal.placeholder.header = Cabeceira
+link_modal.header = Engadir ligazón
+link_modal.url = Url
+link_modal.description = Descrición
[search]
@@ -221,6 +224,7 @@ platform = Multiplataforma
app_desc = Um servizo Git autoxestionado e fácil de usar
install = Fácil de instalar
install_desc = Simplemente executa o binario para a túa plataforma, envíao con Docker ou consígueo empaquetado.
+license = Código aberto
[error]
occurred = Ocorreu un erro
@@ -264,4 +268,26 @@ sqlite_helper = Ruta do ficheiro para a base de datos SQLite3.{index}
vietā.
+settings.tracker_issue_style.regexp_pattern=Regulārās izteiksmes paraugs
+settings.tracker_issue_style.regexp_pattern_desc=Pirmā tveramā kopa tiks izmantota {index}
vietā.
settings.tracker_url_format_desc=Var izmantot vietturus {user}
, {repo}
un {index}
lietotājvārdam, glabātavas nosaukumam un pieteikuma indeksam.
settings.enable_timetracker=Iespējot laika uzskaiti
settings.allow_only_contributors_to_track_time=Atļaut uzskaitīt laiku tikai līdzdalībniekiem
@@ -2217,10 +2241,10 @@ settings.convert_fork_desc=Šo atzarojumu var pārveidot par parastu glabātavu.
settings.convert_fork_notices_1=Šī darbība pārveidos atzarojumu par parastu glabātavu, un tā nav atsaucama.
settings.convert_fork_confirm=Pārveidot glabātavu
settings.convert_fork_succeed=Atzarojums tika pārveidots par parastu glabātavu.
-settings.transfer.title=Mainīt īpašnieku
+settings.transfer.title=Nodot īpašumtiesības
settings.transfer.rejected=Glabātavas nodošana tika noraidīta.
settings.transfer.success=Glabātavas nodošana bija sekmīga.
-settings.transfer_abort=Atcelt īpašnieka maiņu
+settings.transfer_abort=Atcelt nodošanu
settings.transfer_abort_invalid=Nevar atcelt neesošu glabātavas nodošanu.
settings.transfer_abort_success=Glabātavas nodošana %s tika sekmīgi atcelta.
settings.transfer_desc=Nodot šo glabātavu lietotājam vai apvienībai, kurā Tev ir pārvaldītāja tiesības.
@@ -2333,7 +2357,7 @@ settings.event_push_desc=Git aizgādāšana uz glabātavu.
settings.event_repository=Glabātava
settings.event_repository_desc=Izveidota vai izdzēsta glabātava.
settings.event_header_issue=Pieteikumu notikumi
-settings.event_issues=Izmainīšana
+settings.event_issues=Izmaiņas
settings.event_issues_desc=Pieteikums atvērts, aizvērts, atkārtoti atvērts vai labots.
settings.event_issue_assign=Piešķīrums
settings.event_issue_assign_desc=Pieteikumam ir norādīts vai noņemts atbildīgais.
@@ -2444,7 +2468,7 @@ settings.protect_status_check_patterns_desc=Jāievada paraugi, lai norādītu, k
settings.protect_check_status_contexts_desc=Pirms apvienošanas ir nepieciešama sekmīga stāvokļa pārbaužu izpilde. Kad iespējots, iesūtījumiem vispirms jābūt aizgādātiem citā zarā, tad pēc stāvokļa pārbaužu sekmīgas izpildes iekļautiem vai aizgādātiem tieši zarā, kas atbilst šai kārtulai. Ja nav atbilstošu kontekstu, pēdējam iesūtījumam jābūt sekmīgam neatkarīgi no konteksta.
settings.protect_check_status_contexts_list=Stāvokļa pārbaudes, kas šajā glabātavā atrastas pēdējās nedēļas laikā
settings.protect_status_check_matched=Atbilst
-settings.protect_invalid_status_check_pattern=Kļūdains statusa pārbaudes šablons: "%s".
+settings.protect_invalid_status_check_pattern=Nederīgs stāvokļa pārbaudes paraugs: "%s".
settings.protect_no_valid_status_check_patterns=Nav derīgu stāvokļa pārbaužu paraugu.
settings.protect_required_approvals=Nepieciešamie apstiprinājumi
settings.protect_required_approvals_desc=Atļaut iekļaut izmaiņu pieprasījumu tikai ar pietiekamu daudzumu apstiprinošu izskatīšanu.
@@ -2458,7 +2482,7 @@ settings.require_signed_commits=Pieprasīt parakstītus iesūtījumus
settings.require_signed_commits_desc=Noraidīt aizgādāšanu uz šo zaru, ja iesūtījumi nav parakstīti vai apliecināmi.
settings.protect_branch_name_pattern=Aizsargātā zara nosaukuma paraugs
settings.protect_branch_name_pattern_desc=Aizsargāto zaru nosaukumu paraugi. Paraugu pierakstu skatīt dokumentācijā. Piemēri: main, release/**
-settings.protect_patterns=Šabloni
+settings.protect_patterns=Paraugi
settings.protect_protected_file_patterns=Aizsargāto datņu paraugs (vairākus atdala ar semikolu ";")
settings.protect_protected_file_patterns_desc=Aizsargātās datnes nav ļauts tiešā veidā mainīt, pat ja lietotājam šajā zarā ir tiesības pievienot, labot vai izdzēst datnes. Vairākus paraugus var atdalīt ar semikolu (";"). Paraugu pieraksts ir skatāms %[2]s dokumentācijā. Piemēri: .drone.yml
, /docs/**/*.txt
.
settings.protect_unprotected_file_patterns=Neaizsargāto datņu paraugs (vairākus atdala ar semikolu ";")
@@ -2471,9 +2495,9 @@ settings.remove_protected_branch_failed=Zara aizsargāšanas kārtulas "%s" noņ
settings.protected_branch_deletion=Izdzēst zara aizsargāšanu
settings.protected_branch_deletion_desc=Zara aizsargāšanas atspējošana ļauj lietotājiem ar rakstīšanas atļauju aizgādāt zarā izmaiņas. Turpināt?
settings.block_rejected_reviews=Liegt apvienošanu, ja izskatīšana ir beigusies ar noraidīšanu
-settings.block_rejected_reviews_desc=Apvienošana nebūs iespējama, kad oficiālie izskatītāji ir pieprasījuši izmaiņas, pat ja ir pietiekami daudz apstiprinājumu.
+settings.block_rejected_reviews_desc=Apvienošana nebūs iespējama, kad oficiālie izskatītāji gūs pieprasījuši izmaiņas, pat ja ir pietiekami daudz apstiprinājumu.
settings.block_on_official_review_requests=Liegt apvienošanu, ja ir oficiāli izskatīšanas pieprasījumi
-settings.block_on_official_review_requests_desc=Apvienošana nebūs iespējama, ja ir oficiāli izskatīšanas pieprasījumi, pat ja ir pietiekami daudz apstiprinājumu.
+settings.block_on_official_review_requests_desc=Apvienošana nebūs iespējama, ja būs oficiāli izskatīšanas pieprasījumi, pat ja būs pietiekami daudz apstiprinājumu.
settings.block_outdated_branch=Liegt apvienošanu, ja izmaiņu pieprasījums ir novecojis
settings.block_outdated_branch_desc=Apvienošana nebūs iespējama, ja zars būs atpalicis no pamata zara.
settings.default_branch_desc=Atlasīt noklusējuma glabātavas zaru izmaiņu pieprasījumiem un koda iesūtījumiem:
@@ -2517,7 +2541,7 @@ settings.unarchive.error=Glabātavas arhivēšanas atcelšanas laikā atgadījā
settings.update_avatar_success=Glabātavas attēls tika atjaunināts.
settings.lfs=LFS
settings.lfs_filelist=Šajā glabātavā uzglabātās LFS datnes
-settings.lfs_no_lfs_files=Šajā glabātavā nav uzglabātu LFS datņu
+settings.lfs_no_lfs_files=Šajā glabātavā netiek glabātas LFS datnes
settings.lfs_findcommits=Atrast iesūtījumus
settings.lfs_lfs_file_no_commits=Šai LFS datnei netika atrasts neviens iesūtījums
settings.lfs_noattribute=Šim ceļam noklusējuma zarā nav slēdzamības atribūta
@@ -2533,8 +2557,8 @@ settings.lfs_lock_path=Slēdzamās datnes ceļš...
settings.lfs_locks_no_locks=Nav slēdzeņu
settings.lfs_lock_file_no_exist=Aizslēgtā datne nepastāv noklusējuma zarā
settings.lfs_force_unlock=Uzspiest atslēgšanu
-settings.lfs_pointers.found=Atrasta(s) %d binārā objekta norāde(s) - %d saistītas, %d nesaistītas (%d trūkstošas glabātuvē)
-settings.lfs_pointers.sha=Binārā objekta jaucējkods
+settings.lfs_pointers.found=Atrasta(s) %d binārā objekta norāde(s) - %d saistīta(s), %d nesaistīta(s) (%d trūkst krātuvē)
+settings.lfs_pointers.sha=Binārā objekta jaucējvirkne
settings.lfs_pointers.oid=OID
settings.lfs_pointers.inRepo=Glabātavā
settings.lfs_pointers.exists=Pastāv krātuvē
@@ -2564,7 +2588,7 @@ diff.whitespace_ignore_all_whitespace=Neņemt vērā atstarpes, kad tiek salīdz
diff.whitespace_ignore_amount_changes=Neņemt vērā atstarpju daudzuma izmaiņas
diff.whitespace_ignore_at_eol=Neņemt vērā atstarpju izmaiņas rindu beigās
diff.stats_desc=%d izmainītas datnes ar %d papildinājumiem un %d izdzēšanām
-diff.stats_desc_file=%d izmaiņas: %d pievienotas un %d dzēstas
+diff.stats_desc_file=%d izmaiņas: %d pievienošanas un %d izdzēšanas
diff.bin=Binārs
diff.bin_not_shown=Binārā datne netiek rādīta.
diff.view_file=Apskatīt datni
@@ -2615,7 +2639,7 @@ release.stable=Stabila
release.compare=Salīdzināt
release.edit=Labot
release.ahead.commits=%d iesūtījumi
-release.ahead.target=no %s kopš laidiena publicēšanas
+release.ahead.target=%s kopš šī laidiena laišanas klajā
tag.ahead.target=%s kopš šīs birkas
release.source_code=Pirmkods
release.new_subheader=Laidieni apkopo projekta versijas.
@@ -2629,7 +2653,7 @@ release.title=Laidiena nosaukums
release.title_empty=Nosaukums nevar būt tukšs.
release.message=Aprakstīt šo laidienu
release.prerelease_desc=Atzīmēt kā pirmsizlaidi
-release.prerelease_helper=Atzīmēt, ka šo laidienu nav ieteicams lietot produkcijā.
+release.prerelease_helper=Atzīmēt šo laidienu kā nepiemērotu izmantošanai produkcijā.
release.cancel=Atcelt
release.publish=Laist klajā laidienu
release.save_draft=Saglabāt melnrakstu
@@ -2640,10 +2664,10 @@ release.deletion=Izdzēst laidienu
release.deletion_desc=Laidiena izdzēšana tikai noņem to no Forgejo. Tā neietekmēs Git birku, glabātavas saturu vai vēsturi. Turpināt?
release.deletion_success=Laidiens tika izdzēsts.
release.deletion_tag_desc=Šī birka tiks izdzēsta no glabātavas. Glabātavas saturs un vēsture paliks nemainīta. Turpināt?
-release.deletion_tag_success=Tags tika izdzēsts.
+release.deletion_tag_success=Birka tika izdzēsta.
release.tag_name_already_exist=Laidiens ar šādu birkas nosaukumu jau pastāv.
release.tag_name_invalid=Nederīgs birkas nosaukums.
-release.tag_name_protected=Taga nosaukums ir aizsargāts.
+release.tag_name_protected=Birkas nosaukums ir aizsargāts.
release.tag_already_exist=Šāds birkas nosaukums jau pastāv.
release.downloads=Lejupielādes
release.download_count=Lejupielādes: %s
@@ -2693,7 +2717,7 @@ tag.create_tag_operation=Izveidot birku
tag.confirm_create_tag=Izveidot birku
tag.create_tag_from=Izveidot jaunu birku no "%s"
-tag.create_success=Tags "%s" tika izveidots.
+tag.create_success=Birka "%s" tika izveidota.
topic.manage_topics=Pārvaldīt tēmas
topic.done=Gatavs
@@ -2875,6 +2899,10 @@ editor.commit_email = Iesūtījuma e-pasta adrese
commits.view_single_diff = Apskatīt šajā datnē veiktās izmaiņas šajā iesūtījumā
pulls.editable = Labojams
pulls.editable_explanation = Šis izmaiņu pieprasījums pieļauj labojumus no uzturētājiem. Tu vari tieši līdzdarboties tajā.
+issues.reopen.blocked_by_user = Tu nevari atkārtoti atvērt šo pieteikumu, jo tā izveidotājs vai glabātavas īpašnieks ir liedzis Tevi.
+pulls.comment.blocked_by_user = Tu šim izmaiņu pieprasījumam nevari pievienot piebildi, jo tā izveidotājs vai glabātavas īpašnieks ir liedzis Tevi.
+issues.filter_no_results = Nav vienumu
+issues.filter_no_results_placeholder = Jāmēģina pielāgot meklēšanas atlasītāji.
[graphs]
component_loading=Ielādē %s...
@@ -2921,7 +2949,7 @@ settings.location=Atrašanās vieta
settings.permission=Tiesības
settings.repoadminchangeteam=Glabātavas pārvaldītājs var pievienot un noņemt komandu piekļuvi
settings.visibility=Redzamība
-settings.visibility.public=Publiska
+settings.visibility.public=Atklāta
settings.visibility.limited=Ierobežota (redzama tikai lietotājiem, kuri ir pieteikušies)
settings.visibility.limited_shortname=Ierobežota
settings.visibility.private=Privāta (redzama tikai apvienības dalībniekiem)
@@ -2946,19 +2974,19 @@ members.membership_visibility=Dalībnieku redzamība:
members.public=Redzams
members.public_helper=Padarīt slēptu
members.private=Slēpts
-members.private_helper=Padarīt redzemu
+members.private_helper=Padarīt redzamu
members.member_role=Dalībnieka loma:
members.owner=Īpašnieks
members.member=Dalībnieks
members.remove=Noņemt
members.remove.detail=Noņemt %[1]s no %[2]s?
-members.leave=Atstāt
+members.leave=Pamest
members.leave.detail=Vai tiešām pamest apvienību "%s"?
-members.invite_desc=Pievienot jaunu dalībnieku pie %s:
+members.invite_desc=Pievienot jaunu dalībnieku %s:
members.invite_now=Uzaicināt tagad
teams.join=Pievienoties
-teams.leave=Atstāt
+teams.leave=Pamest
teams.leave.detail=Vai tiešām pamest komandu "%s"?
teams.can_create_org_repo=Izveidot glabātavas
teams.can_create_org_repo_helper=Dalībnieki apvienībā var izveidot jaunas glabātavas. Izveidotājs iegūs jaunās glabātavas pārvaldītāja piekļuvi.
@@ -2966,11 +2994,11 @@ teams.none_access=Nav piekļuves
teams.none_access_helper="Nav piekļuve" iespēja iedarbojas tikai privātās glabātavās.
teams.general_access=Pielāgota piekļuve
teams.general_access_helper=Komandas tiesības tiks noteiktas pēc tabulas zemāk.
-teams.read_access=Skatīšanās
+teams.read_access=Lasīt
teams.read_access_helper=Komanda varēs skatīties un klonēt šīs organizācijas repozitorijus.
-teams.write_access=Rakstīšanas
+teams.write_access=Rakstīt
teams.write_access_helper=Šī komanda varēs lasīt un nosūtīt izmaiņas uz tās repozitorijiem.
-teams.admin_access=Pārvaldītaja piekļuve
+teams.admin_access=Pārvaldītāja piekļuve
teams.admin_access_helper=Dalībnieki var atgādāt un aizgādāt izmaiņas uz komandas glabātavām un pievienot tām līdzdalībniekus.
teams.no_desc=Komandai nav apraksta
teams.settings=Iestatījumi
@@ -3027,7 +3055,7 @@ authentication=Autentificēšanas avoti
emails=Lietotāju e-pasta adreses
config=Konfigurācija
notices=Sistēmas paziņojumi
-monitor=Uzraudzība
+monitor=Pārraudzīšana
first_page=Pirmā
last_page=Pēdējā
total=Kopā: %d
@@ -3178,8 +3206,8 @@ users.details=Lietotāja informācija
emails.email_manage_panel=Pārvaldīt lietotāju e-pasta adreses
emails.primary=Galvenā
emails.activated=Aktivēta
-emails.filter_sort.email=E-pasts
-emails.filter_sort.email_reverse=E-pasta adrese (pretēji alfabētiski)
+emails.filter_sort.email=E-pasta adrese
+emails.filter_sort.email_reverse=E-pasta adrese (apvērsti)
emails.filter_sort.name=Lietotājvārds
emails.filter_sort.name_reverse=Lietotāja vārds (apvērsti)
emails.updated=E-pasta adrese atjaunināta
@@ -3195,11 +3223,11 @@ orgs.members=Dalībnieki
orgs.new_orga=Jauna apvienība
repos.repo_manage_panel=Pārvaldīt glabātavas
-repos.unadopted=Nepieemtās glabātavas
+repos.unadopted=Nepieņemtās glabātavas
repos.unadopted.no_more=Nav atrasta neviena nepieņemta glabātava.
repos.owner=Īpašnieks
repos.name=Nosaukums
-repos.private=Privāts
+repos.private=Privāta
repos.watches=Vērošana
repos.stars=Zvaigznes
repos.forks=Atdalītie
@@ -3219,7 +3247,7 @@ packages.version=Versija
packages.type=Veids
packages.repository=Glabātava
packages.size=Izmērs
-packages.published=Publicēts
+packages.published=Laista klajā
defaulthooks=Noklusējuma tīmekļa aizķeres
defaulthooks.desc=Tīmekļa aizķeres automātiski nosūta HTTP POST pieprasījumus serverim, kad iestājas noteikti Forgejo notikumi. Šeit esošās tīmekļa aizķeres ir noklusējuma, un tās tiks ievietotas visās jaunajās glabātavās. Vairāk ir lasāms norādēs par tīmekļa aizķerēm.
@@ -3306,7 +3334,7 @@ auths.oauth2_group_claim_name=Prasības nosaukums, kas šim avotam nodrošina gr
auths.oauth2_admin_group=Kopas prasības vērtība pārvaldītājiem. (Izvēles - nepieciešams augstāk esošais prasības nosaukums)
auths.oauth2_restricted_group=Grupas prasības vērtība ierobežotajiem lietotājiem. (Izvēles - nepieciešams augstāk esošais prasības nosaukums)
auths.oauth2_map_group_to_team=Sasaistīt pieprasītās kopas ar apvienības komandām. (Izvēles - nepieciešams augstāk esošais prasības nosaukums)
-auths.oauth2_map_group_to_team_removal=Noņemt lietotājus no sinhronizētajām komandām, ja lietotājs nav piesaistīts attiecīgajai grupai.
+auths.oauth2_map_group_to_team_removal=Noņemt lietotājus no sinhronizētajām komandām, ja lietotājs nav attiecīgajā grupai.
auths.enable_auto_register=Iespējot automātisko reģistrāciju
auths.sspi_auto_create_users=Automātiski izveidot lietotājus
auths.sspi_auto_create_users_helper=Ļauj SSPI autentificēšanās veidam automātiski izveidot jaunus kontus lietotājiem, kas piesakās pirmo reizi
@@ -3334,20 +3362,20 @@ auths.tip.twitter=Jādodas uz %s, jāizveido lietotne un jānodrošina, ka iesp
auths.tip.discord=Jāizveido jauna lietotne %s
auths.tip.gitea=Pievienot jaunu OAuth2 lietotni. Norādes ir atrodamas %s
auths.tip.yandex=%s jāizveido jauna lietotne. Sadaļā "Yandex.Passport API" jāatlasa šīs atļaujas: "Access to email address", "Access to user avatar" un "Access to username, first name and surname, gender"
-auths.tip.mastodon=Jāievada pielāgota Mastodon servera URL, ar kuru vēlies autentificēties (vai jāizmanto noklusējuma)
+auths.tip.mastodon=Jāievada pielāgota Mastodon servera URL, ar kuru ir vēlēšanās autentificēties (vai jāizmanto noklusējuma)
auths.edit=Labot autentificēšanas avotu
-auths.activated=Autentificēšanas avots ir atkivēts
-auths.new_success=Jauna autentifikācija "%s" tika pievienota.
+auths.activated=Šis autentificēšanas avots ir atkivēts
+auths.new_success=Autentificēšanās "%s" tika pievienota.
auths.update_success=Autentificēšanās avots tika atjaunināts.
auths.update=Atjaunināt autentificēšanās avotu
auths.delete=Izdzēst autentificēšanas avotu
auths.delete_auth_title=Izdzēst autentificēšanas avotu
-auths.delete_auth_desc=Izdzēšot autentifikācijas avotu, tā lietotājiem nebūs iespējams pieteikties. Vai turpināt?
+auths.delete_auth_desc=Autentificēšanās avota izdzēšana liedz lietotājiem to izmantot, lai pieteiktos. Turpināt?
auths.still_in_used=Šo autentificēšanās avotu joprojām izmanto viens vai vairāki lietotāji, tos nepieciešams izdzēst vai pārvietot uz citu autentificēšanās avotu.
auths.deletion_success=Autentificēšanās avots tika izdzēsts.
auths.login_source_exist=Jau pastāv autentificēšanās avots "%s".
auths.login_source_of_type_exist=Jau pastāv šāda veida autentificēšanās avots.
-auths.unable_to_initialize_openid=Nevarēja inicializēt OpenID Connect sliedzēju: %s
+auths.unable_to_initialize_openid=Nevarēja sāknēt OpenID Connect sniedzēju: %s
auths.invalid_openIdConnectAutoDiscoveryURL=Nederīgs automātiskās atklāšanas URL (tam jābūt derīgam URL, kas sākas ar http:// vai https://)
config.server_config=Servera konfigurācija
@@ -3500,7 +3528,7 @@ monitor.download_diagnosis_report=Lejupielādēt diagnostikas atskaiti
monitor.desc=Apraksts
monitor.start=Sākuma laiks
monitor.execute_time=Izpildes laiks
-monitor.last_execution_result=Rezultāts
+monitor.last_execution_result=Iznākums
monitor.process.cancel=Atcelt procesu
monitor.process.cancel_desc=Procesa atcelšana var radīt datu zaudējumus
monitor.process.cancel_notices=Atcelt: %s?
@@ -3520,7 +3548,7 @@ monitor.queue.settings.title=Pūla iestatījumi
monitor.queue.settings.desc=Pūli dinamiski palielinās atkarībā no to strādņu rindu aizturēšanas.
monitor.queue.settings.maxnumberworkers=Maksimālais strādņu skaits
monitor.queue.settings.maxnumberworkers.placeholder=Pašalaik %[1]d
-monitor.queue.settings.maxnumberworkers.error=Maksimālajam strādņu skaitam ir jābūt skaitlim
+monitor.queue.settings.maxnumberworkers.error=Lielākajam pieļaujamajam strādņu skaitam ir jābūt skaitlim
monitor.queue.settings.submit=Atjaunināt iestatījumus
monitor.queue.settings.changed=Iestatījumi atjaunināti
monitor.queue.settings.remove_all_items=Noņemt visus
@@ -3539,7 +3567,7 @@ notices.type_1=Glabātava
notices.type_2=Uzdevums
notices.desc=Apraksts
notices.op=Op.
-notices.delete_success=Sistēmas paziņojumi ir dzēsti.
+notices.delete_success=Sistēmas paziņojumi tika dzēsti.
self_check.no_problem_found=Vēl nav atrasts neviens sarežģījums.
config_summary = Kopsavilkums
@@ -3556,7 +3584,7 @@ self_check.database_collation_mismatch = Sagaidīt, ka datubāzē tiek izmantota
self_check.database_fix_mysql = MySQL/MariaDB lietotāji var izmantot komandu "forgejo doctor convert", lai novērstu salīdzināšanas sarežģījumus, vai arī tos var pašrocīgi novērst ar "ALTER ... COLLATE ..." vaicājumiem.
config.app_slogan = Servera sauklis
config.allow_dots_in_usernames = Ļaut lietotājiem izmantot punktus savā lietotājvārdā. Neietekmē esošos kontus.
-users.restricted.description = Ļaut mijiedarbību tikai ar glabātavām un apvienībām, kurās šis lietotājs ir pievienots kā līdzdalībnieks. Tas neļauj piekļūt šī servera publiskajām glabātavām.
+users.restricted.description = Ļaut mijiedarbību tikai ar glabātavām un apvienībām, kurās šis lietotājs ir pievienots kā līdzdalībnieks. Tas neļauj piekļūt šī servera atklātajām glabātavām.
dashboard.sync_tag.started = Uzsākta birku sinhronizēšana
users.organization_creation.description = Ļaut jaunu apvienību izveidošanu.
users.block.description = Liegt šī lietotāja mijiedarbību ar šo serveri caur tā kontu un neļaut pieteikšanos.
@@ -3596,14 +3624,14 @@ compare_commits_general=Salīdzināt iesūtījumus
mirror_sync_push=sinhronizēja iesūtījumus uz %[3]s %[4]s no spoguļglabātavas
mirror_sync_create=sinhronizēja jaunu atsauci %[3]s uz %[4]s no spoguļglabātavas
mirror_sync_delete=sinhronizēja un izdzēsa atsauci %[2]s
%[3]s no spoguļglabātavas
-approve_pull_request=`apstiprināja izmaiņu pieprasījumu %[3]s#%[2]s`
+approve_pull_request=`apstiprināja %[3]s#%[2]s`
reject_pull_request=`ieteica izmaiņas izmaiņu pieprasījumam %[3]s#%[2]s`
publish_release=`izdeva laidienu %[4]s %[3]s`
review_dismissed=`atmeta izskatīšanu no %[4]s %[3]s#%[2]s`
review_dismissed_reason=Iemesls:
create_branch=izveidoja zaru %[3]s glabātavā %[4]s
starred_repo=pievienoja izlasē %[2]s
-watched_repo=sāka sekot %[2]s
+watched_repo=sāka vērot %[2]s
[tool]
now=tagad
@@ -3635,11 +3663,11 @@ remove_file=Noņemt datni
notifications=Paziņojumi
unread=Neizlasītie
read=Izlasītie
-no_unread=Nav nelasītu paziņojumu.
+no_unread=Nav neizlasītu paziņojumu.
no_read=Nav izlasītu paziņojumu.
pin=Piespraust paziņojumu
mark_as_read=Atzīmēt kā izlasītu
-mark_as_unread=Atzīmēt kā nelasītu
+mark_as_unread=Atzīmēt kā neizlasītu
mark_all_as_read=Atzīmēt visus kā izlasītus
subscriptions=Abonementi
watching=Skatās
@@ -3671,9 +3699,9 @@ registry.documentation=Vairāk informācijas par %s reģistru ir %[3]s %[1]s
+filter.container.tagged=Ar birku
+filter.container.untagged=Bez birkas
+published_by=Laida klajā %[3]s %[1]s
published_by_in=%[3]s laida klajā %[1]s %[5]s
installation=Uzstādīšana
about=Par šo pakotni
@@ -3782,7 +3810,7 @@ settings.delete.error=Neizdevās izdzēst pakotni.
owner.settings.cargo.title=Cargo reģistra inkdess
owner.settings.cargo.initialize=Sāknēt indeksu
owner.settings.cargo.initialize.description=Ir nepieciešams īpaša indeksa Git glabātava, lai izmantotu Cargo reģistru. Šīs iespējas izmantošana (atkārtoti) izveidos glabātavu un automātiski to iestatīs.
-owner.settings.cargo.initialize.error=Neizdevās inicializēt Cargo indeksu: %v
+owner.settings.cargo.initialize.error=Neizdevās sāknēt Cargo indeksu: %v
owner.settings.cargo.initialize.success=Cargo indekss tika sekmīgi izveidots.
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.
@@ -3793,12 +3821,12 @@ owner.settings.cleanuprules.add=Pievienot notīrīšanas kārtulu
owner.settings.cleanuprules.edit=Labot notīrīšanas kārtulu
owner.settings.cleanuprules.none=Vēl nav pieejama neviena tīrīšanas kārtula.
owner.settings.cleanuprules.preview=Attīrīšanas kārtulas priekšskatījums
-owner.settings.cleanuprules.preview.overview=Ir ieplānota %d paku dzēšana.
-owner.settings.cleanuprules.preview.none=Notīrīšanas kārtulai neatbilst neviena pakotne.
+owner.settings.cleanuprules.preview.overview=Ir paredzēta %d pakotņu noņemšana.
+owner.settings.cleanuprules.preview.none=Attīrīšanas kārtulai neatbilst neviena pakotne.
owner.settings.cleanuprules.enabled=Iespējots
-owner.settings.cleanuprules.pattern_full_match=Piešķirt šablonu visam pakotnes nosaukumam
+owner.settings.cleanuprules.pattern_full_match=Pielietot paraugu visam pakotnes nosaukumam
owner.settings.cleanuprules.keep.title=Versijas, kas atbilst šīm kārtulām, tiks paturētas, pat ja tās atbildīs zemāk esošajai noņemšanas kārtulai.
-owner.settings.cleanuprules.keep.count=Saglabāt jaunāko versiju
+owner.settings.cleanuprules.keep.count=Paturēt visjaunāko
owner.settings.cleanuprules.keep.count.1=1 versija katrai pakotnei
owner.settings.cleanuprules.keep.count.n=%d versijas katrai pakotnei
owner.settings.cleanuprules.keep.pattern=Paturēt versijas, kas atbilst
@@ -3835,24 +3863,24 @@ search_in_external_registry = Meklēt %s
alt.registry = Šī reģistra uzstādīšana komandrindā:
alt.registry.install = Lai uzstādītu pakotni, jāizpilda šī komanda:
alt.install = Uzstādīt pakotni
-alt.setup = Pievienot glabātavu savienoto glabātavu sarakstā ('_arch_' vietā jāizvēlas nepieciešamā arhitektūra):
+alt.setup = Pievienot glabātavu savienoto glabātavu sarakstā ("_arch_" vietā jāizvēlas nepieciešamā arhitektūra):
alt.repository = Informācija par glabātavu
alt.repository.architectures = Arhitektūras
alt.repository.multiple_groups = Šī pakotne ir pieejama vairākās kopās.
[secrets]
secrets=Noslēpumi
-description=Noslēpumi tiks padoti atsevišķām darbībām un citādi nevar tikt nolasīti.
+description=Noslēpumi tiks padoti noteiktām darbībām, un citādāk tos nevar nolasīt.
none=Pagaidām nav neviena noslēpuma.
creation=Pievienot noslēpumu
creation.name_placeholder=reģistrnejutīgs, tikai burti, cipari un apakšsvītras, nevar sākties ar GITEA_ vai GITHUB_
creation.value_placeholder=Jāievada jebkāds saturs. Atstarpes sākumā un beigās tiks izlaistas.
creation.success=Noslēpums "%s" tika pievienots.
creation.failed=Neizdevās pievienot noslēpumu.
-deletion=Dzēst noslēpumu
-deletion.description=Noslēpuma dzēšana ir neatgriezeniska. Vai turpināt?
-deletion.success=Noslēpums tika izdzēsts.
-deletion.failed=Neizdevās dzēst noslēpumu.
+deletion=Noņemt noslēpumu
+deletion.description=Noslēpuma izdzēšana ir neatgriezeniska un nav atsaucama. Turpināt?
+deletion.success=Noslēpums tika noņemts.
+deletion.failed=Neizdevās noņemt noslēpumu.
management=Pārvaldīt noslēpumus
[actions]
@@ -3873,7 +3901,7 @@ runners=Izpildītāji
runners.runner_manage_panel=Pārvaldīt izpildītājus
runners.new=Izveidot jaunu izpildītāju
runners.new_notice=Kā uzstādīt izpildītāju
-runners.status=Statuss
+runners.status=Stāvoklis
runners.id=ID
runners.name=Nosaukums
runners.owner_type=Veids
@@ -3884,7 +3912,7 @@ runners.runner_title=Izpildītājs
runners.task_list=Pēdējās darbības, kas izpildītas
runners.task_list.no_tasks=Vēl nav uzdevumu.
runners.task_list.run=Izpildījums
-runners.task_list.status=Statuss
+runners.task_list.status=Stāvoklis
runners.task_list.repository=Glabātava
runners.task_list.commit=Iesūtījums
runners.task_list.done_at=Beigu laiks
@@ -3896,11 +3924,11 @@ runners.delete_runner=Dzēst izpildītāju
runners.delete_runner_success=Izpildītājs sekmī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.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 darbplūsmas.
runners.none=Nav pieejami izpildītāji
runners.status.unspecified=Nezināms
runners.status.idle=Dīkstāvē
-runners.status.active=Aktīvs
+runners.status.active=Darbojas
runners.status.offline=Bezsaistē
runners.version=Versija
runners.reset_registration_token=Atiestatīt reģistrācijas pilnvaru
@@ -3913,7 +3941,7 @@ runs.pushed_by=aizgādāja
runs.invalid_workflow_helper=Darbplūsmas konfigurācijas datne ir nederīga. Lūgums pārbaudīt konfigurācijas datni: %s
runs.no_matching_online_runner_helper=Nav tiešsaistē esošu izpildītāju, kas atbilstu iezīmei: %s
runs.actor=Izraisītājs
-runs.status=Statuss
+runs.status=Stāvoklis
runs.actors_no_select=Visi izraisītāji
runs.status_no_select=Visi stāvokļi
runs.no_results=Netika atrasts nekas atbilstošs.
@@ -4005,7 +4033,7 @@ pull_kind = Meklēt izmaiņu pieprasījumus...
branch_kind = Meklēt zarus...
[repo.permissions]
-actions.write = Rakstīt: pašrocīgi izsaukt, pārsāktnēt, atcelt vai apstiprināt gaidošos CI/CD cauruļvadus.
+actions.write = Rakstīt: pašrocīgi izsaukt, pārsāktnēt, atcelt vai apstiprināt ierindotos CI/CD cauruļvadus.
ext_wiki = Piekļūt ārējas vikivietnes saitei. Atļaujas tiek pārvaldītas ārēji.
ext_issues = Piekļūt ārēja pieteikumu izsekotāja saitei. Atļaujas tiek pārvaldītas ārēji.
packages.write = Rakstīt: pievienot un izdzēst glabātavai piesaistītās pakotnes.
diff --git a/options/locale/locale_nds.ini b/options/locale/locale_nds.ini
index 3bfa9e798e..9715d76e86 100644
--- a/options/locale/locale_nds.ini
+++ b/options/locale/locale_nds.ini
@@ -98,7 +98,7 @@ write = Schrieven
preview = Utkiek
loading = Lädt …
error = Fehler
-error404 = De Sied, wat du söchst, gifft dat of nich of du hest nich de Rechten, se antokieken.
+error404 = De Sied, wat du söchst, gifft dat of nich, of se is lösket worden of du hest nich de Rechten, se antokieken.
error413 = Du hest diene Quote överweggahn.
go_back = Torügg gahn
invalid_data = Ungültiger Weert: %v
@@ -210,6 +210,10 @@ table_modal.placeholder.header = Kopprieg
table_modal.placeholder.content = Inholl
table_modal.label.rows = Riegen
table_modal.label.columns = Striepen
+link_modal.url = Url
+link_modal.description = Beschrieven
+link_modal.header = Föög eenen Verwies hento
+link_modal.paste_reminder = Wenk: Wenn in diener Tüskenavlaag eene URL is, kannst du se stracks in de Bewarker infögen, um eenen Verwies to maken.
[filter]
string.desc = Z – A
@@ -859,6 +863,26 @@ change_username_redirect_prompt.with_cooldown.one = De olle Brukernaam word na e
change_username_redirect_prompt.with_cooldown.few = De olle Brukernaam word na eener Ofköhl-Düür vun %[1]d Dagen för all Lüü verföögbaar wesen. In de Ofköhl-Düür kannst du de ollen Naam noch torügghalen.
keep_pronouns_private = Pronomens blots to anmellt Brukers wiesen
keep_pronouns_private.description = Dat word diene Pronomens vun Besökers, wat nich anmellt sünd, verbargen.
+quota.rule.exceeded.helper = De Grött vun all Dingen unner deeser Regel all tosamen is hooger as de Quote.
+quota.applies_to_user = Deese Quoten-Regeln gellen för dien Konto
+storage_overview = Spieker-Översicht
+quota = Quote
+quota.applies_to_org = Deese Quoten-Regeln gellen för deese Vereenigung
+quota.rule.exceeded = Överweggahn
+quota.rule.no_limit = Nich begrenzt
+quota.sizes.all = All
+quota.sizes.repos.all = Repositoriums
+quota.sizes.repos.public = Publike Repositoriums
+quota.sizes.repos.private = Privaate Repositoriums
+quota.sizes.git.all = Git-Inhollen
+quota.sizes.git.lfs = Git-LFS
+quota.sizes.assets.attachments.all = Anhangen
+quota.sizes.assets.attachments.issues = Gefall-Anhangen
+quota.sizes.assets.attachments.releases = Publizerens-Anhangen
+quota.sizes.assets.packages.all = Paketen
+quota.sizes.wiki = Wiki
+quota.sizes.assets.all = Objekten
+quota.sizes.assets.artifacts = Warkwies-Objekten
[repo]
rss.must_be_on_branch = Du muttst up eenem Twieg wesen, um eenen RSS-Schuuv to hebben.
@@ -1031,7 +1055,7 @@ mirror_lfs_desc = Spegeln vun LFS-Daten anknipsen.
adopt_preexisting_content = Repositorium vun %s maken
transfer.no_permission_to_accept = Du hest nich dat Recht, deeses Överdragen antonehmen.
template.git_hooks = Git-Hakens
-archive.title_date = Deeses Repositorium is am %s archiveert worden. Du kannst de Dateien ankieken un ’t klonen, aver du kannst de Tostand vun deesem Repositorium nich ännern, also nix schuven un keene nejen Gefallens, Haalvörslagen of Kommentaren maken.
+archive.title_date = Deeses Repositorium is am %s archiveert worden. Du kannst de Dateien ankieken un ’t klonen, aver du kannst sienen Tostand nich ännern, also nix schuven un keene nejen Gefallens, Haalvörslagen of Kommentaren maken.
form.reach_limit_of_creation_1 = De Eegner is al bi de Grenz vun %d Repositorium.
form.name_reserved = De Repositoriums-Naam »%s« is vörbehollen.
form.string_too_long = De angeven Text is langer as %d Bookstavens.
@@ -1045,7 +1069,7 @@ migrate_options_mirror_helper = Deeses Repositorium word een Spegel wesen
migrate_options_lfs_endpoint.description.local = Een stedenwies Server-Padd word ok unnerstütt.
migrate_items_merge_requests = Tosamenföhren-Vörslagen
migrate.permission_denied = Du düürst keene stedenwies Repositoriums importeren.
-archive.title = Deeses Repositorium is archiveert. Du kannst de Dateien ankieken un ’t klonen, aver du kannst de Tostand vun deesem Repositorium nich ännern, also nix schuven un keene nejen Gefallens, Haalvörslagen of Kommentaren maken.
+archive.title = Deeses Repositorium is archiveert. Du kannst de Dateien ankieken un ’t klonen, aver du kannst sienen Tostand nich ännern, also nix schuven un keene nejen Gefallens, Haalvörslagen of Kommentaren maken.
need_auth = Anmellen
migrate_options = Umtreck-Instellens
migrate.clone_local_path = of een stedenwies Server-Padd
@@ -1449,7 +1473,7 @@ issues.label.filter_sort.reverse_alphabetically = Umdreiht na de Alphabeet
issues.label.filter_sort.by_size = Lüttste Grött
issues.num_participants_one = %d Mitmaker
issues.num_participants_few = %d Mitmakers
-issues.ref_pull_from = `hett deeses Haalvörslag %[4]s %[2]s benöömt`
+issues.ref_pull_from = `hett deesen Haalvörslag %[4]s %[2]s benöömt`
issues.label_title = Naam
issues.label_archived_filter = Archiveert Vermarkens wiesen
issues.archived_label_description = (Archiveert) %s
@@ -1557,7 +1581,7 @@ issues.start_tracking_history = `hett %s to warken begunnen`
issues.lock.notice_2 = - Du un anner Mitarbeiders mit Togriep to deesem Repositorium köönt wiederhen Kommentaren schrieven, wat elkeenwell sücht.
issues.due_date_modified = hett dat Anstahns-Datum vun %[2]s to %[1]s %[3]s ännert
issues.dependency.issue_remove_text = Dat word de Ofhangen vun deesem Gefall wegdoon. Wiedermaken?
-issues.review.approve = hett deese Ännerns %s tostimmt
+issues.review.approve = hett %s deesen Ännerns tostimmt
issues.review.dismissed = hett %[2]s dat Nakieken vun %[1]s ofseggt
issues.lock.title = Snack up deesem Gefall tosluten.
issues.unlock.title = Snack up deesem Gefall upsluten.
@@ -1668,12 +1692,12 @@ pulls.waiting_count_1 = %d Nakieken staht ut
issues.content_history.deleted = lösket
issues.content_history.created = maakt
issues.content_history.delete_from_history_confirm = Ut Histoorje lösken?
-issues.blocked_by_user = Du kannst up deesem Repositorium keenen Gefall opmaken, denn de Repositoriums-Eegner hett di blockeert.
+issues.blocked_by_user = Du kannst in deesem Repositorium keene Gefallens opmaken, denn de Repositoriums-Eegner hett di blockeert.
pulls.merged_title_desc_few = hett %[1]d Kommitterens vun %[2]s
na %[3]s
%[4]s tosamenföhrt
pulls.reject_count_1 = %d Bidde um Ännerns
pulls.blocked_by_user = Du kannst in deesem Repositorium keenen Haalvörslag opmaken, denn de Repositoriums-Eegner hett di blockeert.
pulls.no_merge_access = Du hest nich dat Recht, deesen Haalvörslag tosamentoföhren.
-issues.comment.blocked_by_user = Du kannst up deesem Gefall keenen Kommentaar schrieven, denn de Repositoriums-Eegner of de Autor vun de Gefall hett di blockeert.
+issues.comment.blocked_by_user = Du kannst up deesem Gefall nich kommenteren, denn de Repositoriums-Eegner of de Autor vun de Gefall hett di blockeert.
pulls.switch_comparison_type = Verglieks-Aard ännern
pulls.showing_only_single_commit = Blots Ännerns vun Kommitteren %[1]s wiesen
pulls.blocked_by_changed_protected_files_n = Deeser Haalvörslag is blockeert, denn dat ännert beschütt Dateien:
@@ -2576,6 +2600,10 @@ archive.pull.noreview = Deeses Repositorium is archiveert. Du kannst keene Haalv
commits.view_single_diff = Ännerns an deeser Datei in deesem Kommitteren wiesen
pulls.editable = Bewarkbaar
pulls.editable_explanation = Deeser Haalvörslag verlöövt Bewarkens vun Liddmaten. Du kannst stracks daarto bidragen.
+issues.reopen.blocked_by_user = Du kannst deeses Gefall nich weer opmaken, denn de Repositoriums-Eegner of de Autor vun de Gefall hett di blockeert.
+pulls.comment.blocked_by_user = Du kannst up deesem Haalvörslag nich kommenteren, denn de Repositoriums-Eegner of de Autor vun de Haalvörslag hett di blockeert.
+issues.filter_no_results = Keene Resultaten
+issues.filter_no_results_placeholder = Versöök, diene Söök-Filters antopassen.
[repo.permissions]
code.read = Lesen: De Quelltext vun deesem Repositorium ankieken un klonen.
diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini
index e2eff6b16d..8b5db6ea50 100644
--- a/options/locale/locale_nl-NL.ini
+++ b/options/locale/locale_nl-NL.ini
@@ -4,14 +4,14 @@ dashboard=Overzicht
explore=Verkennen
help=Help
logo=Logo
-sign_in=Inloggen
+sign_in=Aanmelden
sign_in_or=of
sign_out=Uitloggen
sign_up=Registreren
link_account=Account Koppelen
register=Registreren
version=Versie
-powered_by=Aangedreven door %s
+powered_by=Mogelijk gemaakt door %s
page=Pagina
template=Sjabloon
language=Taal
@@ -28,24 +28,24 @@ username=Gebruikersnaam
email=E-mailadres
password=Wachtwoord
access_token=Toegangstoken
-re_type=Verifieer wachtwoord
+re_type=Bevestig wachtwoord
captcha=CAPTCHA
twofa=Twee-factor authenticatie
twofa_scratch=Twee-factor krascode
-passcode=PIN
+passcode=Code
webauthn_insert_key=Voer uw beveiligingssleutel in
-webauthn_sign_in=Druk op de knop van uw beveiligingssleutel. Als uw beveiligingssleutel geen knop heeft, voeg deze dan opnieuw in.
+webauthn_sign_in=Druk op de knop van uw beveiligingssleutel. Als uw beveiligingssleutel geen knop heeft, voer deze dan opnieuw in.
webauthn_press_button=Druk alstublieft op de knop van uw beveiligingssleutel…
webauthn_use_twofa=Gebruik een twee-factor code van uw telefoon
webauthn_error=Kon uw beveiligingssleutel niet lezen.
webauthn_unsupported_browser=Uw browser ondersteunt momenteel geen WebAuthn.
webauthn_error_unknown=Er is een onbekende fout opgetreden. Probeer het opnieuw.
-webauthn_error_insecure=WebAuthn ondersteunt alleen beveiligde verbindingen. Om te testen via HTTP, kan je de oorsprong "localhost" of "127.0.0.1" gebruiken
+webauthn_error_insecure=WebAuthn ondersteunt alleen beveiligde verbindingen. Om te testen via HTTP, kan je als systeemnaam "localhost" of "127.0.0.1" gebruiken
webauthn_error_unable_to_process=De server kon uw verzoek niet verwerken.
-webauthn_error_duplicated=De beveiligingssleutel is niet toegestaan voor dit verzoek. Zorg er alstublieft voor dat de sleutel niet al geregistreerd is.
+webauthn_error_duplicated=De beveiligingssleutel is voor dit verzoek niet toegestaan. Controleer alstublieft of de sleutel niet al is geregistreerd.
webauthn_error_empty=U moet een naam voor deze sleutel instellen.
-webauthn_error_timeout=Time-out bereikt voordat uw sleutel kon worden gelezen. Laad deze pagina opnieuw en probeer het opnieuw.
+webauthn_error_timeout=Time-out bereikt voordat uw sleutel kon worden gelezen. Herlaad deze pagina en probeer het opnieuw.
webauthn_reload=Vernieuwen
repository=Repository
@@ -56,9 +56,9 @@ new_migrate=Nieuwe migratie
new_mirror=Nieuwe mirror
new_fork=Nieuwe repository fork
new_org=Nieuwe organisatie
-new_project=Nieuwe project
+new_project=Nieuw project
manage_org=Beheer organisaties
-admin_panel=Website administratie
+admin_panel=Site beheer
account_settings=Accountinstellingen
settings=Instellingen
your_profile=Profiel
@@ -66,12 +66,12 @@ your_starred=Favoriet
your_settings=Instellingen
all=Alles
-sources=Bronnen
+sources=Broncode
mirrors=Mirrors
-collaborative=Samenwerkend
+collaborative=Samenwerkende
forks=Forks
-activities=Activiteiten
+activities=Activiteit
pull_requests=Pull requests
issues=Issues
milestones=Mijlpalen
@@ -83,7 +83,7 @@ add=Toevoegen
add_all=Alles toevoegen
remove=Verwijder
remove_all=Alles verwijderen
-edit=Bewerk
+edit=Wijzig
enabled=Ingeschakeld
disabled=Uitgeschakeld
@@ -99,7 +99,7 @@ preview=Voorbeeld
loading=Laden…
error=Fout
-error404=De pagina die u probeert te bereiken bestaat niet of u bent niet gemachtigd om het te bekijken.
+error404=De pagina die u probeert te bereiken bestaat niet, is verwijderd of u bent niet bevoegd om deze te bekijken.
never=Nooit
@@ -115,8 +115,8 @@ concept_user_organization=Organisatie
name=Naam
-sign_in_with_provider = Log in met %s
-tracked_time_summary = Overzicht van geregistreerde tijd op basis van filters van probleemlijst
+sign_in_with_provider = Aanmelden met %s
+tracked_time_summary = Overzicht van geregistreerde tijd op basis van filters van issuelijst
enable_javascript = Deze website vereist JavaScript.
retry = Probeer opnieuw
rerun_all = Alle taken opnieuw uitvoeren
@@ -140,9 +140,9 @@ confirm_delete_selected = Bevestigen om alle geselecteerde items te verwijderen?
copy_type_unsupported = Dit bestandstype kan niet worden gekopieerd
pin = Vastpinnen
unpin = Ontpinnen
-remove_label_str = Verwijder punt "%s"
+remove_label_str = Verwijder item "%s"
confirm_delete_artifact = Weet u zeker dat u het artefact "%s" wilt verwijderen?
-toggle_menu = Menu schakelen
+toggle_menu = Menu aan/uit
filter.clear = Filter wissen
filter.is_archived = Gearchiveerd
filter.is_fork = Forks
@@ -159,7 +159,7 @@ more_items = Meer items
invalid_data = Ongeldige data: %v
copy_generic = Kopieer naar klembord
test = Test
-error413 = U heeft al uw quotum opgebruikt.
+error413 = U heeft uw hele quotum gebruikt.
new_migrate.title = Nieuwe migratie
new_org.title = Nieuwe organisatie
new_repo.link = Nieuwe repository
@@ -206,6 +206,10 @@ table_modal.placeholder.header = Kop
table_modal.placeholder.content = Inhoud
table_modal.label.rows = Rijen
table_modal.label.columns = Kolommen
+link_modal.header = Link toevoegen
+link_modal.url = Url
+link_modal.description = Beschrijving
+link_modal.paste_reminder = Tip: Als u een URL op uw klembord heeft, kun u deze direct in de editor plakken om een koppeling te maken.
[filter]
string.asc = A - Z
@@ -1064,6 +1068,26 @@ change_username_redirect_prompt.with_cooldown.few = De oude gebruikersnaam zal v
change_username_redirect_prompt.with_cooldown.one = De oude gebruikersnaam zal voor iedereen beschikbaar zijn na een afkoelperiode van %[1]d dag. U kunt de oude gebruikersnaam nog steeds opeisen tijdens de afkoelperiode.
keep_pronouns_private = Toon voornaamwoorden alleen aan geauthenticeerde gebruikers
keep_pronouns_private.description = Dit verbergt uw voornaamwoorden voor bezoekers die niet zijn ingelogd.
+quota.rule.exceeded.helper = De totale grootte van objecten voor deze regel heeft de quota overschreden.
+quota.sizes.repos.private = Privé repositories
+storage_overview = Opslagoverzicht
+quota = Quotum
+quota.applies_to_user = De volgende quotaregels zijn van toepassing op uw account
+quota.applies_to_org = De volgende quotaregels zijn van toepassing op deze organisatie
+quota.rule.exceeded = Overschreden
+quota.rule.no_limit = Onbeperkt
+quota.sizes.all = Alle
+quota.sizes.repos.all = Repositories
+quota.sizes.repos.public = Openbare repositories
+quota.sizes.git.all = Git inhoud
+quota.sizes.git.lfs = Git LFS
+quota.sizes.assets.all = Bezittingen
+quota.sizes.assets.attachments.all = Bijlagen
+quota.sizes.assets.attachments.issues = Issue bijlagen
+quota.sizes.assets.attachments.releases = Release bijlagen
+quota.sizes.assets.artifacts = Artefacten
+quota.sizes.assets.packages.all = Pakketten
+quota.sizes.wiki = Wiki
[repo]
owner=Eigenaar
@@ -1257,7 +1281,7 @@ tags=Labels
issues=Issues
pulls=Pull requests
project_board=Projecten
-packages=Paketten
+packages=Pakketten
labels=Labels
org_labels_desc=Organisatielabel dat gebruikt kan worden met alle repositories onder deze organisatie
org_labels_desc_manage=beheren
@@ -2397,8 +2421,8 @@ find_file.no_matching = Geen overeenkomstige bestanden gevonden
error.csv.too_large = Kan dit bestand niet renderen omdat het te groot is.
error.csv.unexpected = Kan dit bestand niet renderen omdat het een onverwacht karakter bevat in regel %d en kolom %d.
error.csv.invalid_field_count = Kan dit bestand niet renderen omdat het een verkeerd aantal velden heeft in regel %d.
-issues.comment.blocked_by_user = U kunt geen reactie op deze issue plaatsen omdat u geblokkeerd bent door de eigenaar van de repository of door de persoon die de issue heeft gepost.
-issues.blocked_by_user = U kunt geen issue op deze repository maken omdat u geblokkeerd bent door de eigenaar van de repository.
+issues.comment.blocked_by_user = U kunt niet reageren op deze issue omdat u geblokkeerd bent door de eigenaar van de repository of de poster van de issue.
+issues.blocked_by_user = U kunt geen issues aanmaken in deze repository omdat u geblokkeerd bent door de eigenaar van deze repository.
issues.label_archived_filter = Gearchiveerde labels bekijken
issues.label_archive_tooltip = Gearchiveerde labels zijn standaard uitgezonderd van de suggesties als men op een label zoekt.
issues.max_pinned = U kunt geen issues meer vastpinnen
@@ -2486,8 +2510,8 @@ tree_path_not_found_tag = Pad %[1]s bestaat niet in tag %[2]s
transfer.no_permission_to_reject = Je hebt geen rechten om deze overdracht af te wijzen.
settings.transfer_owner = Nieuwe eigenaar
mirror_address_protocol_invalid = De opgegeven URL is ongeldig. Alleen http(s):// of git:// locaties kunnen gebruikt worden voor spiegelen.
-archive.title = Deze repository is gearchiveerd. Je kunt bestanden bekijken en klonen, maar geen issues of pull requests pushen of openen.
-archive.title_date = Deze repository is gearchiveerd op %s. Je kunt bestanden bekijken en klonen, maar je kunt niet pushen of issues of pull requests openen.
+archive.title = Deze repository is gearchiveerd. U kunt bestanden bekijken en klonen, maar u kunt geen wijzigingen aanbrengen aan de status, zoals het pushen en aanmaken van nieuwe issues, pull requests of opmerkingen.
+archive.title_date = Deze repository is gearchiveerd op %s. U kunt bestanden bekijken en klonen, maar u kunt geen wijzigingen aanbrengen aan de status, zoals het pushen en aanmaken van nieuwe issues, pull requests of opmerkingen.
migrate_options_lfs_endpoint.placeholder = Als dit leeg gelaten wordt, zal het eindpunt afgeleid worden van de kloon URL
invisible_runes_description = `Dit bestand bevat onzichtbare Unicode-tekens die voor mensen niet te onderscheiden zijn, maar door een computer anders verwerkt kunnen worden. Als je denkt dat dit opzettelijk is, kun je deze waarschuwing gerust negeren. Gebruik de Escape knop om ze te onthullen.`
ambiguous_runes_header = `Dit bestand bevat dubbelzinnige Unicode-tekens`
@@ -2874,6 +2898,10 @@ archive.pull.noreview = Deze repository is gearchiveerd. U kunt geen pull reques
commits.view_single_diff = Bekijk de veranderingen aan dit bestand die in deze commit zijn geïntroduceerd
pulls.editable_explanation = Deze pull request staat bewerkingen toe van beheerders. Je kunt er direct aan bijdragen.
pulls.editable = Bewerkbaar
+issues.reopen.blocked_by_user = U kunt deze issue niet heropenen omdat u geblokkeerd bent door de eigenaar van de repository of de poster van de issue.
+pulls.comment.blocked_by_user = U kunt niet reageren op deze pull request omdat u geblokkeerd bent door de eigenaar van de repository of de poster van de issue.
+issues.filter_no_results_placeholder = Probeer uw zoekfilters aan te passen.
+issues.filter_no_results = Geen resultaten
@@ -2951,7 +2979,7 @@ members.invite_desc=Voeg nieuw lid toe aan %s:
members.invite_now=Nu uitnodigen
teams.join=Lid worden
-teams.leave=Vertlaat
+teams.leave=Verlaat
teams.can_create_org_repo=Maak repositories
teams.can_create_org_repo_helper=Leden kunnen nieuwe repositories aanmaken in de organisatie. De maker krijgt beheerder toegang tot de nieuwe repository.
teams.read_access=Gelezen
@@ -3840,7 +3868,7 @@ alt.repository.architectures = Architecturen
alt.repository.multiple_groups = Dit pakket is beschikbaar in meerdere groepen.
alt.registry = Stel dit register in vanaf de opdrachtregel:
alt.install = Pakket installeren
-alt.setup = Voeg een repository toe aan de lijst met gekoppelde repositories (kies de benodigde architectuur in plaats van '_arch_'):
+alt.setup = Voeg een repository toe aan de lijst met gekoppelde repositories (kies de benodigde architectuur in plaats van "_arch_"):
[secrets]
secrets = Geheimen
diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini
index 6ba696573a..7098481fee 100644
--- a/options/locale/locale_pt-BR.ini
+++ b/options/locale/locale_pt-BR.ini
@@ -55,7 +55,7 @@ organization=Organização
mirror=Espelhamento
new_repo=Novo repositório
new_migrate=Nova migração
-new_mirror=Novo espelhamento
+new_mirror=Novo espelho
new_fork=Novo fork do repositório
new_org=Nova organização
new_project=Novo projeto
@@ -109,7 +109,7 @@ preview=Pré-visualização
loading=Carregando…
error=Erro
-error404=A página que você está tentando acessar não existe ou você não está autorizado a visualizá-la.
+error404=A página que você está tentando acessar não existe, foi removida ou você não tem autorização para visualizá-la.
never=Nunca
unknown=Desconhecido
@@ -206,6 +206,10 @@ table_modal.placeholder.header = Cabeçalho
table_modal.placeholder.content = Conteúdo
table_modal.label.rows = Linhas
table_modal.label.columns = Colunas
+link_modal.header = Adicionar um link
+link_modal.url = URL
+link_modal.description = Descrição
+link_modal.paste_reminder = Dica: Com uma URL na sua área de transferência, você pode colar diretamente no editor para criar um link.
[filter]
string.asc=A - Z
@@ -723,8 +727,8 @@ following.title.one = seguindo
followers.title.one = seguidor
followers.title.few = seguidores
public_activity.visibility_hint.self_private = Sua atividade está visível apenas para você e para os administradores da instância. Configurar.
-public_activity.visibility_hint.self_public = Sua atividade está visível para todos, exceto o engajamento em espaços privados. Configurar.
-public_activity.visibility_hint.admin_public = Sua atividade está visível para todos, mas como um administrador você também pode ver o engajamento em espaços privados.
+public_activity.visibility_hint.self_public = Sua atividade está visível para todos, exceto interações em espaços privados. Configurar.
+public_activity.visibility_hint.admin_public = Sua atividade está visível para todos, mas como um administrador você também pode ver interações em espaços privados.
public_activity.visibility_hint.admin_private = Essa atividade está visível para você porque você é um administrador, mas o usuário dejesa que ela seja mantida em privado.
public_activity.visibility_hint.self_private_profile = Sua atividade só é visível para você e para os administradores do servidor porque seu perfil é privado. Configurar.
@@ -993,7 +997,7 @@ scan_this_image=Escaneie esta imagem com o seu aplicativo de autenticação:
or_enter_secret=Ou digite esse código: %s
then_enter_passcode=E insira a senha mostrada no aplicativo:
passcode_invalid=Esse código de acesso é inválido. Tente novamente.
-twofa_enrolled=Sua conta foi inscrita na autenticação de dois fatores. Armazene seu token de backup (%s) em um local seguro, pois ele é exibido apenas uma vez!
+twofa_enrolled=Sua conta foi inscrita na autenticação de dois fatores. Armazene seu token de recuperação de uso único (%s) em um local seguro, pois ele não será exibido novamente.
twofa_failed_get_secret=Falha ao obter o segredo.
webauthn_desc=Chaves de segurança são dispositivos de hardware que contém chaves de criptografia. Elas podem ser usadas para autenticação de dois fatores. A chave de segurança deve suportar o padrão WebAuthnn Authenticator.
@@ -1061,6 +1065,28 @@ user_block_yourself = Você não pode se bloquear.
pronouns_custom_label = Pronomes personalizados
change_username_redirect_prompt.with_cooldown.one = O nome de usuário antigo ficará disponível para qualquer pessoa após um período de espera de %[1]d dia, você ainda pode recuperar o nome de usuário antigo durante este período de espera.
change_username_redirect_prompt.with_cooldown.few = O nome de usuário antigo ficará disponível para qualquer pessoa após um período de espera de %[1]d dias, você ainda pode recuperar o nome de usuário antigo durante este período de espera.
+quota.applies_to_user = As seguintes regras de cota se aplicam à sua conta
+quota.rule.exceeded.helper = O tamanho total de objetos para esta regra excedeu a cota.
+keep_pronouns_private = Mostrar pronomes apenas para usuários autenticados
+keep_pronouns_private.description = Isto irá esconder seus pronomes de visitantes que não fizeram login.
+storage_overview = Visão geral de armazenamento
+quota = Cota
+quota.applies_to_org = As seguintes regras de cota se aplicam a esta organização
+quota.rule.exceeded = Excedido
+quota.rule.no_limit = Ilimitado
+quota.sizes.all = Tudo
+quota.sizes.repos.all = Repositórios
+quota.sizes.repos.public = Repositórios públicos
+quota.sizes.repos.private = Repositórios privados
+quota.sizes.git.all = Conteúdo Git
+quota.sizes.git.lfs = LFS Git
+quota.sizes.assets.all = Assets
+quota.sizes.assets.attachments.all = Anexos
+quota.sizes.assets.attachments.issues = Anexos de issue
+quota.sizes.assets.attachments.releases = Anexos de release
+quota.sizes.assets.artifacts = Artefatos
+quota.sizes.assets.packages.all = Pacotes
+quota.sizes.wiki = Wiki
[repo]
owner=Proprietário
@@ -1175,8 +1201,8 @@ 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.title=Este repositório está arquivado. Você pode visualizar arquivos e cloná-lo, mas não pode fazer alterações, tais como push, novos issues, pull requests ou comentários.
+archive.title_date=Este repositório foi arquivado em %s. Você pode visualizar arquivos e cloná-lo, mas não pode fazer alterações, tais como push, abrir issues, pull requests ou comentários.
archive.issue.nocomment=Este repositório está arquivado. Você não pode comentar em issues.
archive.pull.nocomment=Este repositório está arquivado. Você não pode comentar em pull requests.
@@ -2660,7 +2686,7 @@ pulls.cmd_instruction_checkout_title = Checkout
settings.wiki_globally_editable = Permitir que qualquer pessoa edite a wiki
settings.transfer_abort_success = A transferência de repositório para %s foi cancelada.
settings.enter_repo_name = Digite os nomes do dono e do repositório exatamente neste formato:
-issues.blocked_by_user = Você não pode criar uma questão neste repositório porque você foi bloqueado pelo dono do repositório.
+issues.blocked_by_user = Você não pode criar issues neste repositório porque você foi bloqueado pelo dono do repositório.
settings.new_owner_blocked_doer = Você foi bloqueado pelo novo dono do repositório.
settings.wiki_rename_branch_main_notices_1 = NÃO É POSSÍVEL desfazer esta ação.
tree_path_not_found_commit = O caminho %[1]s não existe no commit %[2]s
@@ -2751,8 +2777,8 @@ release.system_generated = Este anexo foi gerado automaticamente.
settings.wiki_branch_rename_failure = Falha ao regularizar o nome do ramo da wiki do repositório.
settings.add_collaborator_blocked_them = Não foi possível adicionar o(a) colaborador(a) porque ele(a) bloqueou o(a) proprietário(a) do repositório.
settings.thread_id = ID da discussão
-issues.edit.already_changed = Não foi possível salvar as alterações desta questão porque o conteúdo foi alterado por outro(a) usuário(a). Atualize a página e tente novamente para evitar sobrescrever as alterações.
-pulls.edit.already_changed = Não foi possível salvar as alterações deste pedido de integração porque o conteúdo foi alterado por outro(a) usuário(a). Atualize a página e tente novamente para evitar sobrescrever as alterações.
+issues.edit.already_changed = Não foi possível salvar as alterações desta questão. O conteúdo parece já ter sido alterado por outro(a) usuário(a). Atualize a página e tente novamente para evitar sobrescrever estas alterações.
+pulls.edit.already_changed = Não foi possível salvar as alterações deste pull request. Parece que o conteúdo já foi alterado por outro(a) usuário(a). Atualize a página e tente novamente para evitar sobrescrever estas alterações.
editor.commit_id_not_matching = O arquivo foi alterado durante a edição. Salve as alterações em um novo ramo e realize a mesclagem.
blame.ignore_revs = As revisões em .git-blame-ignore-revs foram ignoradas. Clique aqui para retornar à visualização normal.
topic.format_prompt = Os tópicos devem começar com um caracter alfanumérico, podem incluir hífens ("-") e pontos ("."), e podem ter até 35 caracteres. As letras devem ser minúsculas.
@@ -2767,7 +2793,7 @@ pulls.fast_forward_only_merge_pull_request = Apenas fast-forward
pulls.has_merged = Falha: O pull request foi merged, você não pode merge novamente ou mudar o branch destino.
issues.author.tooltip.pr = Esse usuário é o autor dessa solicitação de pull.
editor.push_out_of_date = O push parece estar desatualizado.
-issues.comment.blocked_by_user = Você não pode criar um comentário nesse problema porque você está bloqueado pelo dono do repositório ou pelo autor do problema.
+issues.comment.blocked_by_user = Você não pode comentar neste issue porque você foi bloqueado pelo dono do repositório ou pelo autor deste issue.
pulls.blocked_by_user = Você não pode criar uma solicitação de pull nesse repositório porque você está bloqueado pelo dono do repositório.
mirror_use_ssh.helper = Forgejo irá espelhar o repositório via Git através de SSH e criar um par de chaves para você ao escolher essa opção. Você deverá garantir que a chave pública gerada está autorizada a fazer push para o repositório de destino. Você não pode usar autorização baseada em senha ao escolher essa opção.
mirror_denied_combination = Não é possível combinar o uso de chave pública e autenticação baseada em senha.
@@ -2873,6 +2899,8 @@ editor.commit_email = Email de commit
commits.view_single_diff = Ver modificações neste arquivo introduzidas neste commit
pulls.editable = Editável
pulls.editable_explanation = Este pull request permite edições de mantenedores. Voçê pode contribuir diretamenta para ele.
+issues.reopen.blocked_by_user = Você não pode reabrir este issue porque você foi bloqueado pelo dono do repositório ou pelo criador deste issue.
+pulls.comment.blocked_by_user = Você não pode comentar neste pull request porque você foi bloqueado pelo dono do repositório ou pelo autor do pull request.
[graphs]
component_loading = Carregando %s...
@@ -3181,7 +3209,7 @@ orgs.new_orga=Nova organização
repos.repo_manage_panel=Gerenciar repositórios
repos.unadopted=Repositórios não adotados
-repos.unadopted.no_more=Não foram encontrados repositórios não adotados
+repos.unadopted.no_more=Não foram encontrados repositórios não adotados.
repos.owner=Proprietário(a)
repos.name=Nome
repos.private=Privado
@@ -3837,7 +3865,7 @@ alt.install = Instalar pacote
alt.repository = Informação do repositório
alt.repository.architectures = Arquiteturas
alt.repository.multiple_groups = Este pacote está disponível em múltiplos grupos.
-alt.setup = Adicionar um repositório à lista de repositórios conectados (escolha a arquitetura necessária em vez de '_arch_'):
+alt.setup = Adicionar um repositório à lista de repositórios conectados (escolha a arquitetura necessária em vez de "_arch_"):
[secrets]
secrets=Segredos
@@ -3998,7 +4026,7 @@ commit_kind = Buscar commits…
runner_kind = Pesquisar runners...
code_search_unavailable = A pesquisa de código não está disponível no momento. Entre em contato com o administrador do site.
milestone_kind = Pesquisar marcos...
-union_tooltip = Incluir resultados que coincidam com quaisquer palavras-chave separadas por espaços em branco
+union_tooltip = Incluir resultados que correspondam a quaisquer palavras-chave separadas por espaços em branco
union = União
exact = Exato
exact_tooltip = Incluir apenas resultados que correspondam exatamente ao termo de pesquisa
diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini
index 7bbb23ee55..bf0bab6fd9 100644
--- a/options/locale/locale_pt-PT.ini
+++ b/options/locale/locale_pt-PT.ini
@@ -112,7 +112,7 @@ preview=Pré-visualizar
loading=Carregando…
error=Erro
-error404=A página que pretende aceder não existe ou não tem autorização para a ver.
+error404=A página que pretende aceder não existe, foi removida ou não tem autorização para a ver.
go_back=Voltar
never=Nunca
@@ -206,6 +206,10 @@ table_modal.placeholder.header = Cabeçalho
table_modal.placeholder.content = Conteúdo
table_modal.label.rows = Linhas
table_modal.label.columns = Colunas
+link_modal.header = Adicionar uma ligação
+link_modal.url = URL
+link_modal.description = Descrição
+link_modal.paste_reminder = Sugestão: Com um URL na área de transferência, pode colar diretamente no editor para criar uma ligação.
[filter]
string.asc=A - Z
@@ -1061,6 +1065,28 @@ pronouns_custom_label = Pronomes personalizados
user_block_yourself = Não se pode bloquear a si próprio.
change_username_redirect_prompt.with_cooldown.one = O nome de utilizador antigo estará disponível para todos após um período de espera de %[1]d dia, podendo ainda reivindicar o nome de utilizador antigo durante o período de espera.
change_username_redirect_prompt.with_cooldown.few = O nome de utilizador antigo ficará disponível para todos após um período de espera de %[1]d dias, podendo ainda reivindicar o nome de utilizador antigo durante o período de espera.
+quota.applies_to_user = As seguintes regras de quotas aplicam-se à sua conta
+quota.sizes.assets.artifacts = Artefactos
+quota.rule.exceeded.helper = O tamanho total dos objectos para esta regra excedeu a quota.
+keep_pronouns_private = Mostrar os pronomes apenas aos utilizadores autenticados
+keep_pronouns_private.description = Isto irá ocultar os seus pronomes dos visitantes que não tenham iniciado sessão.
+quota.sizes.git.lfs = Git LFS
+quota.sizes.assets.all = Ativos
+storage_overview = Panorama geral do armazenamento
+quota = Quota
+quota.applies_to_org = As seguintes regras de quotas aplicam-se a esta organização
+quota.rule.exceeded = Excedido
+quota.rule.no_limit = Ilimitado
+quota.sizes.all = Tudo
+quota.sizes.repos.all = Repositórios
+quota.sizes.repos.public = Repositórios públicos
+quota.sizes.repos.private = Repositórios privados
+quota.sizes.git.all = Conteúdo Git
+quota.sizes.assets.attachments.all = Anexos
+quota.sizes.assets.attachments.issues = Anexos de questões
+quota.sizes.assets.attachments.releases = Anexos de lançamentos
+quota.sizes.assets.packages.all = Pacotes
+quota.sizes.wiki = Wiki
[repo]
new_repo_helper=Um repositório contém todos os ficheiros do trabalho, incluindo o histórico das revisões. Já tem um hospedado noutro sítio? Migre o repositório.
@@ -1187,8 +1213,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 ficheiros e cloná-lo, mas não pode fazer envios ou abrir questões ou 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/pedidos de integração.
+archive.title=Este repositório está arquivado. Pode ver os ficheiros e cloná-lo, mas não pode fazer quaisquer alterações ao seu estado, tais como fazer envios e criar novas questões, pedidos de integração ou comentários.
+archive.title_date=Este repositório foi arquivado em %s. Pode ver os ficheiros e cloná-lo, mas não pode fazer quaisquer alterações ao seu estado, tais como fazer envios e criar novas questões, pedidos de integração ou comentários.
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.
@@ -2721,7 +2747,7 @@ find_file.no_matching=Não foi encontrado qualquer ficheiro correspondente
error.csv.too_large=Não é possível apresentar este ficheiro por ser demasiado grande.
error.csv.unexpected=Não é possível apresentar este ficheiro porque contém um caractere inesperado na linha %d e coluna %d.
error.csv.invalid_field_count=Não é possível apresentar este ficheiro porque tem um número errado de campos na linha %d.
-issues.blocked_by_user = Não pode criar uma questão neste repositório porque foi bloqueado/a pelo/a proprietário/a do repositório.
+issues.blocked_by_user = Não pode criar questões neste repositório porque foi bloqueado(a) pelo(a) proprietário(a) do repositório.
issues.num_participants_one = %d participante
stars = Favoritos
editor.invalid_commit_mail = Email inválido para criar um cometimento.
@@ -2787,7 +2813,7 @@ settings.sourcehut_builds.secrets = Segredos
settings.matrix.room_id_helper = O ID da Sala pode ser obtido no cliente web Element > Configurações da sala > Avançado > ID interno da sala. Exemplo: %s.
settings.web_hook_name_sourcehut_builds = Construções do SourceHut
settings.enter_repo_name = Insira o nome do/a proprietário/a e do repositório tal como é apresentado:
-issues.comment.blocked_by_user = Não pode criar um comentário nesta questão porque foi bloqueado/a pelo/a proprietário/a ou pelo remetente da questão.
+issues.comment.blocked_by_user = Não pode comentar nesta questão porque foi bloqueado(a) pelo(a) proprietário(a) ou pelo autor da questão.
pulls.merged_title_desc_one = integrou %[1]d cometimento do ramo %[2]s
no ramo %[3]s
%[4]s
pulls.agit_explanation = Criado usando a sequência de trabalho AGit. AGit deixa os contribuidores proporem alterações usando "git push" sem criar uma derivação ou um ramo novo.
settings.new_owner_blocked_doer = O/A novo/a proprietário/a bloqueou-o/a.
@@ -2872,6 +2898,11 @@ summary_card_alt = Cartão de resumo do repositório %s
release.summary_card_alt = Cartão de resumo de um lançamento com o título "%s" no repositório %s
archive.pull.noreview = Este repositório está arquivado. Não é possível rever os pedidos de integração.
editor.commit_email = Endereço de email do cometimento
+commits.view_single_diff = Ver alterações a este ficheiro introduzidas neste cometimento
+pulls.comment.blocked_by_user = Não pode comentar este pedido de integração porque está bloqueado pelo(a) proprietário(a) do repositório ou pelo(a) autor(a) do pedido de integração.
+issues.reopen.blocked_by_user = Não pode reabrir esta questão porque está bloqueado pelo(a) proprietário(a) do repositório ou pelo autor da questão.
+pulls.editable = Editável
+pulls.editable_explanation = Este pedido de integração permite edições dos responsáveis. Pode contribuir diretamente para ele.
[graphs]
component_loading=A carregar %s...
@@ -3007,8 +3038,8 @@ teams.invite.by=Convidado(a) por %s
teams.invite.description=Clique no botão abaixo para se juntar à equipa.
follow_blocked_user = Não pode seguir esta organização porque esta organização bloqueou-o/a.
open_dashboard = Abrir painel de controlo
-settings.change_orgname_redirect_prompt.with_cooldown.one = O nome de utilizador antigo estará disponível para todos após um período de espera de %[1]d dia, podendo ainda reivindicar o nome de utilizador antigo durante o período de espera.
-settings.change_orgname_redirect_prompt.with_cooldown.few = O nome de utilizador antigo estará disponível para todos após um período de espera de %[1]d dias, podendo ainda reivindicar o nome de utilizador antigo durante o período de espera.
+settings.change_orgname_redirect_prompt.with_cooldown.one = O nome antigo da organização estará disponível para todos após um período de espera de %[1]d dia, podendo ainda reivindicar o nome antigo durante o período de espera.
+settings.change_orgname_redirect_prompt.with_cooldown.few = O nome antigo da organização estará disponível para todos após um período de espera de %[1]d dias, podendo ainda reivindicar o nome antigo durante o período de espera.
[admin]
dashboard=Painel de controlo
@@ -3835,7 +3866,7 @@ alt.install = Instalar pacote
alt.repository = Informação do repositório
alt.repository.architectures = Arquiteturas
alt.repository.multiple_groups = Este pacote está disponível em vários grupos.
-alt.setup = Adicionar um repositório à lista de repositórios ligados (escolha a arquitetura necessária em vez de '_arch_'):
+alt.setup = Adicionar um repositório à lista de repositórios ligados (escolha a arquitetura necessária em vez de "_arch_"):
[secrets]
secrets=Segredos
@@ -3956,6 +3987,7 @@ workflow.dispatch.invalid_input_type = Tipo de entrada "%s" inválido.
runs.expire_log_message = Os registos foram purgados por serem demasiado antigos.
runs.no_workflows.help_no_write_access = Para aprender sobre Forgejo Actions, vejaa documentação.
runs.no_workflows.help_write_access = Não sabe como começar com o Forgejo Actions? Consulte o início rápido na documentação do utilizador para escrever a sua primeira sequência de trabalho, depois prepare um executor Forgejo para executar os seus trabalhos.
+variables.not_found = Não foi possível encontrar a variável.
[projects]
type-1.display_name=Planeamento individual
diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini
index a669e87853..dc5100481c 100644
--- a/options/locale/locale_ru-RU.ini
+++ b/options/locale/locale_ru-RU.ini
@@ -110,7 +110,7 @@ preview=Предпросмотр
loading=Загрузка…
error=Ошибка
-error404=Cтраница, которую вы пытаетесь открыть, не существует, либо у вас недостаточно прав для ее просмотра.
+error404=Cтраница, которую вы пытаетесь открыть, не существует, была удалена, либо у вас недостаточно прав для её просмотра.
go_back=Назад
never=Никогда
@@ -206,6 +206,10 @@ table_modal.header = Создание таблицы
table_modal.placeholder.header = Заголовок
table_modal.placeholder.content = Содержимое
table_modal.label.rows = Кол-во строк
+link_modal.header = Добавить ссылку
+link_modal.url = Ссылка
+link_modal.description = Описание
+link_modal.paste_reminder = Имея ссылку в буфере обмена, вы можете вставить её напрямую в текст, чтобы создать ссылку с описанием.
[filter]
string.asc=A - Я
@@ -1063,6 +1067,26 @@ change_username_redirect_prompt.with_cooldown.one = Прежнее имя буд
change_username_redirect_prompt.with_cooldown.few = Прежнее имя будет доступно для использования другим пользователям после истечения защиты в %[1]d дней. Вы сможете вернуть его себе во время срока защиты.
keep_pronouns_private = Показывать местоимения только зарегистрированным пользователям
keep_pronouns_private.description = Местоимения будут скрыты от пользователей, не имеющих учётных записей на сервере.
+quota.applies_to_user = Эти ограничения хранилища применяются к вашей учётной записи
+quota.applies_to_org = Эти ограничения хранилища применяются к этой организации
+quota.sizes.repos.public = Общедоступные репозитории
+storage_overview = Использование места
+quota = Ограничения хранилища
+quota.rule.exceeded = Превышено
+quota.rule.exceeded.helper = Суммарный объём объектов в этом правиле превысил допустимый.
+quota.rule.no_limit = Неограниченно
+quota.sizes.all = Всё
+quota.sizes.repos.all = Репозитории
+quota.sizes.repos.private = Частные репозитории
+quota.sizes.git.all = Содержимое Git
+quota.sizes.git.lfs = Git LFS
+quota.sizes.wiki = Вики
+quota.sizes.assets.packages.all = Пакеты
+quota.sizes.assets.all = Объекты
+quota.sizes.assets.attachments.all = Все прикреплённые файлы
+quota.sizes.assets.attachments.releases = Файлы выпусков
+quota.sizes.assets.attachments.issues = Файлы задач
+quota.sizes.assets.artifacts = Артефакты
[repo]
owner=Владелец
@@ -2684,7 +2708,7 @@ object_format = Формат объекта
clone_in_vscodium = Клонировать в VSCodium
mirror_sync = синхронизирован
blame.ignore_revs = Правки в .git-blame-ignore-revs проигнорированы. Нажмите здесь, чтобы обойти этот файл и просмотреть авторов полноценно.
-issues.blocked_by_user = Невозможно создать задачу в этом репозитории, т.к. вы заблокированы его владельцем.
+issues.blocked_by_user = Создание задач невозможно в этом репозитории, т.к. вы заблокированы его владельцем.
settings.new_owner_blocked_doer = Вы заблокированы новым владельцем.
settings.add_collaborator_blocked_them = Невозможно добавить соучастника, т.к. им заблокирован владелец репозитория.
pulls.blocked_by_changed_protected_files_1 = Этот запрос на слияние заблокирован, т.к. им изменяется защищённый файл:
@@ -2693,8 +2717,8 @@ pulls.blocked_by_outdated_branch = Этот запрос на слияние з
pulls.blocked_by_changed_protected_files_n = Этот запрос на слияние заблокирован, т.к. им изменяются защищённые файлы:
blame.ignore_revs.failed = Не удалось проигнорировать правки из .git-blame-ignore-revs.
desc.sha256 = SHA256
-archive.title = Этот репозиторий архивирован. Вы можете просматривать его содержимое или клонировать, но не добавлять новые комиты, открывать задачи или запросы на слияние.
-archive.title_date = С %s этот репозиторий архивирован. Вы можете просматривать его содержимое или клонировать, но не добавлять новые комиты, открывать задачи или запросы на слияние.
+archive.title = Этот репозиторий архивирован. Вы можете просматривать содержимое или клонировать, но не вносить изменения: добавлять коммиты, создавать задачи и запросы слияний.
+archive.title_date = С %s этот репозиторий архивирован. Вы можете просматривать содержимое или клонировать, но не вносить изменения: добавлять коммиты, создавать задачи и запросы слияний.
migrate.forgejo.description = Перенести данные с codeberg.org или другого сервера Forgejo.
generated = Сгенерированный
pulls.review_only_possible_for_full_diff = Оставить отзыв можно только при просмотре всех различий
@@ -2878,6 +2902,10 @@ editor.commit_email = Эл. почта автора
commits.view_single_diff = Посмотреть изменения в этом файле из этого коммита
pulls.editable = Изменяемый
pulls.editable_explanation = Автор разрешил изменения от соучастников. Вы можете напрямую отправлять в него изменения.
+issues.reopen.blocked_by_user = Повторное открытие задачи невозможно, т.к. вы заблокированы владельцем репозитория или автором задачи.
+pulls.comment.blocked_by_user = Вы не можете комментировать под этим запросом слияния, т.к. вы заблокированы владельцем репозитория или автором задачи.
+issues.filter_no_results = Ничего не нашлось
+issues.filter_no_results_placeholder = Попробуйте поискать по-другому.
[graphs]
component_loading_failed = Не удалось загрузить %s
@@ -3699,7 +3727,7 @@ details.project_site=Веб-сайт проекта
details.repository_site=Веб-сайт репозитория
details.documentation_site=Веб-сайт документации
details.license=Лицензия
-assets=Ресурсы
+assets=Объекты
versions=Версии
versions.view_all=Показать всё
dependency.id=ID
diff --git a/options/locale/locale_sl.ini b/options/locale/locale_sl.ini
index 0a948f0ec9..7754796558 100644
--- a/options/locale/locale_sl.ini
+++ b/options/locale/locale_sl.ini
@@ -1,23 +1,23 @@
[common]
language = Jezik
-passcode = Pristopna koda
+passcode = Vstopna koda
webauthn_error_timeout = Preden je bilo mogoče prebrati vaš ključ, je bil dosežen časovni rok. Ponovno naložite to stran in poskusite znova.
cancel = Prekliči
webauthn_sign_in = Pritisnite gumb na varnostnem ključu. Če varnostni ključ nima gumba, ga ponovno vstavite.
-create_new = Ustvarite…
+create_new = Ustvari …
disabled = Invalidi
go_back = Pojdi nazaj
licenses = Licence
-sign_in = Prijavite se
+sign_in = Prijava
activities = Dejavnosti
copy_content = Kopiranje vsebine
collaborative = Sodelovanje
archived = Arhivirano
-user_profile_and_more = Profil in nastavitve…
+user_profile_and_more = Profil in nastavitve …
view = Ogled
your_settings = Nastavitve
-explore = Raziščite
-return_to_forgejo = Vrnitev v Forgejo
+explore = Razišči
+return_to_forgejo = Nazaj na Forgejo
write = Napišite
webauthn_error_unknown = Zgodila se je neznana napaka. Prosimo, poskusite znova.
webauthn_reload = Ponovno polnjenje
@@ -38,10 +38,10 @@ page = Stran
concept_system_global = Globalno
forks = Vilice
concept_user_organization = Organizacija
-link_account = Povezava račun
+link_account = Poveži račun
your_profile = Profil
copy_hash = Kopiraj hash
-sign_out = Odjavite se
+sign_out = Odjava
settings = Nastavitve
locked = Zaklenjeno
error = Napaka
@@ -76,7 +76,7 @@ active_stopwatch = Aktivno sledenje času
organization = Organizacija
new_migrate = Nova migracija
save = Shrani
-sign_in_with_provider = Prijavite se z %s
+sign_in_with_provider = Prijava s/z %s
manage_org = Upravljanje organizacij
new_repo = Nov repozitorij
webauthn_error_unable_to_process = Strežnik ni mogel obdelati vaše zahteve.
@@ -84,24 +84,24 @@ register = Registracija
mirror = Zrcalo
access_token = Token za dostop
download_logs = Prenos dnevnikov
-webauthn_insert_key = Vstavite varnostni ključ
+webauthn_insert_key = Vnesite varnostni ključ
password = Geslo
webauthn_error_duplicated = Varnostni ključ za to zahtevo ni dovoljen. Prepričajte se, da ključ še ni registriran.
-template = Šablona
+template = Predloga
webauthn_press_button = Pritisnite gumb na varnostnem ključu…
unknown = Neznano
sign_up = Registracija
enable_javascript = To spletno mesto zahteva JavaScript.
twofa_scratch = Dvofaktorska koda Scratch
home = Domov
-powered_by = Poganja ga %s
+powered_by = Poganja %s
retry = Ponovite
preview = Predogled
mirrors = Ogledala
loading = Nalaganje…
show_full_screen = Prikaži celoten zaslon
webauthn_error_insecure = WebAuthn podpira samo varne povezave. Za testiranje prek protokola HTTP lahko uporabite izvor "localhost" ali "127.0.0.1"
-username = Usmerjevalno ime
+username = Uporabniško ime
tracked_time_summary = Povzetek spremljanega časa na podlagi filtrov seznama zadev
email = E-poštni naslov
captcha = CAPTCHA
@@ -111,7 +111,7 @@ milestones = Mejniki
ok = OK
copy_branch = Kopiranje imena veje
artifacts = Artefakti
-signed_in_as = Prijavil se je kot
+signed_in_as = Prijavljeni ste kot
remove = Odstrani
remove_all = Odstrani vse
remove_label_str = Odstranite element "%s"
diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini
index abdb012120..cbb42b3caa 100644
--- a/options/locale/locale_sv-SE.ini
+++ b/options/locale/locale_sv-SE.ini
@@ -77,7 +77,7 @@ write=Skriv
preview=Förhandsgranska
loading=Laddar…
-error404=Sidan du försöker nå finns inte eller så har du inte behörighet att se den.
+error404=Sidan du försöker nå finns inte, har tagits bort eller så har du inte behörighet att se den.
@@ -160,7 +160,7 @@ confirm_delete_selected = Bekräfta för att ta bort alla valda objekt?
webauthn_error_timeout = Timeout uppnåddes innan din nyckel kan läsas. Vänligen ladda om denna sida och försök igen.
filter.is_fork = Förgreningar
webauthn_error_duplicated = Säkerhetsnyckeln är inte tillåten för denna begäran. Se till att nyckeln inte redan är registrerad.
-filter.not_fork = Inte gafflar
+filter.not_fork = Inte förgrenade
remove_label_str = Ta bort objektet "%"
webauthn_use_twofa = Använd en tvåfaktorskod från din telefon
webauthn_error_insecure = WebAuthn stöder endast säkra anslutningar. För testning över HTTP kan du använda "localhost" eller "127.0.0.1"
diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini
index 59f8fb0f93..18fd4dbb5d 100644
--- a/options/locale/locale_uk-UA.ini
+++ b/options/locale/locale_uk-UA.ini
@@ -86,7 +86,7 @@ preview=Попередній перегляд
loading=Завантаження…
error=Помилка
-error404=Сторінка, до якої ви намагаєтеся звернутися або до , не існує або Ви не маєте права на її перегляд.
+error404=Сторінка, до якої ви намагаєтеся звернутися, не існує, її було видалено або ви не маєте права на її перегляд.
never=Ніколи
@@ -164,7 +164,7 @@ filter.not_fork = Не форки
filter.is_mirror = Дзеркала
filter.not_mirror = Не дзеркала
filter.not_template = Не шаблони
-error413 = Ви вичерпали свою частку.
+error413 = Ви вичерпали свою квоту.
invalid_data = Недійсні дані: %v
copy_path = Копіювати шлях
@@ -206,6 +206,10 @@ table_modal.header = Додати таблицю
table_modal.placeholder.header = Заголовок
table_modal.placeholder.content = Вміст
table_modal.label.rows = Рядки
+link_modal.description = Опис
+link_modal.url = URL
+link_modal.header = Додати посилання
+link_modal.paste_reminder = Підказка: якщо скопіювати URL-адресу в буфер обміну, можна створювати посилання, вставляючи її безпосередньо в редакторі.
[filter]
string.asc = А - Я
@@ -448,8 +452,8 @@ email_domain_blacklisted=З вказаним email реєстрація немо
authorize_application=Авторизувати програму
authorize_redirect_notice=Вас буде переадресовано до %s, якщо ви авторизуєте цю програму.
authorize_application_created_by=Ця програма створена %s.
-authorize_application_description=Якщо ви надасте цей доступ, то він матиме доступ до всіх ваших даних облікового запису, включаючи приватні репозиторії та організації.
-authorize_title=Авторизуйвати "%s" для доступу до вашого облікового запису?
+authorize_application_description=Якщо ви надасте дозвіл, то програма отримає доступ до всіх даних вашого облікового запису, включно з приватними репозиторіями та організаціями.
+authorize_title=Дозволити «%s» доступ до вашого облікового запису?
authorization_failed=Помилка авторизації
sspi_auth_failed=Помилка SSPI-автентифікації
password_pwned_err=Не вдалося виконати запит до HaveIBeenPwed
@@ -1050,6 +1054,25 @@ comment_type_group_reference = Посилання
ssh_key_verified_long = Ключ перевірений за допомогою токена й може підтверджувати коміти з будь-яких активованих адрес електронної пошти користувач_ки.
access_token_deletion_desc = Видалення токена скасує доступ програм, які використовують цей токен, до вашого облікового запису. Це незворотна дія. Продовжити?
oauth2_application_locked = Forgejo попередньо реєструє деякі програми OAuth2 при запуску, якщо це увімкнено в конфігурації. Щоб запобігти неочікуваній поведінці, їх не можна редагувати чи видаляти. Докладніше — в документації OAuth2.
+quota.rule.exceeded.helper = Загальний розмір об'єктів за цим правилом перевищує квоту.
+quota = Квота
+quota.sizes.repos.private = Приватні репозиторії
+quota.sizes.repos.public = Публічні репозиторії
+quota.sizes.git.all = Вміст Git
+quota.sizes.git.lfs = Git LFS
+quota.sizes.assets.packages.all = Пакунки
+quota.sizes.assets.artifacts = Артефакти
+quota.sizes.assets.attachments.issues = Вкладення задач
+quota.sizes.assets.attachments.releases = Вкладення випусків
+quota.sizes.wiki = Вікі
+quota.rule.no_limit = Не обмежено
+storage_overview = Огляд сховища
+quota.sizes.all = Усе
+quota.sizes.repos.all = Репозиторії
+quota.applies_to_user = До вашого облікового запису застосовано такі квоти
+quota.sizes.assets.attachments.all = Вкладення
+quota.applies_to_org = До цієї організації застосовано такі квоти
+quota.rule.exceeded = Перевищено
[repo]
owner=Власник
@@ -1766,8 +1789,8 @@ wiki.save_page=Зберегти сторінку
wiki.last_commit_info=%s редагував цю сторінку %s
wiki.edit_page_button=Редагувати
wiki.new_page_button=Нова сторінка
-wiki.file_revision=Ревізії сторінки
-wiki.wiki_page_revisions=Ревізії вікі сторінок
+wiki.file_revision=Версія сторінки
+wiki.wiki_page_revisions=Версії сторінок
wiki.back_to_wiki=Повернутись на сторінку Вікі
wiki.delete_page_button=Видалити сторінку
wiki.page_already_exists=Вікі-сторінка з таким самим ім'ям вже існує.
@@ -1815,8 +1838,8 @@ activity.title.unresolved_conv_1=%d Незавершене обговоренн
activity.title.unresolved_conv_n=%d Незавершених обговорень
activity.unresolved_conv_desc=Список всіх старих задач і Pull Request'ів з недавньої активністю, але ще не закритих або прийнятих.
activity.unresolved_conv_label=Відкрити
-activity.title.releases_1=%d Реліз
-activity.title.releases_n=%d Релізів
+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=У цей період не було здійснено жодних дій.
@@ -2030,7 +2053,7 @@ settings.event_issue_assign_desc=Задачу призначено або ска
settings.event_issue_label=Мітки
settings.event_issue_label_desc=Додавання або видалення міток задач.
settings.event_issue_milestone=Задача з етапом
-settings.event_issue_milestone_desc=Задача призначена на етап або видалена з етапу.
+settings.event_issue_milestone_desc=Етап призначено, видалено або змінено.
settings.event_issue_comment=Коментарі
settings.event_issue_comment_desc=Коментар задачі створено, видалено чи відредаговано.
settings.event_header_pull_request=Події запиту на злиття
@@ -2040,8 +2063,8 @@ settings.event_pull_request_assign=Призначення
settings.event_pull_request_assign_desc=Запит про злиття призначено або скасовано.
settings.event_pull_request_label=Мітки
settings.event_pull_request_label_desc=Мітки запиту на злиття оновлено або очищено.
-settings.event_pull_request_milestone=Запит на злиття призначений на етап
-settings.event_pull_request_milestone_desc=Запит на злиття призначений на етап або видалений з етапу.
+settings.event_pull_request_milestone=Етапи
+settings.event_pull_request_milestone_desc=Етап призначено, видалено або змінено.
settings.event_pull_request_comment=Коментарі
settings.event_pull_request_comment_desc=Коментар запиту на злиття створено, відредаговано чи видалено.
settings.event_pull_request_review=Відгуки
@@ -2235,7 +2258,7 @@ releases.desc=Відслідковувати версії проєкту і за
release.releases=Релізи
release.detail=Деталі релізу
release.tags=Теги
-release.new_release=Новий реліз
+release.new_release=Новий випуск
release.draft=Чернетка
release.prerelease=Пре-реліз
release.stable=Стабільний
@@ -2316,7 +2339,7 @@ issues.author_helper = Цей користувач - автор.
issues.close = Закрити задачу
issues.role.owner_helper = Цей користувач є власником цього репозиторію.
settings.mirror_settings.docs.more_information_if_disabled = Докладніше про push та pull дзеркала можна дізнатися тут:
-issues.comment.blocked_by_user = Ви не можете створити коментар до цієї задачі, оскільки вас заблокував власник репозиторію або автор цієї задачі.
+issues.comment.blocked_by_user = Ви не можете коментувати цю задачу, оскільки вас заблокував власник репозиторію або автор цієї задачі.
editor.add_file = Додати файл
from_comment = (коментар)
editor.add = Додати %s
@@ -2549,12 +2572,25 @@ mirror_address_protocol_invalid = Хибна URL-адреса. Лише адре
stars_remove_warning = Це вилучить усі зірки репозиторія.
mirror_use_ssh.not_available = SSH-вхід недоступний.
issues.num_reviews_one = %d відгук
-archive.title = Цей репозиторій архівовано. Ви можете переглядати файли і клонувати його, але не можете вносити жодних змін у стан цього репозиторія, зокрема робити push і створювати нові задачі, запити на злиття чи коментарі.
+archive.title = Цей репозиторій архівовано. Ви можете переглядати файли і клонувати його, але не можете вносити жодних змін у його стан, зокрема робити push і створювати нові задачі, запити на злиття чи коментарі.
settings.event_pull_request_review_request = Запити на відгук
-archive.title_date = Цей репозиторій архівовано %s. Ви можете переглядати файли і клонувати його, але не можете вносити жодних змін у стан цього репозиторія, зокрема робити push і створювати нові задачі, запити на злиття чи коментарі.
+archive.title_date = Цей репозиторій архівовано %s. Ви можете переглядати файли і клонувати його, але не можете вносити жодних змін у його стан, зокрема робити push і створювати нові задачі, запити на злиття чи коментарі.
settings.event_pull_request_review_request_desc = Створено або видалено запит на відгук до запиту на злиття.
archive.pull.noreview = Цей репозиторій архівовано. Ви не можете рецензувати запити на злиття.
issues.num_reviews_few = %d відгуків
+n_release_few = %s випусків
+release.releases_for = Випуски %s
+release.type_attachment = Вкладення
+n_release_one = %s випуск
+pulls.comment.blocked_by_user = Ви не можете коментувати цей запит на злиття, оскільки вас заблокував власник репозиторію або автор запиту на злиття.
+issues.reopen.blocked_by_user = Ви не можете знову відкрити цю задачу, оскільки вас заблокував власник репозиторію або автор задачі.
+settings.actions_desc = Увімкнути вбудовані конвеєри CI/CD з Діями Forgejo
+tree_path_not_found_commit = Шлях %[1]s не існує в коміті %[2]s
+pulls.blocked_by_user = Ви не можете створити запит на злиття в цьому репозиторії, оскільки вас заблокував власник репозиторію.
+issues.blocked_by_user = Ви не можете створювати задачі в цьому репозиторії, оскільки вас заблокував власник репозиторію.
+activity.commit = К-ть комітів
+issues.filter_no_results_placeholder = Спробуйте змінити пошукові фільтри.
+issues.filter_no_results = Нічого не знайдено
[graphs]
contributors.what = внески
@@ -2679,6 +2715,7 @@ teams.invite.title = Вас запрошено приєднатися до ко
form.name_reserved = Назву організації «%s» зарезервовано.
settings.change_orgname_redirect_prompt.with_cooldown.one = Стара назва буде доступна всім після періоду захисту, який триватиме %[1]d день. Протягом періоду захисту ви ще можете повернути стару назву.
settings.change_orgname_redirect_prompt.with_cooldown.few = Стара назва буде доступна всім після періоду захисту, який триватиме %[1]d днів. Протягом періоду захисту ви ще можете повернути стару назву.
+teams.none_access = Немає доступу
[admin]
dashboard=Панель управління
@@ -2942,7 +2979,7 @@ auths.tip.google_plus=Отримайте облікові дані клієнт
auths.tip.openid_connect=Використовуйте OpenID Connect Discovery URL (/etc/pacman.conf
:
arch.version.properties = Властивості версії
arch.version.description = Опис
-chef.install = Аби встановити пакунок, запустіть команду:
+chef.install = Аби встановити пакунок, виконайте команду:
container.details.platform = Платформа
container.details.type = Тип образу
container.pull = Завантажити образ із командного рядка:
details.repository_site = Вебсторінка репозиторію
composer.dependencies = Залежності
-debian.install = Аби встановити пакунок, запустіть команду:
+debian.install = Аби встановити пакунок, виконайте команду:
debian.repository = Про репозиторій
debian.repository.distributions = Дистрибутиви
alpine.repository.architectures = Архітектури
arch.version.depends = Залежить
go.install = Встановити пакунок із командного рядка:
debian.repository.architectures = Архітектури
-helm.install = Аби встановити пакунок, запустіть команду:
+helm.install = Аби встановити пакунок, виконайте команду:
keywords = Ключові слова
assets = Ресурси
versions = Версії
@@ -3351,6 +3391,17 @@ alt.install = Встановити пакунок
alt.registry = Налаштуйте цей реєстр із командного рядка:
debian.registry = Налаштуйте цей реєстр із командного рядка:
debian.registry.info = Виберіть $distribution і $component зі списку нижче.
+npm.install = Аби встановити пакунок, використовуючи npm, виконайте команду:
+alt.registry.install = Щоб установити пакунок, виконайте команду:
+swift.install2 = і виконайте команду:
+rubygems.install = Аби встановити пакунок, використовуючи gem, виконайте команду:
+alt.setup = Додайте репозиторій до списку підключених репозиторіїв (виберіть потрібну архітектуру замість «_arch_»):
+pypi.install = Аби встановити пакунок, використовуючи pip, виконайте команду:
+nuget.install = Аби встановити пакунок, використовуючи NuGet, виконайте команду:
+pub.install = Аби встановити пакунок, використовуючи Dart, виконайте команду:
+rpm.install = Щоб установити пакунок, виконайте команду:
+maven.install = Для використання пакунка включіть у блок dependencies
у файлі pom.xml
таке:
+vagrant.install = Щоб додати скриньку Vagrant, виконайте команду:
[secrets]
deletion = Видалити секрет
@@ -3428,6 +3479,9 @@ need_approval_desc = Потрібне схвалення для запуску
variables.not_found = Не вдалося знайти змінну.
runners.task_list.done_at = Завершено
runners.last_online = Востаннє в мережі
+runs.no_workflows.help_no_write_access = Щоб дізнатися більше про Дії Forgejo, читайте документацію.
+runs.no_workflows.help_write_access = Не знаєте, як почати роботу з Діями Forgejo? Перегляньте посібник для початківців у документації, щоб написати свій перший робочий потік, а потім налаштуйте ранер Forgejo для виконання завдань.
+unit.desc = Керування вбудованими конвеєрами CI/CD з Діями Forgejo.
diff --git a/options/locale/locale_vi.ini b/options/locale/locale_vi.ini
index b12bac0c89..57e592a209 100644
--- a/options/locale/locale_vi.ini
+++ b/options/locale/locale_vi.ini
@@ -57,7 +57,7 @@ forks = Các phân nhánh
activities = Hoạt động
pull_requests = Yêu cầu thêm mã
save = Lưu
-issues =
+issues =
enabled = Bật
disabled = Tắt
copy = Chép
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index a73f1e22f5..b9fbc4b0ff 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -87,10 +87,10 @@ rerun=重新运行
rerun_all=重新运行所有任务
save=保存
add=添加
-add_all=添加所有
+add_all=全部添加
remove=移除
-remove_all=移除所有
-remove_label_str=删除标签 "%s"
+remove_all=全部移除
+remove_label_str=删除标签“%s”
edit=编辑
view=查看
@@ -112,7 +112,7 @@ preview=预览
loading=正在加载…
error=错误
-error404=您正尝试访问的页面 不存在 或 您尚未被授权 查看该页面。
+error404=您尝试访问的页面不存在、已被移除或您无权查看。
go_back=返回
never=从未
@@ -143,7 +143,7 @@ confirm_delete_selected=确认删除所有选中项目?
name=名称
value=值
filter = 筛选
-filter.clear = 清除筛选条件
+filter.clear = 清除条件
filter.is_archived = 已存档
filter.not_archived = 未存档
filter.is_fork = 是派生
@@ -206,6 +206,10 @@ table_modal.label.columns = 列数
table_modal.label.rows = 行数
buttons.new_table.tooltip = 添加表格
table_modal.placeholder.content = 内容
+link_modal.header = 添加链接
+link_modal.url = URL
+link_modal.description = 描述
+link_modal.paste_reminder = 提示:您可以将剪贴板中的 URL 直接粘贴到编辑器创建链接。
[filter]
string.asc=A - Z
@@ -243,7 +247,7 @@ user=用户名
password=数据库用户密码
db_name=数据库名称
db_schema=架构模式
-db_schema_helper=留空则数据库中默认值为("public")。
+db_schema_helper=留空则数据库中默认值为("public")。
ssl_mode=SSL
path=数据库文件路径
sqlite_helper=SQLite3 数据库的文件路径。%[2]s
合并至 %[3]s
pulls.merged_title_desc_few=于 %[4]s 将 %[1]d 次代码提交从 %[2]s
合并至 %[3]s
@@ -1925,7 +1949,7 @@ pulls.has_merged=失败:合并请求已经被合并,您不能再次合并或
pulls.push_rejected=合并失败:推送被拒绝。请查看此仓库的 Git 钩子。
pulls.push_rejected_summary=详细拒绝信息
pulls.push_rejected_no_message=推送失败:此推送被拒绝但未提供其他信息。请检查此仓库的 Git 钩子
-pulls.open_unmerged_pull_exists=`您不能执行重新打开操作, 因为已经存在相同的合并请求 (#%d)。`
+pulls.open_unmerged_pull_exists=`您不能执行重新打开操作, 因为已经存在相同的合并请求(#%d)。`
pulls.status_checking=一些检测仍在等待运行
pulls.status_checks_success=所有检测均成功
pulls.status_checks_warning=一些检查报告了警告
@@ -1951,7 +1975,7 @@ pulls.cmd_instruction_merge_desc=合并更改并在 Forgejo 上更新。
pulls.clear_merge_message=清除合并信息
pulls.clear_merge_message_hint=清除合并消息只会删除提交消息内容,并保留生成的 git 附加内容,如“Co-Authored-By …”。
-pulls.auto_merge_button_when_succeed=(当检查成功时)
+pulls.auto_merge_button_when_succeed=(当检查成功时)
pulls.auto_merge_when_succeed=在所有检查成功后自动合并
pulls.auto_merge_newly_scheduled=合并请求计划在所有检查成功后合并。
pulls.auto_merge_has_pending_schedule=%[1]s 安排此拉取请求在所有检查成功时自动合并 %[2]s。
@@ -1964,11 +1988,11 @@ pulls.auto_merge_newly_scheduled_comment=`已安排此拉取请求在所有检
pulls.auto_merge_canceled_schedule_comment=`已取消当所有检查成功后自动合并此拉取请求 %[1]s`
pulls.delete.title=删除此拉取请求?
-pulls.delete.text=你真的要删除这个拉取请求吗? (这将永久删除所有内容。如果你打算将内容存档,请考虑关闭它)
+pulls.delete.text=你真的要删除这个拉取请求吗?(这将永久删除所有内容。如果你打算将内容存档,请考虑关闭它)
pulls.recently_pushed_new_branches=您已于%[2]s推送了分支 %[1]s
-pull.deleted_branch=(已删除): %s
+pull.deleted_branch=(已删除):%s
milestones.new=新的里程碑
milestones.closed=于 %s关闭
@@ -2198,7 +2222,7 @@ settings.enable_timetracker=启用时间跟踪
settings.allow_only_contributors_to_track_time=仅允许成员跟踪时间
settings.pulls_desc=启用合并请求
settings.pulls.ignore_whitespace=忽略空格冲突
-settings.pulls.enable_autodetect_manual_merge=启用自动检测手动合并 (注意:在某些特殊情况下可能发生错误判断)
+settings.pulls.enable_autodetect_manual_merge=启用自动检测手动合并(注意:在某些特殊情况下可能发生错误判断)
settings.pulls.allow_rebase_update=允许通过变基更新拉取请求分支
settings.pulls.default_delete_branch_after_merge=默认合并后删除合并请求分支
settings.pulls.default_allow_edits_from_maintainers=默认开启允许维护者编辑
@@ -2207,7 +2231,7 @@ settings.packages_desc=启用仓库软件包注册中心
settings.projects_desc=启用仓库项目
settings.actions_desc=使用 Forgejo Actions 启用集成 CI/CD 管道
settings.admin_settings=管理员设置
-settings.admin_enable_health_check=启用仓库健康检查 (git fsck)
+settings.admin_enable_health_check=启用仓库健康检查(git fsck)
settings.admin_code_indexer=代码索引器
settings.admin_stats_indexer=代码统计索引器
settings.admin_indexer_commit_sha=上次索引的提交
@@ -2237,8 +2261,8 @@ settings.transfer_desc=您可以将仓库转移至您拥有管理员权限的帐
settings.transfer_form_title=输入仓库名称以做确认:
settings.transfer_in_progress=当前正在进行转让。 如果你想将此代码库转让给另一个用户,请取消它。
settings.transfer_notices_1=- 如果将此仓库转移给其他用户, 您将失去对此仓库的访问权限。
-settings.transfer_notices_2=-如果将其转移到您 (共同) 拥有的组织,您可以继续访问该仓库。
-settings.transfer_notices_3=- 如果仓库是私有的并且被转移给某个用户,那么此操作可以确保该用户至少具有读权限(以及必要时的更改权限)。
+settings.transfer_notices_2=-如果将其转移到您(共同) 拥有的组织,您可以继续访问该仓库。
+settings.transfer_notices_3=- 如果仓库是私有的并且被转移给某个用户,那么此操作可以确保该用户至少具有读权限(以及必要时的更改权限)。
settings.transfer_owner=新拥有者
settings.transfer_perform=执行转让
settings.transfer_started=该代码库已被标记为转让并等待来自 %s 的确认
@@ -2249,10 +2273,10 @@ settings.trust_model.default=默认信任模型
settings.trust_model.default.desc=为此安装使用默认仓库信任模型。
settings.trust_model.collaborator=协作者
settings.trust_model.collaborator.long=协作者:信任协作者的签名
-settings.trust_model.collaborator.desc=此仓库中协作者的有效签名将被标记为「可信」(无论它们是否是提交者),签名只符合提交者时将标记为「不可信」,都不匹配时标记为「不匹配」。
+settings.trust_model.collaborator.desc=此仓库中协作者的有效签名将被标记为「可信」(无论它们是否是提交者),签名只符合提交者时将标记为「不可信」,都不匹配时标记为「不匹配」。
settings.trust_model.committer=提交者
-settings.trust_model.committer.long=提交者: 信任与提交者相符的签名 (此特性类似 GitHub,这会强制采用 Forgejo 作为提交者和签名者)
-settings.trust_model.committer.desc=有效签名只有和提交者相匹配才会被标记为“受信任”,否则它们将被标记为“不匹配”。这强制 Forgejo 成为签名提交的提交者,而实际提交者被加上 Co-authored-by: 和 Co-committed-by: 的标记。 默认的 Forgejo 密钥必须匹配数据库中的一名用户。
+settings.trust_model.committer.long=提交者: 信任与提交者相符的签名(此特性类似 GitHub,这会强制采用 Forgejo 作为提交者和签名者)
+settings.trust_model.committer.desc=有效签名只有和提交者相匹配才会被标记为“受信任”,否则它们将被标记为“不匹配”。这强制 Forgejo 成为签名提交的提交者,而实际提交者被加上 Co-authored-by:和 Co-committed-by:的标记。 默认的 Forgejo 密钥必须匹配数据库中的一名用户。
settings.trust_model.collaboratorcommitter=协作者+提交者
settings.trust_model.collaboratorcommitter.long=协作者+提交者:信任协作者同时是提交者的签名
settings.trust_model.collaboratorcommitter.desc=此仓库中协作者的有效签名在他同时是提交者时将被标记为「可信」,签名只匹配了提交者时将标记为「不可信」,都不匹配时标记为「不匹配」。这会强制 Forgejo 成为签名者和提交者,实际的提交者将被标记于提交消息结尾处的「Co-Authored-By:」和「Co-Committed-By:」。默认的 Forgejo 签名密钥必须匹配数据库中的一个用户密钥。
@@ -2377,7 +2401,7 @@ settings.event_package_desc=软件包已在仓库中被创建或删除。
settings.branch_filter=分支过滤
settings.branch_filter_desc=推送、创建,删除分支事件的分支白名单,使用 glob 模式匹配指定。若为空或 *
,则将报告所有分支的事件。语法文档见 %[2]s。示例:master
,{master,release*}
。
settings.authorization_header=授权标头
-settings.authorization_header_desc=当存在时将被作为授权标头包含在内。例如: %s。
+settings.authorization_header_desc=当存在时将被作为授权标头包含在内。例如:%s。
settings.active=激活
settings.active_helper=触发事件的信息将发送到此 webhook 网址。
settings.add_hook_success=Web 钩子已添加。
@@ -2434,11 +2458,11 @@ settings.protect_this_branch_desc=阻止删除并限制Git推送和合并到分
settings.protect_disable_push=禁用推送
settings.protect_disable_push_desc=此分支不允许推送。
settings.protect_enable_push=启用推送
-settings.protect_enable_push_desc=任何拥有写访问权限的人将被允许推送到此分支(但不能强行推送)。
+settings.protect_enable_push_desc=任何拥有写访问权限的人将被允许推送到此分支(但不能强行推送)。
settings.protect_enable_merge=启用合并
settings.protect_enable_merge_desc=任何具有写入权限的人都可以将合并请求合并到此分支中。
settings.protect_whitelist_committers=受白名单限制的推送
-settings.protect_whitelist_committers_desc=只有列入白名单的用户或团队才能被允许推送到此分支(但不能强行推送)。
+settings.protect_whitelist_committers_desc=只有列入白名单的用户或团队才能被允许推送到此分支(但不能强行推送)。
settings.protect_whitelist_deploy_keys=将具有推送权限的部署密钥加入白名单。
settings.protect_whitelist_users=推送白名单用户
settings.protect_whitelist_search_users=搜索用户...
@@ -2542,11 +2566,11 @@ settings.lfs_invalid_locking_path=无效路径:%s
settings.lfs_invalid_lock_directory=无法锁定目录:%s
settings.lfs_lock_already_exists=锁已经存在:%s
settings.lfs_lock=锁定
-settings.lfs_lock_path=要锁定的文件路径...
+settings.lfs_lock_path=要锁定的文件路径…
settings.lfs_locks_no_locks=无锁定
settings.lfs_lock_file_no_exist=锁定的文件在默认分支中不存在
settings.lfs_force_unlock=强制解锁
-settings.lfs_pointers.found=找到 %d 个块指针 - %d 个关联, %d 个未关联(%d 个从仓库丢失)
+settings.lfs_pointers.found=找到 %d 个块指针 - %d 个关联, %d 个未关联(%d 个从仓库丢失)
settings.lfs_pointers.sha=Blob SHA
settings.lfs_pointers.oid=OID
settings.lfs_pointers.inRepo=在仓库中
@@ -2726,8 +2750,8 @@ rss.must_be_on_branch = 您必须处于一个分支上才能拥有一个RSS订
admin.manage_flags = 管理标志
admin.failed_to_replace_flags = 替换仓库标志失败
clone_in_vscodium = 在 VSCodium 中克隆
-issues.blocked_by_user = 你无法在此仓库创建工单,因为你已被仓库所有者屏蔽。
-issues.comment.blocked_by_user = 你无法对此工单进行评论,因为你已被仓库所有者或此工单的发布者屏蔽。
+issues.blocked_by_user = 由于你已被仓库所有者屏蔽,你无法在此仓库创建工单。
+issues.comment.blocked_by_user = 因为你已被仓库所有者或工单作者屏蔽,你无法对此工单进行评论。
settings.wiki_rename_branch_main_desc = 将百科内部使用的分支重命名为“%s”。此更改是永久性的且不可撤销。
editor.invalid_commit_mail = 用于创建提交的邮件地址无效。
pulls.blocked_by_user = 你无法在此仓库上创建合并请求,因为您已被仓库所有者屏蔽。
@@ -2780,7 +2804,7 @@ editor.push_out_of_date = 推送似乎已过期。
settings.enforce_on_admins = 对仓库的管理员适用该规则
settings.enforce_on_admins_desc = 使仓库管理员也须遵守此规则。
settings.sourcehut_builds.secrets = 密钥
-size_format = %[1]s: %[2]s, %[3]s: %[4]s
+size_format = %[1]s:%[2]s, %[3]s:%[4]s
settings.sourcehut_builds.graphql_url = GraphQL URL (例如: https://builds.sr.ht/query)
settings.add_webhook.invalid_path = 路径中不能包含“.”或“..”,也不能在开头或结尾中使用斜杠。
settings.sourcehut_builds.secrets_helper = 给予任务访问构建密钥的权限(需要 SECRETS:RO 权限)
@@ -2877,6 +2901,10 @@ archive.pull.noreview = 此仓库已存档,您无法评审合并请求。
commits.view_single_diff = 查看该提交对本文件的更改
pulls.editable = 可编辑
pulls.editable_explanation = 此合并请求允许维护者进行编辑。你可以直接向其贡献。
+issues.reopen.blocked_by_user = 由于你已被仓库所有者或工单作者屏蔽,你不能重新打开此工单。
+pulls.comment.blocked_by_user = 由于你已被仓库所有者或合并请求作者屏蔽,你不能在此合并请求发表评论。
+issues.filter_no_results = 无结果
+issues.filter_no_results_placeholder = 尝试调整搜索筛选条件。
[graphs]
component_loading=正在加载 %s…
@@ -2908,7 +2936,7 @@ team_desc_helper=描述团队的目的或作用。
team_access_desc=仓库权限
team_permission_desc=权限
team_unit_desc=允许访问仓库单元
-team_unit_disabled=(已禁用)
+team_unit_disabled=(已禁用)
form.name_reserved=组织名称 '%s' 是被保留的。
form.name_pattern_not_allowed=仓库名称中不允许使用 "%s"。
@@ -3045,15 +3073,15 @@ dashboard.operation_run=执行
dashboard.clean_unbind_oauth=清理未绑定的 OAuth 连接
dashboard.clean_unbind_oauth_success=所有未绑定的 OAuth 连接已被删除。
dashboard.task.started=已开始任务:%[1]s
-dashboard.task.process=任务: %[1]s
-dashboard.task.cancelled=任务: %[1]s 已取消: %[3]s
-dashboard.task.error=任务中的错误: %[1]s: %[3]s
-dashboard.task.finished=任务: %[2]s 启动的 %[1]s 已完成
+dashboard.task.process=任务:%[1]s
+dashboard.task.cancelled=任务:%[1]s 已取消:%[3]s
+dashboard.task.error=任务中的错误:%[1]s:%[3]s
+dashboard.task.finished=任务:%[2]s 启动的 %[1]s 已完成
dashboard.task.unknown=未知任务: %[1]s
dashboard.cron.started=已开始计划任务:%[1]s
dashboard.cron.process=计划任务:%[1]s
-dashboard.cron.cancelled=定时任务: %[1]s 已取消: %[3]s
-dashboard.cron.error=任务中的错误: %s: %[3]s
+dashboard.cron.cancelled=定时任务:%[1]s 已取消:%[3]s
+dashboard.cron.error=任务中的错误: %s:%[3]s
dashboard.cron.finished=任务:%[1]s 已经完成
dashboard.delete_inactive_accounts=删除所有未激活的帐户
dashboard.delete_inactive_accounts.started=删除所有未激活的账户任务已启动。
@@ -3183,9 +3211,9 @@ emails.email_manage_panel=管理用户邮件地址
emails.primary=主要的
emails.activated=已激活
emails.filter_sort.email=电子邮件
-emails.filter_sort.email_reverse=电子邮件(逆序)
+emails.filter_sort.email_reverse=电子邮件(逆序)
emails.filter_sort.name=用户名
-emails.filter_sort.name_reverse=用户名(倒序)
+emails.filter_sort.name_reverse=用户名(倒序)
emails.updated=电子邮件已更新
emails.not_updated=无法更新请求的电子邮件地址: %v
emails.duplicate_active=此电子邮件地址已被另一个用户激活使用。
@@ -3266,12 +3294,12 @@ auths.search_page_size=分页大小
auths.filter=用户过滤规则
auths.admin_filter=管理员过滤规则
auths.restricted_filter=受限的过滤器
-auths.restricted_filter_helper=留空则不将任何用户设置为受限。使用星号('*') 将所有不匹配管理过滤器的用户设置为受限用户。
-auths.verify_group_membership=验证 LDAP 组成员资格 (留空过滤器跳过)
+auths.restricted_filter_helper=留空则不将任何用户设置为受限。使用星号('*') 将所有不匹配管理过滤器的用户设置为受限用户。
+auths.verify_group_membership=验证 LDAP 组成员资格(留空过滤器跳过)
auths.group_search_base=群组搜索基础 DN
auths.group_attribute_list_users=包含用户列表的群组属性
auths.user_attribute_in_group=群组中列出的用户属性
-auths.map_group_to_team=将 LDAP 组映射到组织团队 (留空字段则跳过)
+auths.map_group_to_team=将 LDAP 组映射到组织团队(留空字段则跳过)
auths.map_group_to_team_removal=如果用户不属于相应的 LDAP 组,从已同步团队中移除用户
auths.enable_ldap_groups=启用 LDAP 组
auths.ms_ad_sa=MS AD 搜索属性
@@ -3282,12 +3310,12 @@ auths.allowed_domains=域名白名单
auths.allowed_domains_helper=每个域名用逗号分隔,如要允许任意域名则留空。
auths.skip_tls_verify=忽略 TLS 验证
auths.force_smtps=强制 SMTPS
-auths.force_smtps_helper=SMTPS 始终用于 465 端口。设置此项会强制其他端口也使用 SMTPS。(否则,如果主机支持,将在其他端口上使用 STARTTLS。)
+auths.force_smtps_helper=SMTPS 始终用于 465 端口。设置此项会强制其他端口也使用 SMTPS。(否则,如果主机支持,将在其他端口上使用 STARTTLS。)
auths.helo_hostname=HELO 主机名
auths.helo_hostname_helper=用 HELO 发送的主机名。 留空发送当前主机名。
auths.disable_helo=禁用 HELO
auths.pam_service_name=PAM 服务名称
-auths.pam_email_domain=PAM 电子邮件域(可选)
+auths.pam_email_domain=PAM 电子邮件域(可选)
auths.oauth2_provider=OAuth2 提供程序
auths.oauth2_icon_url=图标 URL
auths.oauth2_clientID=客户端 ID (键)
@@ -3306,9 +3334,9 @@ auths.oauth2_required_claim_name=必须填写 Claim 声明的名称
auths.oauth2_required_claim_name_helper=设置此名称,只有具有此名称的声明(Claim)的用户可从此源登录
auths.oauth2_required_claim_value=必须填写 Claim 声明的值
auths.oauth2_required_claim_value_helper=设置此值,只有拥有对应的声明(Claim)的名称和值的用户才被允许从此源登录
-auths.oauth2_group_claim_name=用于提供用户组名称的 Claim 声明名称。(可选)
-auths.oauth2_admin_group=管理员用户组的 Claim 声明值。(可选 - 需要上面的声明名称)
-auths.oauth2_restricted_group=受限用户组的 Claim 声明值。(可选 - 需要上面的声明名称)
+auths.oauth2_group_claim_name=用于提供用户组名称的 Claim 声明名称。(可选)
+auths.oauth2_admin_group=管理员用户组的 Claim 声明值。(可选 - 需要上面的声明名称)
+auths.oauth2_restricted_group=受限用户组的 Claim 声明值。(可选 - 需要上面的声明名称)
auths.oauth2_map_group_to_team=映射声明的组到组织团队。(可选 - 要求在上面填写声明的名字)
auths.oauth2_map_group_to_team_removal=如果用户不属于相应的组,从已同步团队中移除用户
auths.enable_auto_register=允许自动注册
@@ -3317,9 +3345,9 @@ auths.sspi_auto_create_users_helper=允许 SSPI 认证在用户第一次登录
auths.sspi_auto_activate_users=自动激活用户
auths.sspi_auto_activate_users_helper=允许 SSPI 认证自动激活新用户
auths.sspi_strip_domain_names=从用户名中删除域名部分
-auths.sspi_strip_domain_names_helper=如果选中此项,域名将从登录名中删除(例如,"DOMAIN\user"和"user@example.org",两者都将变成只是 "user")。
+auths.sspi_strip_domain_names_helper=如果选中此项,域名将从登录名中删除(例如,"DOMAIN\user"和"user@example.org",两者都将变成只是 "user")。
auths.sspi_separator_replacement=要使用的分隔符代替\, / 和 @
-auths.sspi_separator_replacement_helper=用于替换下级登录名称分隔符的字符 (例如 "DOMAIN\user") 中的 \ 和用户主名字(如"user@example.org"中的 @)。
+auths.sspi_separator_replacement_helper=用于替换下级登录名称分隔符的字符(例如 "DOMAIN\user") 中的 \ 和用户主名字(如"user@example.org"中的 @)。
auths.sspi_default_language=默认语言
auths.sspi_default_language_helper=SSPI 认证方法为用户自动创建的默认语言。如果您想要自动检测到语言,请留空。
auths.tips=帮助提示
@@ -3332,13 +3360,13 @@ auths.tip.dropbox=在 %s 上创建一个新的应用程序
auths.tip.facebook=`在 %s 注册一个新的应用,并添加产品"Facebook 登录"`
auths.tip.github=在 %s 注册一个 OAuth 应用程序
auths.tip.gitlab=在 https://gitlab.com/profile/applications 上注册新应用程序
-auths.tip.google_plus=从谷歌 API 控制台 (%s) 获得 OAuth2 客户端凭据
-auths.tip.openid_connect=使用 OpenID 连接发现 URL (~/.cargo/config.toml
):
+cargo.registry=在 Cargo 配置文件中设置此注册中心(例如:~/.cargo/config.toml
):
cargo.install=要使用 Cargo 安装软件包,请运行以下命令:
chef.registry=在您的 ~/.chef/config.rb
文件中设置此注册中心:
chef.install=要安装包,请运行以下命令:
@@ -3778,7 +3806,7 @@ settings.link.success=仓库链接已成功更新。
settings.link.error=更新仓库链接失败。
settings.delete=删除软件包
settings.delete.description=删除软件包是永久性的,无法撤消。
-settings.delete.notice=您将要删除 %s (%s)。此操作是不可逆的,您确定吗?
+settings.delete.notice=您将要删除 %s(%s)。此操作是不可逆的,您确定吗?
settings.delete.success=软件包已被删除。
settings.delete.error=删除软件包失败。
owner.settings.cargo.title=Cargo 注册中心索引
@@ -3788,7 +3816,7 @@ owner.settings.cargo.initialize.error=初始化Cargo索引失败: %v
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.error=无法重建 Cargo 索引:%v
owner.settings.cargo.rebuild.success=Cargo 索引已成功重建。
owner.settings.cleanuprules.title=清理规则
owner.settings.cleanuprules.add=添加清理规则
@@ -3836,7 +3864,7 @@ search_in_external_registry = 在 %s 中搜索
alt.registry.install = 要安装此软件包,请运行以下命令:
alt.install = 安装软件包
alt.registry = 通过命令行配置此注册表:
-alt.setup = 添加一个仓库到连接的仓库列表(选择必要的架构而非'_arch_'):
+alt.setup = 添加一个仓库到连接的仓库列表(选择必要的架构而非“_arch_”):
alt.repository = 仓库信息
alt.repository.architectures = 架构
alt.repository.multiple_groups = 此软件包在多个组中可用。
@@ -3922,7 +3950,7 @@ runs.no_workflows=目前还没有工作流。
runs.no_workflows.quick_start=不知道如何使用 Forgejo Actions吗?请查看 快速启动指南。
runs.no_workflows.documentation=关于Forgejo Actions的更多信息,请参阅 文档。
runs.no_runs=工作流尚未运行过。
-runs.empty_commit_message=(空白的提交消息)
+runs.empty_commit_message=(空白的提交消息)
workflow.disable=禁用工作流
workflow.disable_success=工作流 "%s" 已成功禁用。
@@ -3979,14 +4007,14 @@ submodule=子模块
[search]
-keyword_search_unavailable = 关键词搜索目前不可用,请联系站点管理员。
+keyword_search_unavailable = 关键词搜索目前不可用。请联系站点管理员。
search = 搜索…
repo_kind = 搜索仓库…
user_kind = 搜索用户…
org_kind = 搜索组织…
team_kind = 搜索团队…
code_kind = 搜索代码…
-code_search_unavailable = 代码搜索目前不可用,请联系站点管理员。
+code_search_unavailable = 代码搜索目前不可用。请联系站点管理员。
package_kind = 搜索软件包…
project_kind = 搜索项目…
branch_kind = 搜索分支…
@@ -3998,13 +4026,13 @@ fuzzy = 模糊
code_search_by_git_grep = 当前搜索结果由 git grep 提供,如果站点管理员启用了代码索引可能会有更好的结果。
match = 匹配
match_tooltip = 仅包含与搜索词完全匹配的结果
-fuzzy_tooltip = 在搜索结果中包含与搜索词相近的项目
+fuzzy_tooltip = 包含与搜索词相近的结果
exact = 精确
issue_kind = 搜索工单…
pull_kind = 搜索合并请求…
exact_tooltip = 仅包含与搜索词精确匹配的结果
milestone_kind = 搜索里程碑…
-union_tooltip = 包括与任何空格分隔的关键字匹配的结果
+union_tooltip = 包括与以空格分隔的关键字中任意一个相匹配的结果
union = 关键字
regexp = 正则表达式
regexp_tooltip = 将搜索内容解释为正则表达式
diff --git a/options/locale_next/locale_cs-CZ.json b/options/locale_next/locale_cs-CZ.json
index 8d028b8367..8ae2abdb93 100644
--- a/options/locale_next/locale_cs-CZ.json
+++ b/options/locale_next/locale_cs-CZ.json
@@ -1,11 +1,19 @@
{
- "repo.pulls.merged_title_desc": {
- "one": "sloučil %[1]d commit z %[2]s
do %[3]s
%[4]s",
- "other": "sloučil %[1]d commity z větve %[2]s
do větve %[3]s
před %[4]s"
- },
- "repo.pulls.title_desc": {
- "one": "žádá o sloučení %[1]d commitu z %[2]s
do %[3]s
",
- "other": "chce sloučit %[1]d commity z větve %[2]s
do %[3]s
"
- },
- "search.milestone_kind": "Hledat milníky..."
+ "repo.pulls.merged_title_desc": {
+ "one": "sloučil/a %[1]d revizi z větve %[2]s
do větve %[3]s
%[4]s",
+ "few": "sloučil/a %[1]d revize z větve %[2]s
do větve %[3]s
před %[4]s",
+ "other": "sloučil/a %[1]d revizí z větve %[2]s
do větve %[3]s
před %[4]s"
+ },
+ "repo.pulls.title_desc": {
+ "one": "žádá o sloučení %[1]d revize z větve %[2]s
do větve %[3]s
",
+ "few": "žádá o sloučení %[1]d revizí z větve %[2]s
do větve %[3]s
",
+ "other": "žádá o sloučení %[1]d revizí z větve %[2]s
do větve %[3]s
"
+ },
+ "search.milestone_kind": "Hledat milníky…",
+ "home.welcome.no_activity": "Žádná aktivita",
+ "home.welcome.activity_hint": "Váš feed je zatím prázdný. Zde se budou zobrazovat vaše akce a aktivity z repozitářů, které sledujete.",
+ "home.explore_repos": "Procházet repozitáře",
+ "home.explore_users": "Procházet uživatele",
+ "home.explore_orgs": "Procházet organizace",
+ "incorrect_root_url": "Tato instance Forgejo je nastavena tak, aby běžela na adrese „%s“. Vy si momentálně prohlížíte Forgejo na jiné adrese, což může způsobit rozbití některých částí aplikace. Správná adresa je ovládána správci Forgejo pomocí nastavení ROOT_URL v souboru app.ini."
}
diff --git a/options/locale_next/locale_da.json b/options/locale_next/locale_da.json
index 0c2c9a25ea..36eebe9c93 100644
--- a/options/locale_next/locale_da.json
+++ b/options/locale_next/locale_da.json
@@ -1,3 +1,17 @@
{
- "search.milestone_kind": "Søg milepæle..."
+ "search.milestone_kind": "Søg milepæle...",
+ "repo.pulls.title_desc": {
+ "one": "ønsker at flette %[1]d commit fra %[2]s
til %[3]s
",
+ "other": "ønsker at flette %[1]d commits fra %[2]s
til %[3]s
"
+ },
+ "repo.pulls.merged_title_desc": {
+ "one": "flettet %[1]d commit fra %[2]s
til %[3]s
%[4]s",
+ "other": "flettet %[1]d commits fra %[2]s
til %[3]s
%[4]s"
+ },
+ "incorrect_root_url": "Denne Forgejo-instans er konfigureret til at blive serveret på \"%s\". Du ser i øjeblikket Forgejo gennem en anden URL, hvilket kan få dele af applikationen til at gå i stykker. Den kanoniske URL styres af Forgejo-administratorer via indstillingen ROOT_URL i app.ini.",
+ "home.welcome.no_activity": "Ingen aktivitet",
+ "home.welcome.activity_hint": "Der er intet i dit feed endnu. Dine handlinger og aktivitet fra depoterne, som du ser, vises her.",
+ "home.explore_repos": "Udforsk depoter",
+ "home.explore_users": "Udforsk brugere",
+ "home.explore_orgs": "Udforsk organisationer"
}
diff --git a/options/locale_next/locale_de-DE.json b/options/locale_next/locale_de-DE.json
index f4a15ecdb9..a39f5b12bc 100644
--- a/options/locale_next/locale_de-DE.json
+++ b/options/locale_next/locale_de-DE.json
@@ -1,11 +1,16 @@
{
- "repo.pulls.merged_title_desc": {
- "one": "hat %[1]d Commit von %[2]s
nach %[3]s
%[4]s zusammengeführt",
- "other": "hat %[1]d Commits von %[2]s
nach %[3]s
%[4]s zusammengeführt"
- },
- "repo.pulls.title_desc": {
- "one": "möchte %[1]d Commit von %[2]s
nach %[3]s
zusammenführen",
- "other": "möchte %[1]d Commits von %[2]s
nach %[3]s
zusammenführen"
- },
- "search.milestone_kind": "Meilensteine suchen …"
+ "repo.pulls.merged_title_desc": {
+ "one": "hat %[1]d Commit von %[2]s
nach %[3]s
%[4]s zusammengeführt",
+ "other": "hat %[1]d Commits von %[2]s
nach %[3]s
%[4]s zusammengeführt"
+ },
+ "repo.pulls.title_desc": {
+ "one": "möchte %[1]d Commit von %[2]s
nach %[3]s
zusammenführen",
+ "other": "möchte %[1]d Commits von %[2]s
nach %[3]s
zusammenführen"
+ },
+ "search.milestone_kind": "Meilensteine suchen …",
+ "home.welcome.no_activity": "Keine Aktivität",
+ "home.explore_repos": "Repositorys erkunden",
+ "home.explore_users": "Benutzer erkunden",
+ "home.explore_orgs": "Organisationen erkunden",
+ "home.welcome.activity_hint": "Es gibt noch nichts in deinem Feed. Deine Aktionen und Aktivitäten aus Repositorys, die du beobachtest, werden hier auftauchen."
}
diff --git a/options/locale_next/locale_en-US.json b/options/locale_next/locale_en-US.json
index cc06102c46..0d47b351f5 100644
--- a/options/locale_next/locale_en-US.json
+++ b/options/locale_next/locale_en-US.json
@@ -12,5 +12,9 @@
"one": "wants to merge %[1]d commit from %[2]s
into %[3]s
",
"other": "wants to merge %[1]d commits from %[2]s
into %[3]s
"
},
- "search.milestone_kind": "Search milestones..."
+ "search.milestone_kind": "Search milestones…",
+ "incorrect_root_url": "This Forgejo instance is configured to be served on \"%s\". You are currently viewing Forgejo through a different URL, which may cause parts of the application to break. The canonical URL is controlled by Forgejo admins via the ROOT_URL setting in the app.ini.",
+ "themes.names.forgejo-auto": "Forgejo (follow system theme)",
+ "themes.names.forgejo-light": "Forgejo light",
+ "themes.names.forgejo-dark": "Forgejo dark"
}
diff --git a/options/locale_next/locale_fa-IR.json b/options/locale_next/locale_fa-IR.json
index 0a703d22d7..78d6944203 100644
--- a/options/locale_next/locale_fa-IR.json
+++ b/options/locale_next/locale_fa-IR.json
@@ -1,8 +1,16 @@
{
- "repo.pulls.merged_title_desc": {
- "other": "%[1]d کامیت ادغام شده از %[2]s
به %[3]s
%[4]s"
- },
- "repo.pulls.title_desc": {
- "other": "قصد ادغام %[1]d تغییر را از %[2]s
به %[3]s
دارد"
- }
+ "repo.pulls.merged_title_desc": {
+ "one": "واکشی %[1]d سپرده از %[2]s
به %[3]s
%[4]s",
+ "other": "واکشی %[1]d سپردهها از %[2]s
به %[3]s
%[4]s"
+ },
+ "repo.pulls.title_desc": {
+ "one": "خواست واکشی %[1]d سپرده را از %[2]s
به %[3]s
دارد",
+ "other": "خواست واکشی %[1]d سپردهها را از %[2]s
به %[3]s
دارد"
+ },
+ "home.welcome.activity_hint": "هنوز چیزی در آزوغه شما نیست. در اینجا کنشها و کوششهای شما در مخازنی که نگاهبانی میکنید نمایش داده خواهد شد.",
+ "search.milestone_kind": "جستجو نقاط عطف...",
+ "home.welcome.no_activity": "بدون کوشش",
+ "home.explore_repos": "کاوش مخازن",
+ "home.explore_users": "کاوش کاربران",
+ "home.explore_orgs": "کاوش سازمانها"
}
diff --git a/options/locale_next/locale_lv-LV.json b/options/locale_next/locale_lv-LV.json
index a16e3aaf8a..a0d57309ff 100644
--- a/options/locale_next/locale_lv-LV.json
+++ b/options/locale_next/locale_lv-LV.json
@@ -1,11 +1,19 @@
{
- "repo.pulls.merged_title_desc": {
- "one": "iekļāva %[1]d iesūtījumu no %[2]s
%[3]s
%[4]s",
- "other": "Iekļāva %[1]d iesūtījumus no %[2]s
zarā %[3]s
%[4]s"
- },
- "repo.pulls.title_desc": {
- "one": "vēlas iekļaut %[1]d iesūtījumu no %[2]s
%[3]s
",
- "other": "vēlas iekļaut %[1]d iesūtījumus no %[2]s
zarā %[3]s
"
- },
- "search.milestone_kind": "Meklēt atskaites punktus..."
+ "repo.pulls.merged_title_desc": {
+ "zero": "iekļāva %[1]d iesūtījumu no %[2]s
%[3]s
%[4]s",
+ "one": "Iekļāva %[1]d iesūtījumu no %[2]s
zarā %[3]s
%[4]s",
+ "other": "Iekļāva %[1]d iesūtījumus no %[2]s
zarā %[3]s
%[4]s"
+ },
+ "repo.pulls.title_desc": {
+ "zero": "vēlas iekļaut %[1]d iesūtījumu no %[2]s
%[3]s
",
+ "one": "vēlas iekļaut %[1]d iesūtījumu no %[2]s
zarā %[3]s
",
+ "other": "vēlas iekļaut %[1]d iesūtījumus no %[2]s
zarā %[3]s
"
+ },
+ "search.milestone_kind": "Meklēt atskaites punktus...",
+ "home.welcome.no_activity": "Nav darbību",
+ "home.welcome.activity_hint": "Barotnē pagaidām nekā nav. Šeit parādīsies darbības un vēroto glabātavu notikumi.",
+ "home.explore_repos": "Izpētīt glabātavas",
+ "home.explore_users": "Izpētīt lietotājus",
+ "home.explore_orgs": "Izpētīt apvienības",
+ "incorrect_root_url": "Šis Forgejo serveris ir konfigurēts darboties \"%s\". Pašlaik Forgejo tiek apmeklēta ar atšķirīgu URL, kas var radīt atsevišķu lietotnes daļu salūšanu. Kanonisko URL pārrauga Forgejo pārvaldītāji ar app.ini iestatījumu ROOT_URL."
}
diff --git a/options/locale_next/locale_nds.json b/options/locale_next/locale_nds.json
index 564302820a..a587997da3 100644
--- a/options/locale_next/locale_nds.json
+++ b/options/locale_next/locale_nds.json
@@ -1,11 +1,17 @@
{
- "repo.pulls.merged_title_desc": {
- "one": "hett %[1]d Kommitteren vun %[2]s
na %[3]s
%[4]s tosamenföhrt",
- "other": "hett %[1]d Kommitterens vun %[2]s
na %[3]s
%[4]s tosamenföhrt"
- },
- "repo.pulls.title_desc": {
- "one": "will %[1]d Kommitteren vun %[2]s
na %[3]s
tosamenföhren",
- "other": "will %[1]d Kommitterens vun %[2]s
na %[3]s
tosamenföhren"
- },
- "search.milestone_kind": "In Markstenen söken …"
+ "repo.pulls.merged_title_desc": {
+ "one": "hett %[4]s %[1]d Kommitteren vun %[2]s
na %[3]s
tosamenföhrt",
+ "other": "hett %[4]s %[1]d Kommitterens vun %[2]s
na %[3]s
tosamenföhrt"
+ },
+ "repo.pulls.title_desc": {
+ "one": "will %[1]d Kommitteren vun %[2]s
na %[3]s
tosamenföhren",
+ "other": "will %[1]d Kommitterens vun %[2]s
na %[3]s
tosamenföhren"
+ },
+ "search.milestone_kind": "In Markstenen söken …",
+ "home.explore_users": "Brukers utförsken",
+ "home.explore_orgs": "Vereenigungen utförsken",
+ "home.explore_repos": "Repositoriums utförsken",
+ "home.welcome.no_activity": "Keen Doon",
+ "home.welcome.activity_hint": "In dienem Schuuv is noch nix. Dien Doon un dat Doon vun Repositoriums, wat du beluurst, word hier wiest worden.",
+ "incorrect_root_url": "Deese Forgejo-Instanz is inricht, unner »%s« besöcht to worden. Du bekiekst Forgejo jüüst dör een anner URL, wat daarto föhren kann, dat ’t deelwies nich richtig warkt. De kanonisk URL word vun de Forgejo-Chefs över de ROOT_URL-Instellen in de app.ini kuntrolleert."
}
diff --git a/options/locale_next/locale_nl-NL.json b/options/locale_next/locale_nl-NL.json
index fbb78e9280..cfa80104e8 100644
--- a/options/locale_next/locale_nl-NL.json
+++ b/options/locale_next/locale_nl-NL.json
@@ -1,11 +1,17 @@
{
- "repo.pulls.merged_title_desc": {
- "one": "heeft %[1]d commit van %[2]s
samengevoegd in %[3]s
%[4]s",
- "other": "heeft %[1]d commits samengevoegd van %[2]s
naar %[3]s
%[4]s"
- },
- "repo.pulls.title_desc": {
- "one": "wilt %[1]d commit van %[2]s
samenvoegen in %[3]s
",
- "other": "wilt %[1]d commits van %[2]s
samenvoegen met %[3]s
"
- },
- "search.milestone_kind": "Zoek mijlpalen..."
+ "repo.pulls.merged_title_desc": {
+ "one": "heeft %[1]d commit van %[2]s
samengevoegd in %[3]s
%[4]s",
+ "other": "heeft %[1]d commits samengevoegd van %[2]s
naar %[3]s
%[4]s"
+ },
+ "repo.pulls.title_desc": {
+ "one": "wilt %[1]d commit van %[2]s
samenvoegen in %[3]s
",
+ "other": "wilt %[1]d commits van %[2]s
samenvoegen met %[3]s
"
+ },
+ "search.milestone_kind": "Zoek mijlpalen...",
+ "home.welcome.no_activity": "Geen activiteit",
+ "home.welcome.activity_hint": "Er staat nog niets in uw feed. Uw acties en activiteiten van repositories die u bekijkt zullen hier verschijnen.",
+ "home.explore_repos": "Ontdek repositories",
+ "home.explore_users": "Ontdek gebruikers",
+ "home.explore_orgs": "Ontdek organisaties",
+ "incorrect_root_url": "Deze Forgejo-instantie is geconfigureerd om geserveerd te worden op \"%s\". U bekijkt Forgejo momenteel via een andere URL, waardoor onderdelen van de applicatie kunnen breken. De canonieke URL kan worden gewijzigd door Forgejo admins via de ROOT_URL instelling in de app.ini."
}
diff --git a/options/locale_next/locale_pt-BR.json b/options/locale_next/locale_pt-BR.json
index 4de44582a5..a66d679e96 100644
--- a/options/locale_next/locale_pt-BR.json
+++ b/options/locale_next/locale_pt-BR.json
@@ -1,11 +1,19 @@
{
- "repo.pulls.merged_title_desc": {
- "one": "mesclou %[1]d commit de %[2]s
em %[3]s
%[4]s",
- "other": "mesclou %[1]d commits de %[2]s
em %[3]s
%[4]s"
- },
- "repo.pulls.title_desc": {
- "one": "quer mesclar %[1]d commit de %[2]s
em %[3]s
",
- "other": "quer mesclar %[1]d commits de %[2]s
em %[3]s
"
- },
- "search.milestone_kind": "Pesquisar marcos..."
+ "repo.pulls.merged_title_desc": {
+ "one": "mesclou %[1]d commit de %[2]s
em %[3]s
%[4]s",
+ "many": "mesclou %[1]d commits de %[2]s
em %[3]s
%[4]s",
+ "other": ""
+ },
+ "repo.pulls.title_desc": {
+ "one": "quer mesclar %[1]d commit de %[2]s
em %[3]s
",
+ "many": "quer mesclar %[1]d commits de %[2]s
em %[3]s
",
+ "other": ""
+ },
+ "search.milestone_kind": "Pesquisar marcos...",
+ "home.welcome.no_activity": "Sem atividade",
+ "home.welcome.activity_hint": "Ainda não tem nada no seu feed. Suas ações e atividade dos seus repositórios vigiados aparecerão aqui.",
+ "home.explore_repos": "Explorar repositórios",
+ "home.explore_users": "Explorar usuários",
+ "home.explore_orgs": "Explorar organizações",
+ "incorrect_root_url": "Esta instância do Forgejo está configurada para o endereço \"%s\". Você está atualmente vendo o Forgejo através de uma URL diferente, o que pode causar erros em algumas partes da aplicação. A URL oficial é controlada pela administração do Forgejo através da configuração ROOT_URL no arquivo app.ini."
}
diff --git a/options/locale_next/locale_pt-PT.json b/options/locale_next/locale_pt-PT.json
index cf72ef3e09..4d58ffff73 100644
--- a/options/locale_next/locale_pt-PT.json
+++ b/options/locale_next/locale_pt-PT.json
@@ -1,11 +1,18 @@
{
- "repo.pulls.merged_title_desc": {
- "one": "integrou %[1]d cometimento do ramo %[2]s
no ramo %[3]s
%[4]s",
- "other": "integrou %[1]d cometimento(s) do ramo %[2]s
no ramo %[3]s
%[4]s"
- },
- "repo.pulls.title_desc": {
- "one": "quer integrar %[1]d cometimento do ramo %[2]s
no ramo %[3]s
",
- "other": "quer integrar %[1]d cometimento(s) do ramo %[2]s
no ramo %[3]s
"
- },
- "search.milestone_kind": "Procurar etapas..."
+ "repo.pulls.merged_title_desc": {
+ "one": "integrou %[1]d cometimento do ramo %[2]s
no ramo %[3]s
%[4]s",
+ "many": "integrou %[1]d cometimentos do ramo %[2]s
no ramo %[3]s
%[4]s",
+ "other": ""
+ },
+ "repo.pulls.title_desc": {
+ "one": "quer integrar %[1]d cometimento do ramo %[2]s
no ramo %[3]s
",
+ "many": "quer integrar %[1]d cometimentos do ramo %[2]s
no ramo %[3]s
",
+ "other": ""
+ },
+ "search.milestone_kind": "Procurar etapas...",
+ "home.welcome.no_activity": "Sem atividade",
+ "home.welcome.activity_hint": "Ainda não há nada no seu feed. As suas operações e a atividade dos repositórios que vigia aparecerão aqui.",
+ "home.explore_repos": "Explorar repositórios",
+ "home.explore_users": "Explorar utilizadores",
+ "home.explore_orgs": "Explorar organizações"
}
diff --git a/options/locale_next/locale_ru-RU.json b/options/locale_next/locale_ru-RU.json
index 36f54f405b..3db0072760 100644
--- a/options/locale_next/locale_ru-RU.json
+++ b/options/locale_next/locale_ru-RU.json
@@ -1,11 +1,19 @@
{
- "repo.pulls.merged_title_desc": {
- "one": "слит %[1]d коммит из %[2]s
в %[3]s
%[4]s",
- "many": "слито %[1]d коммит(ов) из %[2]s
в %[3]s
%[4]s"
- },
- "repo.pulls.title_desc": {
- "one": "хочет влить %[1]d коммит из %[2]s
в %[3]s
",
- "many": "хочет влить %[1]d коммит(ов) из %[2]s
в %[3]s
"
- },
- "search.milestone_kind": "Найти этапы..."
+ "repo.pulls.merged_title_desc": {
+ "one": "слит %[1]d коммит из %[2]s
в %[3]s
%[4]s",
+ "few": "слито %[1]d коммита из %[2]s
в %[3]s
%[4]s",
+ "many": "слито %[1]d коммитов из %[2]s
в %[3]s
%[4]s"
+ },
+ "repo.pulls.title_desc": {
+ "one": "хочет влить %[1]d коммит из %[2]s
в %[3]s
",
+ "few": "хочет влить %[1]d коммита из %[2]s
в %[3]s
",
+ "many": "хочет влить %[1]d коммитов из %[2]s
в %[3]s
"
+ },
+ "search.milestone_kind": "Найти этапы...",
+ "home.explore_repos": "Каталог репозиториев",
+ "home.explore_users": "Каталог пользователей",
+ "home.explore_orgs": "Каталог организаций",
+ "home.welcome.activity_hint": "В вашей ленте пока ничего нет. Ваши действия и активность из отслеживаемых вами репозиториев будут отображены здесь.",
+ "home.welcome.no_activity": "Нет событий",
+ "incorrect_root_url": "Этот сервер Forgejo расположен по адресу «%s», но вы просматриваете страницу с другого адреса. Это может приводить к поломкам частей приложения. Канонический адрес указывается администратором сервера в файле конфигурации app.ini - ROOT_URL."
}
diff --git a/options/locale_next/locale_uk-UA.json b/options/locale_next/locale_uk-UA.json
index ce37b9bef3..f76e502124 100644
--- a/options/locale_next/locale_uk-UA.json
+++ b/options/locale_next/locale_uk-UA.json
@@ -1,11 +1,19 @@
{
- "repo.pulls.merged_title_desc": {
- "one": "об'єднав %[1]d коміт з %[2]s
в %[3]s
%[4]s",
- "many": "об'єднав %[1]d комітів з %[2]s
в %[3]s
%[4]s"
- },
- "repo.pulls.title_desc": {
- "one": "хоче об'єднати %[1]d коміт з %[2]s
в %[3]s
",
- "many": "хоче об'єднати %[1]d комітів з %[2]s
в %[3]s
"
- },
- "search.milestone_kind": "Шукати віхи..."
+ "repo.pulls.merged_title_desc": {
+ "one": "об'єднує %[1]d коміт з %[2]s
в %[3]s
%[4]s",
+ "few": "об'єднує %[1]d коміти з %[2]s
в %[3]s
%[4]s",
+ "many": "об'єднує %[1]d комітів з %[2]s
в %[3]s
%[4]s"
+ },
+ "repo.pulls.title_desc": {
+ "one": "хоче об'єднати %[1]d коміт з %[2]s
в %[3]s
",
+ "few": "хоче об'єднати %[1]d коміти з %[2]s
в %[3]s
",
+ "many": "хоче об'єднати %[1]d комітів з %[2]s
в %[3]s
"
+ },
+ "search.milestone_kind": "Шукати етапи...",
+ "home.welcome.activity_hint": "У вашій стрічці ще нічого немає. Тут з'являтимуться ваші дії та активність із відстежуваних репозиторіїв.",
+ "home.welcome.no_activity": "Немає подій",
+ "home.explore_repos": "Огляд репозиторіїв",
+ "home.explore_users": "Огляд користувачів",
+ "home.explore_orgs": "Огляд організацій",
+ "incorrect_root_url": "Цей екземпляр Forgejo налаштовано на відвідування з «%s». Зараз ви переглядаєте Forgejo за іншою URL-адресою, що може призвести до збоїв деяких частин програми. Канонічна URL-адреса встановлюється адміністраторами Forgejo за допомогою параметра ROOT_URL у файлі app.ini."
}
diff --git a/options/locale_next/locale_zh-CN.json b/options/locale_next/locale_zh-CN.json
index 10b1c9a4be..944b3dbf47 100644
--- a/options/locale_next/locale_zh-CN.json
+++ b/options/locale_next/locale_zh-CN.json
@@ -1,9 +1,11 @@
{
- "repo.pulls.merged_title_desc": {
- "other": "于 %[4]s 将 %[1]d 次代码提交从 %[2]s
合并至 %[3]s
"
- },
- "repo.pulls.title_desc": {
- "other": "请求将 %[1]d 次代码提交从 %[2]s
合并至 %[3]s
"
- },
- "search.milestone_kind": "搜索里程碑…"
+ "repo.pulls.merged_title_desc": "于 %[4]s 将 %[1]d 次代码提交从 %[2]s
合并至 %[3]s
",
+ "repo.pulls.title_desc": "请求将 %[1]d 次代码提交从 %[2]s
合并至 %[3]s
",
+ "search.milestone_kind": "搜索里程碑…",
+ "home.welcome.no_activity": "无活动",
+ "home.welcome.activity_hint": "您的订阅中还没有任何内容。您关注的仓库中的操作和活动将显示在此处。",
+ "home.explore_repos": "探索仓库",
+ "home.explore_users": "探索用户",
+ "home.explore_orgs": "探索组织",
+ "incorrect_root_url": "此 Forgejo 实例配置为在“%s”上提供服务。您当前正在通过不同的网址查看 Forgejo,这可能会导致应用程序的某些部分损坏。Forgejo 管理员通过 app.ini 中的 ROOT_URL 设置控制规范网址。"
}
diff --git a/package-lock.json b/package-lock.json
index 929f905d50..09359fabc5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -65,8 +65,8 @@
"@eslint-community/eslint-plugin-eslint-comments": "4.4.1",
"@playwright/test": "1.50.1",
"@stoplight/spectral-cli": "6.14.2",
- "@stylistic/eslint-plugin-js": "2.12.1",
- "@stylistic/stylelint-plugin": "3.1.1",
+ "@stylistic/eslint-plugin-js": "4.2.0",
+ "@stylistic/stylelint-plugin": "3.1.2",
"@typescript-eslint/parser": "8.18.2",
"@vitejs/plugin-vue": "5.1.5",
"@vitest/coverage-v8": "3.0.5",
@@ -84,11 +84,11 @@
"eslint-plugin-toml": "0.12.0",
"eslint-plugin-unicorn": "56.0.1",
"eslint-plugin-vitest-globals": "1.5.0",
- "eslint-plugin-vue": "9.32.0",
+ "eslint-plugin-vue": "10.0.0",
"eslint-plugin-vue-scoped-css": "2.9.0",
"eslint-plugin-wc": "2.2.0",
- "globals": "15.15.0",
- "happy-dom": "17.1.0",
+ "globals": "16.0.0",
+ "happy-dom": "17.1.8",
"license-checker-rseidelsohn": "4.4.2",
"markdownlint-cli": "0.44.0",
"postcss-html": "1.8.0",
@@ -2755,9 +2755,9 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz",
- "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz",
+ "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2860,13 +2860,13 @@
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.2.5",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz",
- "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==",
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz",
+ "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@eslint/core": "^0.10.0",
+ "@eslint/core": "^0.12.0",
"levn": "^0.4.1"
},
"engines": {
@@ -2874,9 +2874,9 @@
}
},
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
- "version": "0.10.0",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz",
- "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==",
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
+ "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -2973,9 +2973,9 @@
}
},
"node_modules/@humanwhocodes/retry": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz",
- "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==",
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz",
+ "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -3008,6 +3008,18 @@
"mlly": "^1.7.4"
}
},
+ "node_modules/@iconify/utils/node_modules/globals": {
+ "version": "15.15.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
+ "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -3469,9 +3481,9 @@
"license": "MIT"
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.7.tgz",
- "integrity": "sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.9.tgz",
+ "integrity": "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==",
"cpu": [
"arm"
],
@@ -3483,9 +3495,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.7.tgz",
- "integrity": "sha512-KvyJpFUueUnSp53zhAa293QBYqwm94TgYTIfXyOTtidhm5V0LbLCJQRGkQClYiX3FXDQGSvPxOTD/6rPStMMDg==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.9.tgz",
+ "integrity": "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==",
"cpu": [
"arm64"
],
@@ -3497,9 +3509,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.7.tgz",
- "integrity": "sha512-jq87CjmgL9YIKvs8ybtIC98s/M3HdbqXhllcy9EdLV0yMg1DpxES2gr65nNy7ObNo/vZ/MrOTxt0bE5LinL6mA==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz",
+ "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==",
"cpu": [
"arm64"
],
@@ -3511,9 +3523,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.7.tgz",
- "integrity": "sha512-rSI/m8OxBjsdnMMg0WEetu/w+LhLAcCDEiL66lmMX4R3oaml3eXz3Dxfvrxs1FbzPbJMaItQiksyMfv1hoIxnA==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz",
+ "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==",
"cpu": [
"x64"
],
@@ -3525,9 +3537,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.7.tgz",
- "integrity": "sha512-oIoJRy3ZrdsXpFuWDtzsOOa/E/RbRWXVokpVrNnkS7npz8GEG++E1gYbzhYxhxHbO2om1T26BZjVmdIoyN2WtA==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.9.tgz",
+ "integrity": "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==",
"cpu": [
"arm64"
],
@@ -3539,9 +3551,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.7.tgz",
- "integrity": "sha512-X++QSLm4NZfZ3VXGVwyHdRf58IBbCu9ammgJxuWZYLX0du6kZvdNqPwrjvDfwmi6wFdvfZ/s6K7ia0E5kI7m8Q==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.9.tgz",
+ "integrity": "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==",
"cpu": [
"x64"
],
@@ -3553,9 +3565,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.7.tgz",
- "integrity": "sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.9.tgz",
+ "integrity": "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==",
"cpu": [
"arm"
],
@@ -3567,9 +3579,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.7.tgz",
- "integrity": "sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.9.tgz",
+ "integrity": "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==",
"cpu": [
"arm"
],
@@ -3581,9 +3593,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.7.tgz",
- "integrity": "sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz",
+ "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==",
"cpu": [
"arm64"
],
@@ -3595,9 +3607,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.7.tgz",
- "integrity": "sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz",
+ "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==",
"cpu": [
"arm64"
],
@@ -3609,9 +3621,9 @@
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.7.tgz",
- "integrity": "sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.9.tgz",
+ "integrity": "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==",
"cpu": [
"loong64"
],
@@ -3623,9 +3635,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.7.tgz",
- "integrity": "sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.9.tgz",
+ "integrity": "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==",
"cpu": [
"ppc64"
],
@@ -3637,9 +3649,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.7.tgz",
- "integrity": "sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.9.tgz",
+ "integrity": "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==",
"cpu": [
"riscv64"
],
@@ -3651,9 +3663,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.7.tgz",
- "integrity": "sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.9.tgz",
+ "integrity": "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==",
"cpu": [
"s390x"
],
@@ -3665,9 +3677,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.7.tgz",
- "integrity": "sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz",
+ "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==",
"cpu": [
"x64"
],
@@ -3679,9 +3691,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.7.tgz",
- "integrity": "sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz",
+ "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==",
"cpu": [
"x64"
],
@@ -3693,9 +3705,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.7.tgz",
- "integrity": "sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz",
+ "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==",
"cpu": [
"arm64"
],
@@ -3707,9 +3719,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.7.tgz",
- "integrity": "sha512-aeawEKYswsFu1LhDM9RIgToobquzdtSc4jSVqHV8uApz4FVvhFl/mKh92wc8WpFc6aYCothV/03UjY6y7yLgbg==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.9.tgz",
+ "integrity": "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==",
"cpu": [
"ia32"
],
@@ -3721,9 +3733,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.7.tgz",
- "integrity": "sha512-4ZedScpxxIrVO7otcZ8kCX1mZArtH2Wfj3uFCxRJ9NO80gg1XV0U/b2f/MKaGwj2X3QopHfoWiDQ917FRpwY3w==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz",
+ "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==",
"cpu": [
"x64"
],
@@ -4253,9 +4265,9 @@
}
},
"node_modules/@stylistic/eslint-plugin-js": {
- "version": "2.12.1",
- "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.12.1.tgz",
- "integrity": "sha512-5ybogtEgWIGCR6dMnaabztbWyVdAPDsf/5XOk6jBonWug875Q9/a6gm9QxnU3rhdyDEnckWKX7dduwYJMOWrVA==",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.2.0.tgz",
+ "integrity": "sha512-MiJr6wvyzMYl/wElmj8Jns8zH7Q1w8XoVtm+WM6yDaTrfxryMyb8n0CMxt82fo42RoLIfxAEtM6tmQVxqhk0/A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4266,13 +4278,13 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"peerDependencies": {
- "eslint": ">=8.40.0"
+ "eslint": ">=9.0.0"
}
},
"node_modules/@stylistic/stylelint-plugin": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.1.tgz",
- "integrity": "sha512-XagAHHIa528EvyGybv8EEYGK5zrVW74cHpsjhtovVATbhDRuJYfE+X4HCaAieW9lCkwbX6L+X0I4CiUG3w/hFw==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.2.tgz",
+ "integrity": "sha512-tylFJGMQo62alGazK74MNxFjMagYOHmBZiePZFOJK2n13JZta0uVkB3Bh5qodUmOLtRH+uxH297EibK14UKm8g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4669,9 +4681,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "22.13.4",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz",
- "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
+ "version": "22.13.8",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.8.tgz",
+ "integrity": "sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
@@ -5468,13 +5480,13 @@
"license": "Apache-2.0"
},
"node_modules/abbrev": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.0.tgz",
- "integrity": "sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
+ "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
"dev": true,
"license": "ISC",
"engines": {
- "node": "^18.17.0 || >=20.5.0"
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/abort-controller": {
@@ -6155,9 +6167,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001700",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz",
- "integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==",
+ "version": "1.0.30001701",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001701.tgz",
+ "integrity": "sha512-faRs/AW3jA9nTwmJBSO1PQ6L/EOgsB5HMQQq4iCu5zhPgVVgO/pZRHlmatwijZKetFw8/Pr4q6dEN8sJuq8qTw==",
"funding": [
{
"type": "opencollective",
@@ -6565,13 +6577,13 @@
"license": "MIT"
},
"node_modules/core-js-compat": {
- "version": "3.40.0",
- "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.40.0.tgz",
- "integrity": "sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==",
+ "version": "3.41.0",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz",
+ "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "browserslist": "^4.24.3"
+ "browserslist": "^4.24.4"
},
"funding": {
"type": "opencollective",
@@ -6783,9 +6795,9 @@
"license": "MIT"
},
"node_modules/cytoscape": {
- "version": "3.31.0",
- "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.31.0.tgz",
- "integrity": "sha512-zDGn1K/tfZwEnoGOcHc0H4XazqAAXAuDpcYw9mUnUjATjqljyCNGJv8uEvbvxGaGHaVshxMecyl6oc6uKzRfbw==",
+ "version": "3.31.1",
+ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.31.1.tgz",
+ "integrity": "sha512-Hx5Mtb1+hnmAKaZZ/7zL1Y5HTFYOjdDswZy/jD+1WINRU8KVi1B7+vlHdsTwY+VCFucTreoyu1RDzQJ9u0d2Hw==",
"license": "MIT",
"engines": {
"node": ">=0.10"
@@ -7693,9 +7705,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.5.101",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.101.tgz",
- "integrity": "sha512-L0ISiQrP/56Acgu4/i/kfPwWSgrzYZUnQrC0+QPFuhqlLP1Ir7qzPPDVS9BcKIyWTRU8+o6CC8dKw38tSWhYIA==",
+ "version": "1.5.109",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.109.tgz",
+ "integrity": "sha512-AidaH9JETVRr9DIPGfp1kAarm/W6hRJTPuCnkF+2MqhF4KaAgRIcBc8nvjk+YMXZhwfISof/7WG29eS4iGxQLQ==",
"license": "ISC"
},
"node_modules/emoji-regex": {
@@ -8437,6 +8449,19 @@
"eslint": ">=8.56.0"
}
},
+ "node_modules/eslint-plugin-unicorn/node_modules/globals": {
+ "version": "15.15.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
+ "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/eslint-plugin-vitest-globals": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-vitest-globals/-/eslint-plugin-vitest-globals-1.5.0.tgz",
@@ -8445,26 +8470,25 @@
"license": "MIT"
},
"node_modules/eslint-plugin-vue": {
- "version": "9.32.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.32.0.tgz",
- "integrity": "sha512-b/Y05HYmnB/32wqVcjxjHZzNpwxj1onBOvqW89W+V+XNG1dRuaFbNd3vT9CLbr2LXjEoq+3vn8DanWf7XU22Ug==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.0.0.tgz",
+ "integrity": "sha512-XKckedtajqwmaX6u1VnECmZ6xJt+YvlmMzBPZd+/sI3ub2lpYZyFnsyWo7c3nMOQKJQudeyk1lw/JxdgeKT64w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
- "globals": "^13.24.0",
"natural-compare": "^1.4.0",
"nth-check": "^2.1.1",
"postcss-selector-parser": "^6.0.15",
"semver": "^7.6.3",
- "vue-eslint-parser": "^9.4.3",
"xml-name-validator": "^4.0.0"
},
"engines": {
- "node": "^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"peerDependencies": {
- "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
+ "eslint": "^8.57.0 || ^9.0.0",
+ "vue-eslint-parser": "^10.0.0"
}
},
"node_modules/eslint-plugin-vue-scoped-css": {
@@ -8494,35 +8518,6 @@
"vue-eslint-parser": ">=7.1.0"
}
},
- "node_modules/eslint-plugin-vue/node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint-plugin-vue/node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "license": "(MIT OR CC0-1.0)",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/eslint-plugin-wc": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-2.2.0.tgz",
@@ -8710,9 +8705,9 @@
}
},
"node_modules/expect-type": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz",
- "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.0.tgz",
+ "integrity": "sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -8807,9 +8802,9 @@
}
},
"node_modules/fastq": {
- "version": "1.19.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz",
- "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+ "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
"license": "ISC",
"dependencies": {
"reusify": "^1.0.4"
@@ -8890,9 +8885,9 @@
}
},
"node_modules/flatted": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz",
- "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+ "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"dev": true,
"license": "ISC"
},
@@ -8913,12 +8908,12 @@
}
},
"node_modules/foreground-child": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
- "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
"license": "ISC",
"dependencies": {
- "cross-spawn": "^7.0.0",
+ "cross-spawn": "^7.0.6",
"signal-exit": "^4.0.1"
},
"engines": {
@@ -9044,18 +9039,18 @@
}
},
"node_modules/get-intrinsic": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
- "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
+ "call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
+ "es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
- "get-proto": "^1.0.0",
+ "get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
@@ -9239,9 +9234,10 @@
}
},
"node_modules/globals": {
- "version": "15.15.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
- "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
+ "version": "16.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz",
+ "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
@@ -9337,9 +9333,9 @@
}
},
"node_modules/happy-dom": {
- "version": "17.1.0",
- "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-17.1.0.tgz",
- "integrity": "sha512-9tUhXyePCjzUMycaHS/IzrIpF69xiq/laAT7golk4MtZ6t8ft5+Rv7U3lfrs2b4NMH0JTL3EhZzjfahrPmOnaQ==",
+ "version": "17.1.8",
+ "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-17.1.8.tgz",
+ "integrity": "sha512-Yxbq/FG79z1rhAf/iB6YM8wO2JB/JDQBy99RiLSs+2siEAi5J05x9eW1nnASHZJbpldjJE2KuFLsLZ+AzX/IxA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -10412,9 +10408,9 @@
"license": "MIT"
},
"node_modules/js-beautify": {
- "version": "1.15.3",
- "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.3.tgz",
- "integrity": "sha512-rKKGuyTxGNlyN4EQKWzNndzXpi0bOl8Gl8YQAW1as/oMz0XhD6sHJO1hTvoBDOSzKuJb9WkwoAb34FfdkKMv2A==",
+ "version": "1.15.4",
+ "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz",
+ "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -10422,7 +10418,7 @@
"editorconfig": "^1.0.4",
"glob": "^10.4.2",
"js-cookie": "^3.0.5",
- "nopt": "^8.0.0"
+ "nopt": "^7.2.1"
},
"bin": {
"css-beautify": "js/bin/css-beautify.js",
@@ -10795,32 +10791,6 @@
"npm": ">=8"
}
},
- "node_modules/license-checker-rseidelsohn/node_modules/abbrev": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
- "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
- }
- },
- "node_modules/license-checker-rseidelsohn/node_modules/nopt": {
- "version": "7.2.1",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
- "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "abbrev": "^2.0.0"
- },
- "bin": {
- "nopt": "bin/nopt.js"
- },
- "engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
- }
- },
"node_modules/lilconfig": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
@@ -10873,13 +10843,14 @@
}
},
"node_modules/local-pkg": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.0.0.tgz",
- "integrity": "sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.0.tgz",
+ "integrity": "sha512-xbZBuX6gYIWrlLmZG43aAVer4ocntYO09vPy9lxd6Ns8DnR4U7N+IIeDkubinqFOHHzoMlPxTxwo0jhE7oYjAw==",
"license": "MIT",
"dependencies": {
- "mlly": "^1.7.3",
- "pkg-types": "^1.3.0"
+ "mlly": "^1.7.4",
+ "pkg-types": "^1.3.1",
+ "quansync": "^0.2.1"
},
"engines": {
"node": ">=14"
@@ -11760,9 +11731,9 @@
}
},
"node_modules/micromark-util-subtokenize": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.4.tgz",
- "integrity": "sha512-N6hXjrin2GTJDe3MVjf5FuXpm12PGm80BrUAeub9XFXca8JZbP+oIwY4LJSVwFUCL1IPm/WwSVUN7goFHmSGGQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz",
+ "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==",
"dev": true,
"funding": [
{
@@ -12073,19 +12044,19 @@
}
},
"node_modules/nopt": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz",
- "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==",
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
+ "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
"dev": true,
"license": "ISC",
"dependencies": {
- "abbrev": "^3.0.0"
+ "abbrev": "^2.0.0"
},
"bin": {
"nopt": "bin/nopt.js"
},
"engines": {
- "node": "^18.17.0 || >=20.5.0"
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/normalize-package-data": {
@@ -12321,10 +12292,13 @@
"license": "BlueOak-1.0.0"
},
"node_modules/package-manager-detector": {
- "version": "0.2.9",
- "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.9.tgz",
- "integrity": "sha512-+vYvA/Y31l8Zk8dwxHhL3JfTuHPm6tlxM2A3GeQyl7ovYnSp1+mzAxClxaOr0qO1TtPxbQxetI7v5XqKLJZk7Q==",
- "license": "MIT"
+ "version": "0.2.11",
+ "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz",
+ "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==",
+ "license": "MIT",
+ "dependencies": {
+ "quansync": "^0.2.7"
+ }
},
"node_modules/parent-module": {
"version": "1.0.1",
@@ -13180,6 +13154,22 @@
"node": ">=6"
}
},
+ "node_modules/quansync": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.7.tgz",
+ "integrity": "sha512-KZDFlN9/Si3CgKHZsIfLBsrjWKFjqu9KA0zDGJEQoQzPm5HWNDEFc2mkLeYUBBOwEJtxNBSMaNLE/GlvArIEfQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/antfu"
+ },
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -13721,9 +13711,9 @@
}
},
"node_modules/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
"license": "MIT",
"engines": {
"iojs": ">=1.0.0",
@@ -14232,9 +14222,9 @@
}
},
"node_modules/solid-js": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.4.tgz",
- "integrity": "sha512-ipQl8FJ31bFUoBNScDQTG3BjN6+9Rg+Q+f10bUbnO6EOTTf5NGerJeHc7wyu5I4RMHEl/WwZwUmy/PTRgxxZ8g==",
+ "version": "1.9.5",
+ "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.5.tgz",
+ "integrity": "sha512-ogI3DaFcyn6UhYhrgcyRAMbu/buBJitYQASZz5WzfQVPP10RD2AbCoRZ517psnezrasyCbWzIxZ6kVqet768xw==",
"license": "MIT",
"dependencies": {
"csstype": "^3.1.0",
@@ -15103,9 +15093,9 @@
}
},
"node_modules/terser-webpack-plugin": {
- "version": "5.3.11",
- "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz",
- "integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==",
+ "version": "5.3.12",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.12.tgz",
+ "integrity": "sha512-jDLYqo7oF8tJIttjXO6jBY5Hk8p3A8W4ttih7cCEq64fQFWmgJ4VqAQjKr7WwIDlmXKEc6QeoRb5ecjZ+2afcg==",
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.25",
@@ -15636,9 +15626,9 @@
}
},
"node_modules/update-browserslist-db": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz",
- "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==",
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
"funding": [
{
"type": "opencollective",
@@ -16281,9 +16271,9 @@
}
},
"node_modules/vite/node_modules/rollup": {
- "version": "4.34.7",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.7.tgz",
- "integrity": "sha512-8qhyN0oZ4x0H6wmBgfKxJtxM7qS98YJ0k0kNh5ECVtuchIJ7z9IVVvzpmtQyT10PXKMtBxYr1wQ5Apg8RS8kXQ==",
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.9.tgz",
+ "integrity": "sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -16297,25 +16287,25 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.34.7",
- "@rollup/rollup-android-arm64": "4.34.7",
- "@rollup/rollup-darwin-arm64": "4.34.7",
- "@rollup/rollup-darwin-x64": "4.34.7",
- "@rollup/rollup-freebsd-arm64": "4.34.7",
- "@rollup/rollup-freebsd-x64": "4.34.7",
- "@rollup/rollup-linux-arm-gnueabihf": "4.34.7",
- "@rollup/rollup-linux-arm-musleabihf": "4.34.7",
- "@rollup/rollup-linux-arm64-gnu": "4.34.7",
- "@rollup/rollup-linux-arm64-musl": "4.34.7",
- "@rollup/rollup-linux-loongarch64-gnu": "4.34.7",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.34.7",
- "@rollup/rollup-linux-riscv64-gnu": "4.34.7",
- "@rollup/rollup-linux-s390x-gnu": "4.34.7",
- "@rollup/rollup-linux-x64-gnu": "4.34.7",
- "@rollup/rollup-linux-x64-musl": "4.34.7",
- "@rollup/rollup-win32-arm64-msvc": "4.34.7",
- "@rollup/rollup-win32-ia32-msvc": "4.34.7",
- "@rollup/rollup-win32-x64-msvc": "4.34.7",
+ "@rollup/rollup-android-arm-eabi": "4.34.9",
+ "@rollup/rollup-android-arm64": "4.34.9",
+ "@rollup/rollup-darwin-arm64": "4.34.9",
+ "@rollup/rollup-darwin-x64": "4.34.9",
+ "@rollup/rollup-freebsd-arm64": "4.34.9",
+ "@rollup/rollup-freebsd-x64": "4.34.9",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.34.9",
+ "@rollup/rollup-linux-arm-musleabihf": "4.34.9",
+ "@rollup/rollup-linux-arm64-gnu": "4.34.9",
+ "@rollup/rollup-linux-arm64-musl": "4.34.9",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.34.9",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.34.9",
+ "@rollup/rollup-linux-riscv64-gnu": "4.34.9",
+ "@rollup/rollup-linux-s390x-gnu": "4.34.9",
+ "@rollup/rollup-linux-x64-gnu": "4.34.9",
+ "@rollup/rollup-linux-x64-musl": "4.34.9",
+ "@rollup/rollup-win32-arm64-msvc": "4.34.9",
+ "@rollup/rollup-win32-ia32-msvc": "4.34.9",
+ "@rollup/rollup-win32-x64-msvc": "4.34.9",
"fsevents": "~2.3.2"
}
},
@@ -16480,83 +16470,36 @@
}
},
"node_modules/vue-component-type-helpers": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.2.tgz",
- "integrity": "sha512-6lLY+n2xz2kCYshl59mL6gy8OUUTmkscmDFMO8i7Lj+QKwgnIFUZmM1i/iTYObtrczZVdw7UakPqDTGwVSGaRg==",
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.8.tgz",
+ "integrity": "sha512-4bjIsC284coDO9om4HPA62M7wfsTvcmZyzdfR0aUlFXqq4tXxM1APyXpNVxPC8QazKw9OhmZNHBVDA6ODaZsrA==",
"dev": true,
"license": "MIT"
},
"node_modules/vue-eslint-parser": {
- "version": "9.4.3",
- "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz",
- "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==",
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.1.1.tgz",
+ "integrity": "sha512-bh2Z/Au5slro9QJ3neFYLanZtb1jH+W2bKqGHXAoYD4vZgNG3KeotL7JpPv5xzY4UXUXJl7TrIsnzECH63kd3Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
- "debug": "^4.3.4",
- "eslint-scope": "^7.1.1",
- "eslint-visitor-keys": "^3.3.0",
- "espree": "^9.3.1",
- "esquery": "^1.4.0",
+ "debug": "^4.4.0",
+ "eslint-scope": "^8.2.0",
+ "eslint-visitor-keys": "^4.2.0",
+ "espree": "^10.3.0",
+ "esquery": "^1.6.0",
"lodash": "^4.17.21",
- "semver": "^7.3.6"
+ "semver": "^7.6.3"
},
"engines": {
- "node": "^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://github.com/sponsors/mysticatea"
},
"peerDependencies": {
- "eslint": ">=6.0.0"
- }
- },
- "node_modules/vue-eslint-parser/node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/vue-eslint-parser/node_modules/espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "acorn": "^8.9.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
+ "eslint": "^8.57.0 || ^9.0.0"
}
},
"node_modules/vue-loader": {
diff --git a/package.json b/package.json
index 865017f69d..351b486c37 100644
--- a/package.json
+++ b/package.json
@@ -64,8 +64,8 @@
"@eslint-community/eslint-plugin-eslint-comments": "4.4.1",
"@playwright/test": "1.50.1",
"@stoplight/spectral-cli": "6.14.2",
- "@stylistic/eslint-plugin-js": "2.12.1",
- "@stylistic/stylelint-plugin": "3.1.1",
+ "@stylistic/eslint-plugin-js": "4.2.0",
+ "@stylistic/stylelint-plugin": "3.1.2",
"@typescript-eslint/parser": "8.18.2",
"@vitejs/plugin-vue": "5.1.5",
"@vitest/coverage-v8": "3.0.5",
@@ -83,11 +83,11 @@
"eslint-plugin-unicorn": "56.0.1",
"eslint-plugin-toml": "0.12.0",
"eslint-plugin-vitest-globals": "1.5.0",
- "eslint-plugin-vue": "9.32.0",
+ "eslint-plugin-vue": "10.0.0",
"eslint-plugin-vue-scoped-css": "2.9.0",
"eslint-plugin-wc": "2.2.0",
- "globals": "15.15.0",
- "happy-dom": "17.1.0",
+ "globals": "16.0.0",
+ "happy-dom": "17.1.8",
"license-checker-rseidelsohn": "4.4.2",
"markdownlint-cli": "0.44.0",
"postcss-html": "1.8.0",
diff --git a/poetry.lock b/poetry.lock
index 72118b2a01..707a276df7 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -44,13 +44,13 @@ files = [
[[package]]
name = "cssbeautifier"
-version = "1.15.3"
+version = "1.15.4"
description = "CSS unobfuscator and beautifier."
optional = false
python-versions = "*"
files = [
- {file = "cssbeautifier-1.15.3-py3-none-any.whl", hash = "sha256:0dcaf5ce197743a79b3a160b84ea58fcbd9e3e767c96df1171e428125b16d410"},
- {file = "cssbeautifier-1.15.3.tar.gz", hash = "sha256:406b04d09e7d62c0be084fbfa2cba5126fe37359ea0d8d9f7b963a6354fc8303"},
+ {file = "cssbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:78c84d5e5378df7d08622bbd0477a1abdbd209680e95480bf22f12d5701efc98"},
+ {file = "cssbeautifier-1.15.4.tar.gz", hash = "sha256:9bb08dc3f64c101a01677f128acf01905914cf406baf87434dcde05b74c0acf5"},
]
[package.dependencies]
@@ -115,13 +115,13 @@ files = [
[[package]]
name = "jsbeautifier"
-version = "1.15.3"
+version = "1.15.4"
description = "JavaScript unobfuscator and beautifier."
optional = false
python-versions = "*"
files = [
- {file = "jsbeautifier-1.15.3-py3-none-any.whl", hash = "sha256:b207a15ab7529eee4a35ae7790e9ec4e32a2b5026d51e2d0386c3a65e6ecfc91"},
- {file = "jsbeautifier-1.15.3.tar.gz", hash = "sha256:5f1baf3d4ca6a615bb5417ee861b34b77609eeb12875555f8bbfabd9bf2f3457"},
+ {file = "jsbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:72f65de312a3f10900d7685557f84cb61a9733c50dcc27271a39f5b0051bf528"},
+ {file = "jsbeautifier-1.15.4.tar.gz", hash = "sha256:5bb18d9efb9331d825735fbc5360ee8f1aac5e52780042803943aa7f854f7592"},
]
[package.dependencies]
diff --git a/release-notes/6523.md b/release-notes/6523.md
new file mode 100644
index 0000000000..96a1fe0cf3
--- /dev/null
+++ b/release-notes/6523.md
@@ -0,0 +1 @@
+Reduce noise in the timeline of issues and pull requests. If certain timeline events are performed within a certain timeframe of each other with no other events in between, they will be combined into a single timeline event, and any contradictory actions will be canceled and not displayed. The older the events, the wider the timeframe will become.
diff --git a/routers/api/actions/ping/ping_test.go b/routers/api/actions/ping/ping_test.go
index 098b003ea2..98d2dcb820 100644
--- a/routers/api/actions/ping/ping_test.go
+++ b/routers/api/actions/ping/ping_test.go
@@ -4,7 +4,6 @@
package ping
import (
- "context"
"net/http"
"net/http/httptest"
"testing"
@@ -51,7 +50,7 @@ func MainServiceTest(t *testing.T, h http.Handler) {
clients := []pingv1connect.PingServiceClient{connectClient, grpcClient, grpcWebClient}
t.Run("ping request", func(t *testing.T) {
for _, client := range clients {
- result, err := client.Ping(context.Background(), connect.NewRequest(&pingv1.PingRequest{
+ result, err := client.Ping(t.Context(), connect.NewRequest(&pingv1.PingRequest{
Data: "foobar",
}))
require.NoError(t, err)
diff --git a/routers/api/actions/runner/runner.go b/routers/api/actions/runner/runner.go
index cb47074e98..4316b4a8e1 100644
--- a/routers/api/actions/runner/runner.go
+++ b/routers/api/actions/runner/runner.go
@@ -158,7 +158,7 @@ func (s *Service) FetchTask(
// if the task version in request is not equal to the version in db,
// it means there may still be some tasks not be assigned.
// try to pick a task for the runner that send the request.
- if t, ok, err := pickTask(ctx, runner); err != nil {
+ if t, ok, err := actions_service.PickTask(ctx, runner); err != nil {
log.Error("pick task failed: %v", err)
return nil, status.Errorf(codes.Internal, "pick task: %v", err)
} else if ok {
diff --git a/routers/api/actions/runner/utils.go b/routers/api/actions/runner/utils.go
deleted file mode 100644
index 0fd7ca5c44..0000000000
--- a/routers/api/actions/runner/utils.go
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package runner
-
-import (
- "context"
- "fmt"
-
- actions_model "code.gitea.io/gitea/models/actions"
- secret_model "code.gitea.io/gitea/models/secret"
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/services/actions"
-
- runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
- "google.golang.org/protobuf/types/known/structpb"
-)
-
-func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv1.Task, bool, error) {
- t, ok, err := actions_model.CreateTaskForRunner(ctx, runner)
- if err != nil {
- return nil, false, fmt.Errorf("CreateTaskForRunner: %w", err)
- }
- if !ok {
- return nil, false, nil
- }
-
- secrets, err := secret_model.GetSecretsOfTask(ctx, t)
- if err != nil {
- return nil, false, fmt.Errorf("GetSecretsOfTask: %w", err)
- }
-
- vars, err := actions_model.GetVariablesOfRun(ctx, t.Job.Run)
- if err != nil {
- return nil, false, fmt.Errorf("GetVariablesOfRun: %w", err)
- }
-
- actions.CreateCommitStatus(ctx, t.Job)
-
- task := &runnerv1.Task{
- Id: t.ID,
- WorkflowPayload: t.Job.WorkflowPayload,
- Context: generateTaskContext(t),
- Secrets: secrets,
- Vars: vars,
- }
-
- if needs, err := findTaskNeeds(ctx, t); err != nil {
- log.Error("Cannot find needs for task %v: %v", t.ID, err)
- // Go on with empty needs.
- // If return error, the task will be wild, which means the runner will never get it when it has been assigned to the runner.
- // In contrast, missing needs is less serious.
- // And the task will fail and the runner will report the error in the logs.
- } else {
- task.Needs = needs
- }
-
- return task, true, nil
-}
-
-func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
- giteaRuntimeToken, err := actions.CreateAuthorizationToken(t.ID, t.Job.RunID, t.JobID)
- if err != nil {
- log.Error("actions.CreateAuthorizationToken failed: %v", err)
- }
-
- gitCtx := actions.GenerateGiteaContext(t.Job.Run, t.Job)
- gitCtx["token"] = t.Token
- gitCtx["gitea_runtime_token"] = giteaRuntimeToken
-
- taskContext, err := structpb.NewStruct(gitCtx)
- if err != nil {
- log.Error("structpb.NewStruct failed: %v", err)
- }
-
- return taskContext
-}
-
-func findTaskNeeds(ctx context.Context, task *actions_model.ActionTask) (map[string]*runnerv1.TaskNeed, error) {
- if err := task.LoadAttributes(ctx); err != nil {
- return nil, fmt.Errorf("task LoadAttributes: %w", err)
- }
- taskNeeds, err := actions.FindTaskNeeds(ctx, task.Job)
- if err != nil {
- return nil, err
- }
- ret := make(map[string]*runnerv1.TaskNeed, len(taskNeeds))
- for jobID, taskNeed := range taskNeeds {
- ret[jobID] = &runnerv1.TaskNeed{
- Outputs: taskNeed.Outputs,
- Result: runnerv1.Result(taskNeed.Result),
- }
- }
- return ret, nil
-}
diff --git a/routers/api/packages/composer/api.go b/routers/api/packages/composer/api.go
index a3bcf80417..a3ea2c2f9a 100644
--- a/routers/api/packages/composer/api.go
+++ b/routers/api/packages/composer/api.go
@@ -66,6 +66,7 @@ type PackageMetadataResponse struct {
}
// PackageVersionMetadata contains package metadata
+// https://getcomposer.org/doc/05-repositories.md#package
type PackageVersionMetadata struct {
*composer_module.Metadata
Name string `json:"name"`
@@ -73,6 +74,7 @@ type PackageVersionMetadata struct {
Type string `json:"type"`
Created time.Time `json:"time"`
Dist Dist `json:"dist"`
+ Source Source `json:"source"`
}
// Dist contains package download information
@@ -82,6 +84,13 @@ type Dist struct {
Checksum string `json:"shasum"`
}
+// Source contains package source information
+type Source struct {
+ URL string `json:"url"`
+ Type string `json:"type"`
+ Reference string `json:"reference"`
+}
+
func createPackageMetadataResponse(registryURL string, pds []*packages_model.PackageDescriptor) *PackageMetadataResponse {
versions := make([]*PackageVersionMetadata, 0, len(pds))
@@ -94,7 +103,7 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac
}
}
- versions = append(versions, &PackageVersionMetadata{
+ pkg := PackageVersionMetadata{
Name: pd.Package.Name,
Version: pd.Version.Version,
Type: packageType,
@@ -105,7 +114,16 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac
URL: fmt.Sprintf("%s/files/%s/%s/%s", registryURL, url.PathEscape(pd.Package.LowerName), url.PathEscape(pd.Version.LowerVersion), url.PathEscape(pd.Files[0].File.LowerName)),
Checksum: pd.Files[0].Blob.HashSHA1,
},
- })
+ }
+ if pd.Repository != nil {
+ pkg.Source = Source{
+ URL: pd.Repository.HTMLURL(),
+ Type: "git",
+ Reference: pd.Version.Version,
+ }
+ }
+
+ versions = append(versions, &pkg)
}
return &PackageMetadataResponse{
diff --git a/routers/api/packages/nuget/api_v2.go b/routers/api/packages/nuget/api_v2.go
index a726065ad0..073b2700ef 100644
--- a/routers/api/packages/nuget/api_v2.go
+++ b/routers/api/packages/nuget/api_v2.go
@@ -249,6 +249,9 @@ type FeedEntryProperties struct {
Version string `xml:"d:Version"`
NormalizedVersion string `xml:"d:NormalizedVersion"`
Authors string `xml:"d:Authors"`
+ Owners string `xml:"d:Owners,omitempty"`
+ Copyright string `xml:"d:Copyright,omitempty"`
+ Language string `xml:"d:Language,omitempty"`
Dependencies string `xml:"d:Dependencies"`
Description string `xml:"d:Description"`
VersionDownloadCount TypedValue[int64] `xml:"d:VersionDownloadCount"`
@@ -258,9 +261,15 @@ type FeedEntryProperties struct {
LastUpdated TypedValue[time.Time] `xml:"d:LastUpdated"`
Published TypedValue[time.Time] `xml:"d:Published"`
ProjectURL string `xml:"d:ProjectUrl,omitempty"`
+ LicenseURL string `xml:"d:LicenseUrl,omitempty"`
+ IconURL string `xml:"d:IconUrl,omitempty"`
ReleaseNotes string `xml:"d:ReleaseNotes,omitempty"`
RequireLicenseAcceptance TypedValue[bool] `xml:"d:RequireLicenseAcceptance"`
- Title string `xml:"d:Title"`
+ DevelopmentDependency TypedValue[bool] `xml:"d:DevelopmentDependency"`
+ Title string `xml:"d:Title,omitempty"`
+ MinClientVersion string `xml:"d:MinClientVersion,omitempty"`
+ Tags string `xml:"d:Tags,omitempty"`
+ ID string `xml:"d:Id,omitempty"`
}
type FeedEntry struct {
@@ -356,6 +365,9 @@ func createEntry(l *linkBuilder, pd *packages_model.PackageDescriptor, withNames
Version: pd.Version.Version,
NormalizedVersion: pd.Version.Version,
Authors: metadata.Authors,
+ Owners: metadata.Owners,
+ Copyright: metadata.Copyright,
+ Language: metadata.Language,
Dependencies: buildDependencyString(metadata),
Description: metadata.Description,
VersionDownloadCount: TypedValue[int64]{Type: "Edm.Int64", Value: pd.Version.DownloadCount},
@@ -365,9 +377,15 @@ func createEntry(l *linkBuilder, pd *packages_model.PackageDescriptor, withNames
LastUpdated: createdValue,
Published: createdValue,
ProjectURL: metadata.ProjectURL,
+ LicenseURL: metadata.LicenseURL,
+ IconURL: metadata.IconURL,
ReleaseNotes: metadata.ReleaseNotes,
RequireLicenseAcceptance: TypedValue[bool]{Type: "Edm.Boolean", Value: metadata.RequireLicenseAcceptance},
- Title: pd.Package.Name,
+ DevelopmentDependency: TypedValue[bool]{Type: "Edm.Boolean", Value: metadata.DevelopmentDependency},
+ Title: metadata.Title,
+ MinClientVersion: metadata.MinClientVersion,
+ Tags: metadata.Tags,
+ ID: pd.Package.Name,
},
}
diff --git a/routers/api/shared/middleware.go b/routers/api/shared/middleware.go
index e2ff004024..5e863cb9eb 100644
--- a/routers/api/shared/middleware.go
+++ b/routers/api/shared/middleware.go
@@ -6,8 +6,6 @@ package shared
import (
"net/http"
- auth_model "code.gitea.io/gitea/models/auth"
- "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/common"
@@ -51,10 +49,6 @@ func buildAuthGroup() *auth.Group {
group.Add(&auth.ReverseProxy{})
}
- if setting.IsWindows && auth_model.IsSSPIEnabled(db.DefaultContext) {
- group.Add(&auth.SSPI{}) // it MUST be the last, see the comment of SSPI
- }
-
return group
}
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 684686b1e2..3791a6fbba 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -1485,13 +1485,19 @@ func Routes() *web.Route {
// NOTE: these are Gitea package management API - see packages.CommonRoutes and packages.DockerContainerRoutes for endpoints that implement package manager APIs
m.Group("/packages/{username}", func() {
- m.Group("/{type}/{name}/{version}", func() {
- m.Get("", reqToken(), packages.GetPackage)
- m.Delete("", reqToken(), reqPackageAccess(perm.AccessModeWrite), packages.DeletePackage)
- m.Get("/files", reqToken(), packages.ListPackageFiles)
+ m.Group("/{type}/{name}", func() {
+ m.Group("/{version}", func() {
+ m.Get("", packages.GetPackage)
+ m.Delete("", reqPackageAccess(perm.AccessModeWrite), packages.DeletePackage)
+ m.Get("/files", packages.ListPackageFiles)
+ })
+
+ m.Post("/-/link/{repo_name}", reqPackageAccess(perm.AccessModeWrite), packages.LinkPackage)
+ m.Post("/-/unlink", reqPackageAccess(perm.AccessModeWrite), packages.UnlinkPackage)
})
- m.Get("/", reqToken(), packages.ListPackages)
- }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead), checkTokenPublicOnly())
+
+ m.Get("/", packages.ListPackages)
+ }, reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead), checkTokenPublicOnly())
// Organizations
m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs)
diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go
index b38aa13167..a98b5dbc69 100644
--- a/routers/api/v1/packages/package.go
+++ b/routers/api/v1/packages/package.go
@@ -4,11 +4,14 @@
package packages
import (
+ "errors"
"net/http"
"code.gitea.io/gitea/models/packages"
+ repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/optional"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
@@ -213,3 +216,122 @@ func ListPackageFiles(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, apiPackageFiles)
}
+
+// LinkPackage sets a repository link for a package
+func LinkPackage(ctx *context.APIContext) {
+ // swagger:operation POST /packages/{owner}/{type}/{name}/-/link/{repo_name} package linkPackage
+ // ---
+ // summary: Link a package to a repository
+ // parameters:
+ // - name: owner
+ // in: path
+ // description: owner of the package
+ // type: string
+ // required: true
+ // - name: type
+ // in: path
+ // description: type of the package
+ // type: string
+ // required: true
+ // - name: name
+ // in: path
+ // description: name of the package
+ // type: string
+ // required: true
+ // - name: repo_name
+ // in: path
+ // description: name of the repository to link.
+ // type: string
+ // required: true
+ // responses:
+ // "201":
+ // "$ref": "#/responses/empty"
+ // "404":
+ // "$ref": "#/responses/notFound"
+
+ pkg, err := packages.GetPackageByName(ctx, ctx.ContextUser.ID, packages.Type(ctx.PathParamRaw("type")), ctx.PathParamRaw("name"))
+ if err != nil {
+ if errors.Is(err, util.ErrNotExist) {
+ ctx.Error(http.StatusNotFound, "GetPackageByName", err)
+ } else {
+ ctx.Error(http.StatusInternalServerError, "GetPackageByName", err)
+ }
+ return
+ }
+
+ repo, err := repo_model.GetRepositoryByName(ctx, ctx.ContextUser.ID, ctx.PathParamRaw("repo_name"))
+ if err != nil {
+ if errors.Is(err, util.ErrNotExist) {
+ ctx.Error(http.StatusNotFound, "GetRepositoryByName", err)
+ } else {
+ ctx.Error(http.StatusInternalServerError, "GetRepositoryByName", err)
+ }
+ return
+ }
+
+ err = packages_service.LinkToRepository(ctx, pkg, repo, ctx.Doer)
+ if err != nil {
+ switch {
+ case errors.Is(err, util.ErrInvalidArgument):
+ ctx.Error(http.StatusBadRequest, "LinkToRepository", err)
+ case errors.Is(err, util.ErrPermissionDenied):
+ ctx.Error(http.StatusForbidden, "LinkToRepository", err)
+ default:
+ ctx.Error(http.StatusInternalServerError, "LinkToRepository", err)
+ }
+ return
+ }
+ ctx.Status(http.StatusCreated)
+}
+
+// UnlinkPackage sets a repository link for a package
+func UnlinkPackage(ctx *context.APIContext) {
+ // swagger:operation POST /packages/{owner}/{type}/{name}/-/unlink package unlinkPackage
+ // ---
+ // summary: Unlink a package from a repository
+ // parameters:
+ // - name: owner
+ // in: path
+ // description: owner of the package
+ // type: string
+ // required: true
+ // - name: type
+ // in: path
+ // description: type of the package
+ // type: string
+ // required: true
+ // - name: name
+ // in: path
+ // description: name of the package
+ // type: string
+ // required: true
+ // responses:
+ // "201":
+ // "$ref": "#/responses/empty"
+ // "404":
+ // "$ref": "#/responses/notFound"
+
+ pkg, err := packages.GetPackageByName(ctx, ctx.ContextUser.ID, packages.Type(ctx.PathParamRaw("type")), ctx.PathParamRaw("name"))
+ if err != nil {
+ if errors.Is(err, util.ErrNotExist) {
+ ctx.Error(http.StatusNotFound, "GetPackageByName", err)
+ } else {
+ ctx.Error(http.StatusInternalServerError, "GetPackageByName", err)
+ }
+ return
+ }
+
+ err = packages_service.UnlinkFromRepository(ctx, pkg, ctx.Doer)
+ if err != nil {
+ switch {
+ case errors.Is(err, util.ErrPermissionDenied):
+ ctx.Error(http.StatusForbidden, "UnlinkFromRepository", err)
+ case errors.Is(err, util.ErrInvalidArgument):
+ ctx.Error(http.StatusBadRequest, "UnlinkFromRepository", err)
+ default:
+ ctx.Error(http.StatusInternalServerError, "UnlinkFromRepository", err)
+ }
+ return
+ }
+ ctx.Status(http.StatusNoContent)
+}
diff --git a/routers/common/errpage_test.go b/routers/common/errpage_test.go
index 4fd63ba49e..f15d3f1b35 100644
--- a/routers/common/errpage_test.go
+++ b/routers/common/errpage_test.go
@@ -4,7 +4,6 @@
package common
import (
- "context"
"errors"
"net/http"
"net/http/httptest"
@@ -21,7 +20,7 @@ import (
func TestRenderPanicErrorPage(t *testing.T) {
w := httptest.NewRecorder()
req := &http.Request{URL: &url.URL{}}
- req = req.WithContext(middleware.WithContextData(context.Background()))
+ req = req.WithContext(middleware.WithContextData(t.Context()))
RenderPanicErrorPage(w, req, errors.New("fake panic error (for test only)"))
respContent := w.Body.String()
assert.Contains(t, respContent, `class="page-content status-page-500"`)
diff --git a/routers/install/install.go b/routers/install/install.go
index 24db25f459..86e342f1f9 100644
--- a/routers/install/install.go
+++ b/routers/install/install.go
@@ -29,7 +29,6 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/translation"
- "code.gitea.io/gitea/modules/user"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/routers/common"
@@ -119,15 +118,7 @@ func Install(ctx *context.Context) {
form.AppSlogan = "Beyond coding. We Forge."
form.RepoRootPath = setting.RepoRootPath
form.LFSRootPath = setting.LFS.Storage.Path
-
- // Note(unknown): it's hard for Windows users change a running user,
- // so just use current one if config says default.
- if setting.IsWindows && setting.RunUser == "git" {
- form.RunUser = user.CurrentUsername()
- } else {
- form.RunUser = setting.RunUser
- }
-
+ form.RunUser = setting.RunUser
form.Domain = setting.Domain
form.SSHPort = setting.SSH.Port
form.HTTPPort = setting.HTTPPort
diff --git a/routers/private/hook_verification_test.go b/routers/private/hook_verification_test.go
index 5f0d1d0f4f..47e06245ed 100644
--- a/routers/private/hook_verification_test.go
+++ b/routers/private/hook_verification_test.go
@@ -4,7 +4,6 @@
package private
import (
- "context"
"testing"
"code.gitea.io/gitea/models/unittest"
@@ -18,7 +17,7 @@ var testReposDir = "tests/repos/"
func TestVerifyCommits(t *testing.T) {
unittest.PrepareTestEnv(t)
- gitRepo, err := git.OpenRepository(context.Background(), testReposDir+"repo1_hook_verification")
+ gitRepo, err := git.OpenRepository(t.Context(), testReposDir+"repo1_hook_verification")
defer gitRepo.Close()
require.NoError(t, err)
diff --git a/routers/private/manager_unix.go b/routers/private/manager_unix.go
index 0c63ebc918..311bfe6858 100644
--- a/routers/private/manager_unix.go
+++ b/routers/private/manager_unix.go
@@ -1,8 +1,6 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-//go:build !windows
-
package private
import (
diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go
index dcdc8e6a2a..8af14f6d52 100644
--- a/routers/web/admin/auths.go
+++ b/routers/web/admin/auths.go
@@ -4,11 +4,9 @@
package admin
import (
- "errors"
"fmt"
"net/http"
"net/url"
- "regexp"
"strconv"
"strings"
@@ -18,14 +16,12 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
auth_service "code.gitea.io/gitea/services/auth"
"code.gitea.io/gitea/services/auth/source/ldap"
"code.gitea.io/gitea/services/auth/source/oauth2"
pam_service "code.gitea.io/gitea/services/auth/source/pam"
"code.gitea.io/gitea/services/auth/source/smtp"
- "code.gitea.io/gitea/services/auth/source/sspi"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
@@ -38,11 +34,6 @@ const (
tplAuthEdit base.TplName = "admin/auth/edit"
)
-var (
- separatorAntiPattern = regexp.MustCompile(`[^\w-\.]`)
- langCodePattern = regexp.MustCompile(`^[a-z]{2}-[A-Z]{2}$`)
-)
-
// Authentications show authentication config page
func Authentications(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("admin.authentication")
@@ -70,7 +61,6 @@ var (
{auth.DLDAP.String(), auth.DLDAP},
{auth.SMTP.String(), auth.SMTP},
{auth.OAuth2.String(), auth.OAuth2},
- {auth.SSPI.String(), auth.SSPI},
}
if pam.Supported {
items = append(items, dropdownItem{auth.Names[auth.PAM], auth.PAM})
@@ -102,12 +92,6 @@ func NewAuthSource(ctx *context.Context) {
oauth2providers := oauth2.GetSupportedOAuth2Providers()
ctx.Data["OAuth2Providers"] = oauth2providers
- ctx.Data["SSPIAutoCreateUsers"] = true
- ctx.Data["SSPIAutoActivateUsers"] = true
- ctx.Data["SSPIStripDomainNames"] = true
- ctx.Data["SSPISeparatorReplacement"] = "_"
- ctx.Data["SSPIDefaultLanguage"] = ""
-
// only the first as default
ctx.Data["oauth2_provider"] = oauth2providers[0].Name()
@@ -209,30 +193,6 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
}
}
-func parseSSPIConfig(ctx *context.Context, form forms.AuthenticationForm) (*sspi.Source, error) {
- if util.IsEmptyString(form.SSPISeparatorReplacement) {
- ctx.Data["Err_SSPISeparatorReplacement"] = true
- return nil, errors.New(ctx.Locale.TrString("form.SSPISeparatorReplacement") + ctx.Locale.TrString("form.require_error"))
- }
- if separatorAntiPattern.MatchString(form.SSPISeparatorReplacement) {
- ctx.Data["Err_SSPISeparatorReplacement"] = true
- return nil, errors.New(ctx.Locale.TrString("form.SSPISeparatorReplacement") + ctx.Locale.TrString("form.alpha_dash_dot_error"))
- }
-
- if form.SSPIDefaultLanguage != "" && !langCodePattern.MatchString(form.SSPIDefaultLanguage) {
- ctx.Data["Err_SSPIDefaultLanguage"] = true
- return nil, errors.New(ctx.Locale.TrString("form.lang_select_error"))
- }
-
- return &sspi.Source{
- AutoCreateUsers: form.SSPIAutoCreateUsers,
- AutoActivateUsers: form.SSPIAutoActivateUsers,
- StripDomainNames: form.SSPIStripDomainNames,
- SeparatorReplacement: form.SSPISeparatorReplacement,
- DefaultLanguage: form.SSPIDefaultLanguage,
- }, nil
-}
-
// NewAuthSourcePost response for adding an auth source
func NewAuthSourcePost(ctx *context.Context) {
form := *web.GetForm(ctx).(*forms.AuthenticationForm)
@@ -247,12 +207,6 @@ func NewAuthSourcePost(ctx *context.Context) {
oauth2providers := oauth2.GetSupportedOAuth2Providers()
ctx.Data["OAuth2Providers"] = oauth2providers
- ctx.Data["SSPIAutoCreateUsers"] = true
- ctx.Data["SSPIAutoActivateUsers"] = true
- ctx.Data["SSPIStripDomainNames"] = true
- ctx.Data["SSPISeparatorReplacement"] = "_"
- ctx.Data["SSPIDefaultLanguage"] = ""
-
hasTLS := false
var config convert.Conversion
switch auth.Type(form.Type) {
@@ -279,19 +233,6 @@ func NewAuthSourcePost(ctx *context.Context) {
return
}
}
- case auth.SSPI:
- var err error
- config, err = parseSSPIConfig(ctx, form)
- if err != nil {
- ctx.RenderWithErr(err.Error(), tplAuthNew, form)
- return
- }
- existing, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{LoginType: auth.SSPI})
- if err != nil || len(existing) > 0 {
- ctx.Data["Err_Type"] = true
- ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_of_type_exist"), tplAuthNew, form)
- return
- }
default:
ctx.Error(http.StatusBadRequest)
return
@@ -408,12 +349,6 @@ func EditAuthSourcePost(ctx *context.Context) {
return
}
}
- case auth.SSPI:
- config, err = parseSSPIConfig(ctx, form)
- if err != nil {
- ctx.RenderWithErr(err.Error(), tplAuthEdit, form)
- return
- }
default:
ctx.Error(http.StatusBadRequest)
return
diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go
index d592dff077..1d00c97b6e 100644
--- a/routers/web/auth/auth.go
+++ b/routers/web/auth/auth.go
@@ -164,7 +164,6 @@ func SignIn(ctx *context.Context) {
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
ctx.Data["PageIsSignIn"] = true
ctx.Data["PageIsLogin"] = true
- ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx)
ctx.Data["EnableInternalSignIn"] = setting.Service.EnableInternalSignIn
if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin {
@@ -190,7 +189,6 @@ func SignInPost(ctx *context.Context) {
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
ctx.Data["PageIsSignIn"] = true
ctx.Data["PageIsLogin"] = true
- ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx)
ctx.Data["EnableInternalSignIn"] = setting.Service.EnableInternalSignIn
ctx.Data["DisablePassword"] = !setting.Service.EnableInternalSignIn
diff --git a/routers/web/org/setting/storage_overview.go b/routers/web/org/setting/storage_overview.go
new file mode 100644
index 0000000000..4b9bd02ca4
--- /dev/null
+++ b/routers/web/org/setting/storage_overview.go
@@ -0,0 +1,20 @@
+// Copyright 2024 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package setting
+
+import (
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/routers/web/shared"
+ "code.gitea.io/gitea/services/context"
+)
+
+const (
+ tplSettingsStorageOverview base.TplName = "org/settings/storage_overview"
+)
+
+// StorageOverview render a size overview of the organization, as well as relevant
+// quota limits of the instance.
+func StorageOverview(ctx *context.Context) {
+ shared.StorageOverview(ctx, ctx.Org.Organization.ID, tplSettingsStorageOverview)
+}
diff --git a/routers/web/repo/action_aggregator_test.go b/routers/web/repo/action_aggregator_test.go
new file mode 100644
index 0000000000..181c1120db
--- /dev/null
+++ b/routers/web/repo/action_aggregator_test.go
@@ -0,0 +1,800 @@
+// Copyright 2025 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package repo
+
+import (
+ "strings"
+ "testing"
+
+ issue_model "code.gitea.io/gitea/models/issues"
+ "code.gitea.io/gitea/models/organization"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/timeutil"
+
+ "github.com/stretchr/testify/assert"
+)
+
+// *************** Helper functions for the tests ***************
+
+func testComment(t int64) *issue_model.Comment {
+ return &issue_model.Comment{PosterID: 1, CreatedUnix: timeutil.TimeStamp(t)}
+}
+
+func nameToID(name string) int64 {
+ var id int64
+ for c, letter := range name {
+ id += int64((c+1)*1000) * int64(letter)
+ }
+ return id
+}
+
+func createReqReviewTarget(name string) issue_model.RequestReviewTarget {
+ if strings.HasSuffix(name, "-team") {
+ team := createTeam(name)
+ return issue_model.RequestReviewTarget{Team: &team}
+ }
+ user := createUser(name)
+ return issue_model.RequestReviewTarget{User: &user}
+}
+
+func createUser(name string) user_model.User {
+ return user_model.User{Name: name, ID: nameToID(name)}
+}
+
+func createTeam(name string) organization.Team {
+ return organization.Team{Name: name, ID: nameToID(name)}
+}
+
+func createLabel(name string) issue_model.Label {
+ return issue_model.Label{Name: name, ID: nameToID(name)}
+}
+
+func addLabel(t int64, name string) *issue_model.Comment {
+ c := testComment(t)
+ c.Type = issue_model.CommentTypeLabel
+ c.Content = "1"
+ lbl := createLabel(name)
+ c.Label = &lbl
+ c.AddedLabels = []*issue_model.Label{&lbl}
+ return c
+}
+
+func delLabel(t int64, name string) *issue_model.Comment {
+ c := addLabel(t, name)
+ c.Content = ""
+ c.RemovedLabels = c.AddedLabels
+ c.AddedLabels = nil
+ return c
+}
+
+func openOrClose(t int64, close bool) *issue_model.Comment {
+ c := testComment(t)
+ if close {
+ c.Type = issue_model.CommentTypeClose
+ } else {
+ c.Type = issue_model.CommentTypeReopen
+ }
+ return c
+}
+
+func reqReview(t int64, name string, delReq bool) *issue_model.Comment {
+ c := testComment(t)
+ c.Type = issue_model.CommentTypeReviewRequest
+ if strings.HasSuffix(name, "-team") {
+ team := createTeam(name)
+ c.AssigneeTeam = &team
+ c.AssigneeTeamID = team.ID
+ } else {
+ user := createUser(name)
+ c.Assignee = &user
+ c.AssigneeID = user.ID
+ }
+ c.RemovedAssignee = delReq
+ return c
+}
+
+func reqReviewList(t int64, del bool, names ...string) *issue_model.Comment {
+ req := []issue_model.RequestReviewTarget{}
+ for _, name := range names {
+ req = append(req, createReqReviewTarget(name))
+ }
+ cmnt := testComment(t)
+ cmnt.Type = issue_model.CommentTypeReviewRequest
+ if del {
+ cmnt.RemovedRequestReview = req
+ } else {
+ cmnt.AddedRequestReview = req
+ }
+ return cmnt
+}
+
+func aggregatedComment(t int64,
+ closed bool,
+ addLabels []*issue_model.Label,
+ delLabels []*issue_model.Label,
+ addReqReview []issue_model.RequestReviewTarget,
+ delReqReview []issue_model.RequestReviewTarget,
+) *issue_model.Comment {
+ cmnt := testComment(t)
+ cmnt.Type = issue_model.CommentTypeAggregator
+ cmnt.Aggregator = &issue_model.ActionAggregator{
+ IsClosed: closed,
+ AddedLabels: addLabels,
+ RemovedLabels: delLabels,
+ AddedRequestReview: addReqReview,
+ RemovedRequestReview: delReqReview,
+ }
+ if len(addLabels) > 0 {
+ cmnt.AddedLabels = addLabels
+ }
+ if len(delLabels) > 0 {
+ cmnt.RemovedLabels = delLabels
+ }
+ if len(addReqReview) > 0 {
+ cmnt.AddedRequestReview = addReqReview
+ }
+ if len(delReqReview) > 0 {
+ cmnt.RemovedRequestReview = delReqReview
+ }
+ return cmnt
+}
+
+func commentText(t int64, text string) *issue_model.Comment {
+ c := testComment(t)
+ c.Type = issue_model.CommentTypeComment
+ c.Content = text
+ return c
+}
+
+// ****************************************************************
+
+type testCase struct {
+ name string
+ beforeCombined []*issue_model.Comment
+ afterCombined []*issue_model.Comment
+ sameAfter bool
+ timestampCombination int64
+}
+
+func (kase *testCase) doTest(t *testing.T) {
+ issue := issue_model.Issue{Comments: kase.beforeCombined}
+
+ var now int64 = -9223372036854775808
+ for c := 0; c < len(kase.beforeCombined); c++ {
+ assert.Greater(t, int64(kase.beforeCombined[c].CreatedUnix), now)
+ now = int64(kase.beforeCombined[c].CreatedUnix)
+ }
+
+ if kase.timestampCombination != 0 {
+ now = kase.timestampCombination
+ }
+
+ issue_model.CombineCommentsHistory(&issue, now)
+
+ after := kase.afterCombined
+ if kase.sameAfter {
+ after = kase.beforeCombined
+ }
+
+ if len(after) != len(issue.Comments) {
+ t.Logf("Expected %v comments, got %v", len(after), len(issue.Comments))
+ t.Logf("Comments got after combination:")
+ for c := 0; c < len(issue.Comments); c++ {
+ cmt := issue.Comments[c]
+ t.Logf("%v %v %v\n", cmt.Type, cmt.CreatedUnix, cmt.Content)
+ }
+ assert.EqualValues(t, len(after), len(issue.Comments))
+ t.Fail()
+ return
+ }
+
+ for c := 0; c < len(after); c++ {
+ l := (after)[c]
+ r := issue.Comments[c]
+
+ // Ignore some inner data of the aggregator to facilitate testing
+ if l.Type == issue_model.CommentTypeAggregator {
+ r.Aggregator.StartUnix = 0
+ r.Aggregator.PrevClosed = false
+ r.Aggregator.PosterID = 0
+ r.Aggregator.StartInd = 0
+ r.Aggregator.EndInd = 0
+ r.Aggregator.AggAge = 0
+ }
+
+ // We can safely ignore this if the rest matches
+ if l.Type == issue_model.CommentTypeLabel {
+ l.Label = nil
+ l.Content = ""
+ } else if l.Type == issue_model.CommentTypeReviewRequest {
+ l.Assignee = nil
+ l.AssigneeID = 0
+ l.AssigneeTeam = nil
+ l.AssigneeTeamID = 0
+ }
+
+ assert.EqualValues(t, (after)[c], issue.Comments[c],
+ "Comment %v is not equal", c,
+ )
+ }
+}
+
+// **************** Start of the tests ******************
+
+func TestCombineLabelComments(t *testing.T) {
+ var tmon int64 = 60 * 60 * 24 * 30
+ var tday int64 = 60 * 60 * 24
+ var thour int64 = 60 * 60
+ kases := []testCase{
+ // ADD single = normal label comment
+ {
+ name: "add_single_label",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(0, "a"),
+ commentText(10, "I'm a salmon"),
+ },
+ sameAfter: true,
+ },
+
+ // ADD then REMOVE = Nothing
+ {
+ name: "add_label_then_remove",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(0, "a"),
+ delLabel(1, "a"),
+ commentText(65, "I'm a salmon"),
+ },
+ afterCombined: []*issue_model.Comment{
+ commentText(65, "I'm a salmon"),
+ },
+ },
+
+ // ADD 1 then comment then REMOVE = separate comments
+ {
+ name: "add_label_then_comment_then_remove",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(0, "a"),
+ commentText(10, "I'm a salmon"),
+ delLabel(20, "a"),
+ },
+ sameAfter: true,
+ },
+
+ // ADD 2 = Combined labels
+ {
+ name: "combine_labels",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(0, "a"),
+ addLabel(10, "b"),
+ commentText(20, "I'm a salmon"),
+ addLabel(30, "c"),
+ addLabel(80, "d"),
+ addLabel(85, "e"),
+ delLabel(90, "c"),
+ },
+ afterCombined: []*issue_model.Comment{
+ {
+ PosterID: 1,
+ Type: issue_model.CommentTypeLabel,
+ CreatedUnix: timeutil.TimeStamp(0),
+ AddedLabels: []*issue_model.Label{
+ {Name: "a", ID: nameToID("a")},
+ {Name: "b", ID: nameToID("b")},
+ },
+ },
+ commentText(20, "I'm a salmon"),
+ {
+ PosterID: 1,
+ Type: issue_model.CommentTypeLabel,
+ CreatedUnix: timeutil.TimeStamp(30),
+ AddedLabels: []*issue_model.Label{
+ {Name: "d", ID: nameToID("d")},
+ {Name: "e", ID: nameToID("e")},
+ },
+ },
+ },
+ },
+
+ // ADD 1, then 1 later = 2 separate comments
+ {
+ name: "add_then_later_label",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(0, "a"),
+ addLabel(60, "b"),
+ addLabel(121, "c"),
+ },
+ afterCombined: []*issue_model.Comment{
+ {
+ PosterID: 1,
+ Type: issue_model.CommentTypeLabel,
+ CreatedUnix: timeutil.TimeStamp(0),
+ AddedLabels: []*issue_model.Label{
+ {Name: "a", ID: nameToID("a")},
+ {Name: "b", ID: nameToID("b")},
+ },
+ },
+ addLabel(121, "c"),
+ },
+ },
+
+ // ADD 2 then REMOVE 1 = label
+ {
+ name: "add_2_remove_1",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(0, "a"),
+ addLabel(10, "b"),
+ delLabel(20, "a"),
+ },
+ afterCombined: []*issue_model.Comment{
+ // The timestamp will be the one of the first aggregated comment
+ addLabel(0, "b"),
+ },
+ },
+
+ // ADD then REMOVE multiple = nothing
+ {
+ name: "add_multiple_remove_all",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(0, "a"),
+ addLabel(1, "b"),
+ addLabel(2, "c"),
+ addLabel(3, "d"),
+ addLabel(4, "e"),
+ delLabel(5, "d"),
+ delLabel(6, "a"),
+ delLabel(7, "e"),
+ delLabel(8, "c"),
+ delLabel(9, "b"),
+ },
+ afterCombined: nil,
+ },
+
+ // ADD 2, wait, REMOVE 2 = +2 then -2 comments
+ {
+ name: "add2_wait_rm2_labels",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(0, "a"),
+ addLabel(1, "b"),
+ delLabel(120, "a"),
+ delLabel(121, "b"),
+ },
+ afterCombined: []*issue_model.Comment{
+ {
+ PosterID: 1,
+ Type: issue_model.CommentTypeLabel,
+ CreatedUnix: timeutil.TimeStamp(0),
+ AddedLabels: []*issue_model.Label{
+ {Name: "a", ID: nameToID("a")},
+ {Name: "b", ID: nameToID("b")},
+ },
+ },
+ {
+ PosterID: 1,
+ Type: issue_model.CommentTypeLabel,
+ CreatedUnix: timeutil.TimeStamp(120),
+ RemovedLabels: []*issue_model.Label{
+ {Name: "a", ID: nameToID("a")},
+ {Name: "b", ID: nameToID("b")},
+ },
+ },
+ },
+ },
+
+ // Regression check on edge case
+ {
+ name: "regression_edgecase_finalagg",
+ beforeCombined: []*issue_model.Comment{
+ commentText(0, "hey"),
+ commentText(1, "ho"),
+ addLabel(2, "a"),
+ addLabel(3, "b"),
+ delLabel(4, "a"),
+ delLabel(5, "b"),
+
+ addLabel(120, "a"),
+
+ addLabel(220, "c"),
+ addLabel(221, "d"),
+ addLabel(222, "e"),
+ delLabel(223, "d"),
+
+ delLabel(400, "a"),
+ },
+ afterCombined: []*issue_model.Comment{
+ commentText(0, "hey"),
+ commentText(1, "ho"),
+ addLabel(120, "a"),
+ {
+ PosterID: 1,
+ Type: issue_model.CommentTypeLabel,
+ CreatedUnix: timeutil.TimeStamp(220),
+ AddedLabels: []*issue_model.Label{
+ {Name: "c", ID: nameToID("c")},
+ {Name: "e", ID: nameToID("e")},
+ },
+ },
+ delLabel(400, "a"),
+ },
+ },
+
+ {
+ name: "combine_label_high_timestamp_separated",
+ timestampCombination: tmon + 1,
+ beforeCombined: []*issue_model.Comment{
+ // 1 month old, comments separated by 1 Day + 1 sec (not agg)
+ addLabel(0, "d"),
+ delLabel(tday+1, "d"),
+
+ // 1 day old, comments separated by 1 hour + 1 sec (not agg)
+ addLabel((tmon-tday)-thour, "c"),
+ delLabel((tmon-tday)+1, "c"),
+
+ // 1 hour old, comments separated by 10 mins + 1 sec (not agg)
+ addLabel(tmon-thour, "b"),
+ delLabel((tmon-(50*60))+1, "b"),
+
+ // Else, aggregate by minute
+ addLabel(tmon-61, "a"),
+ delLabel(tmon, "a"),
+ },
+ sameAfter: true,
+ },
+
+ // Test higher timestamp diff
+ {
+ name: "combine_label_high_timestamp_merged",
+ timestampCombination: tmon + 1,
+ beforeCombined: []*issue_model.Comment{
+ // 1 month old, comments separated by 1 Day (aggregated)
+ addLabel(0, "d"),
+ delLabel(tday, "d"),
+
+ // 1 day old, comments separated by 1 hour (aggregated)
+ addLabel((tmon-tday)-thour, "c"),
+ delLabel(tmon-tday, "c"),
+
+ // 1 hour old, comments separated by 10 mins (aggregated)
+ addLabel(tmon-thour, "b"),
+ delLabel(tmon-(50*60), "b"),
+
+ addLabel(tmon-60, "a"),
+ delLabel(tmon, "a"),
+ },
+ },
+ }
+
+ for _, kase := range kases {
+ t.Run(kase.name, kase.doTest)
+ }
+}
+
+func TestCombineReviewRequests(t *testing.T) {
+ kases := []testCase{
+ // ADD single = normal request review comment
+ {
+ name: "add_single_review",
+ beforeCombined: []*issue_model.Comment{
+ reqReview(0, "toto", false),
+ commentText(10, "I'm a salmon"),
+ reqReview(20, "toto-team", false),
+ },
+ sameAfter: true,
+ },
+
+ // ADD then REMOVE = Nothing
+ {
+ name: "add_then_remove_review",
+ beforeCombined: []*issue_model.Comment{
+ reqReview(0, "toto", false),
+ reqReview(5, "toto", true),
+ commentText(10, "I'm a salmon"),
+ },
+ afterCombined: []*issue_model.Comment{
+ commentText(10, "I'm a salmon"),
+ },
+ },
+
+ // ADD 1 then comment then REMOVE = separate comments
+ {
+ name: "add_comment_del_review",
+ beforeCombined: []*issue_model.Comment{
+ reqReview(0, "toto", false),
+ commentText(5, "I'm a salmon"),
+ reqReview(10, "toto", true),
+ },
+ sameAfter: true,
+ },
+
+ // ADD 2 = Combined request reviews
+ {
+ name: "combine_reviews",
+ beforeCombined: []*issue_model.Comment{
+ reqReview(0, "toto", false),
+ reqReview(10, "tutu-team", false),
+ commentText(20, "I'm a salmon"),
+ reqReview(30, "titi", false),
+ reqReview(80, "tata", false),
+ reqReview(85, "tyty-team", false),
+ reqReview(90, "titi", true),
+ },
+ afterCombined: []*issue_model.Comment{
+ reqReviewList(0, false, "toto", "tutu-team"),
+ commentText(20, "I'm a salmon"),
+ reqReviewList(30, false, "tata", "tyty-team"),
+ },
+ },
+
+ // ADD 1, then 1 later = 2 separate comments
+ {
+ name: "add_then_later_review",
+ beforeCombined: []*issue_model.Comment{
+ reqReview(0, "titi", false),
+ reqReview(60, "toto-team", false),
+ reqReview(121, "tutu", false),
+ },
+ afterCombined: []*issue_model.Comment{
+ reqReviewList(0, false, "titi", "toto-team"),
+ reqReviewList(121, false, "tutu"),
+ },
+ },
+
+ // ADD 2 then REMOVE 1 = single request review
+ {
+ name: "add_2_then_remove_review",
+ beforeCombined: []*issue_model.Comment{
+ reqReview(0, "titi-team", false),
+ reqReview(59, "toto", false),
+ reqReview(60, "titi-team", true),
+ },
+ afterCombined: []*issue_model.Comment{
+ reqReviewList(0, false, "toto"),
+ },
+ },
+
+ // ADD then REMOVE multiple = nothing
+ {
+ name: "add_multiple_then_remove_all_review",
+ beforeCombined: []*issue_model.Comment{
+ reqReview(0, "titi0-team", false),
+ reqReview(1, "toto1", false),
+ reqReview(2, "titi2", false),
+ reqReview(3, "titi3-team", false),
+ reqReview(4, "titi4", false),
+ reqReview(5, "titi5", false),
+ reqReview(6, "titi6-team", false),
+ reqReview(10, "titi0-team", true),
+ reqReview(11, "toto1", true),
+ reqReview(12, "titi2", true),
+ reqReview(13, "titi3-team", true),
+ reqReview(14, "titi4", true),
+ reqReview(15, "titi5", true),
+ reqReview(16, "titi6-team", true),
+ },
+ afterCombined: nil,
+ },
+
+ // ADD 2, wait, REMOVE 2 = +2 then -2 comments
+ {
+ name: "add2_wait_rm2_requests",
+ beforeCombined: []*issue_model.Comment{
+ reqReview(1, "titi", false),
+ reqReview(2, "toto-team", false),
+ reqReview(121, "titi", true),
+ reqReview(122, "toto-team", true),
+ },
+ afterCombined: []*issue_model.Comment{
+ reqReviewList(1, false, "titi", "toto-team"),
+ reqReviewList(121, true, "titi", "toto-team"),
+ },
+ },
+ }
+
+ for _, kase := range kases {
+ t.Run(kase.name, kase.doTest)
+ }
+}
+
+func TestCombineOpenClose(t *testing.T) {
+ kases := []testCase{
+ // Close then open = nullified
+ {
+ name: "close_open_nullified",
+ beforeCombined: []*issue_model.Comment{
+ openOrClose(0, true),
+ openOrClose(10, false),
+ },
+ afterCombined: nil,
+ },
+
+ // Close then open later = separate comments
+ {
+ name: "close_open_later",
+ beforeCombined: []*issue_model.Comment{
+ openOrClose(0, true),
+ openOrClose(61, false),
+ },
+ sameAfter: true,
+ },
+
+ // Close then comment then open = separate comments
+ {
+ name: "close_comment_open",
+ beforeCombined: []*issue_model.Comment{
+ openOrClose(0, true),
+ commentText(1, "I'm a salmon"),
+ openOrClose(2, false),
+ },
+ sameAfter: true,
+ },
+ }
+
+ for _, kase := range kases {
+ t.Run(kase.name, kase.doTest)
+ }
+}
+
+func TestCombineMultipleDifferentComments(t *testing.T) {
+ lblA := createLabel("a")
+ kases := []testCase{
+ // Add Label + Close + ReqReview = Combined
+ {
+ name: "label_close_reqreview_combined",
+ beforeCombined: []*issue_model.Comment{
+ reqReview(1, "toto", false),
+ addLabel(2, "a"),
+ openOrClose(3, true),
+
+ reqReview(101, "toto", true),
+ openOrClose(102, false),
+ delLabel(103, "a"),
+ },
+ afterCombined: []*issue_model.Comment{
+ aggregatedComment(1,
+ true,
+ []*issue_model.Label{&lblA},
+ []*issue_model.Label{},
+ []issue_model.RequestReviewTarget{createReqReviewTarget("toto")},
+ []issue_model.RequestReviewTarget{},
+ ),
+ aggregatedComment(101,
+ false,
+ []*issue_model.Label{},
+ []*issue_model.Label{&lblA},
+ []issue_model.RequestReviewTarget{},
+ []issue_model.RequestReviewTarget{createReqReviewTarget("toto")},
+ ),
+ },
+ },
+
+ // Add Req + Add Label + Close + Del Req + Del Label = Close only
+ {
+ name: "req_label_close_dellabel_delreq",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(2, "a"),
+ reqReview(3, "titi", false),
+ openOrClose(4, true),
+ delLabel(5, "a"),
+ reqReview(6, "titi", true),
+ },
+ afterCombined: []*issue_model.Comment{
+ openOrClose(2, true),
+ },
+ },
+
+ // Close + Add Req + Add Label + Del Req + Open = Label only
+ {
+ name: "close_req_label_open_delreq",
+ beforeCombined: []*issue_model.Comment{
+ openOrClose(2, true),
+ reqReview(4, "titi", false),
+ addLabel(5, "a"),
+ reqReview(6, "titi", true),
+ openOrClose(8, false),
+ },
+ afterCombined: []*issue_model.Comment{
+ addLabel(2, "a"),
+ },
+ },
+
+ // Add Label + Close + Add ReqReview + Del Label + Open = ReqReview only
+ {
+ name: "label_close_req_dellabel_open",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(1, "a"),
+ openOrClose(2, true),
+ reqReview(4, "titi", false),
+ openOrClose(7, false),
+ delLabel(8, "a"),
+ },
+ afterCombined: []*issue_model.Comment{
+ reqReviewList(1, false, "titi"),
+ },
+ },
+
+ // Add Label + Close + ReqReview, then delete everything = nothing
+ {
+ name: "add_multiple_delete_everything",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(1, "a"),
+ openOrClose(2, true),
+ reqReview(4, "titi", false),
+ openOrClose(7, false),
+ delLabel(8, "a"),
+ reqReview(10, "titi", true),
+ },
+ afterCombined: nil,
+ },
+
+ // Add multiple, then comment, then delete everything = separate aggregation
+ {
+ name: "add_multiple_comment_delete_everything",
+ beforeCombined: []*issue_model.Comment{
+ addLabel(1, "a"),
+ openOrClose(2, true),
+ reqReview(4, "titi", false),
+
+ commentText(6, "I'm a salmon"),
+
+ openOrClose(7, false),
+ delLabel(8, "a"),
+ reqReview(10, "titi", true),
+ },
+ afterCombined: []*issue_model.Comment{
+ aggregatedComment(1,
+ true,
+ []*issue_model.Label{&lblA},
+ []*issue_model.Label{},
+ []issue_model.RequestReviewTarget{createReqReviewTarget("titi")},
+ []issue_model.RequestReviewTarget{},
+ ),
+ commentText(6, "I'm a salmon"),
+ aggregatedComment(7,
+ false,
+ []*issue_model.Label{},
+ []*issue_model.Label{&lblA},
+ []issue_model.RequestReviewTarget{},
+ []issue_model.RequestReviewTarget{createReqReviewTarget("titi")},
+ ),
+ },
+ },
+
+ {
+ name: "regression_edgecase_finalagg",
+ beforeCombined: []*issue_model.Comment{
+ commentText(0, "hey"),
+ commentText(1, "ho"),
+ addLabel(2, "a"),
+ reqReview(3, "titi", false),
+ delLabel(4, "a"),
+ reqReview(5, "titi", true),
+
+ addLabel(120, "a"),
+
+ openOrClose(220, true),
+ addLabel(221, "d"),
+ reqReview(222, "toto-team", false),
+ delLabel(223, "d"),
+
+ delLabel(400, "a"),
+ },
+ afterCombined: []*issue_model.Comment{
+ commentText(0, "hey"),
+ commentText(1, "ho"),
+ addLabel(120, "a"),
+ aggregatedComment(220,
+ true,
+ []*issue_model.Label{},
+ []*issue_model.Label{},
+ []issue_model.RequestReviewTarget{createReqReviewTarget("toto-team")},
+ []issue_model.RequestReviewTarget{},
+ ),
+ delLabel(400, "a"),
+ },
+ },
+ }
+
+ for _, kase := range kases {
+ t.Run(kase.name, kase.doTest)
+ }
+}
diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go
index e5134c1f62..e0ef709ea6 100644
--- a/routers/web/repo/actions/actions.go
+++ b/routers/web/repo/actions/actions.go
@@ -240,7 +240,7 @@ func List(ctx *context.Context) {
}
ctx.Data["Actors"] = repo.MakeSelfOnTop(ctx.Doer, actors)
- ctx.Data["StatusInfoList"] = actions_model.GetStatusInfoList(ctx)
+ ctx.Data["StatusInfoList"] = actions_model.GetStatusInfoList(ctx, ctx.Locale)
pager := context.NewPagination(int(total), opts.PageSize, opts.Page, 5)
pager.SetDefaultParams(ctx)
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index c2436a1c59..857e34381e 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -315,11 +315,7 @@ func Diff(ctx *context.Context) {
commit, err := gitRepo.GetCommit(commitID)
if err != nil {
- if git.IsErrNotExist(err) {
- ctx.NotFound("Repo.GitRepo.GetCommit", err)
- } else {
- ctx.ServerError("Repo.GitRepo.GetCommit", err)
- }
+ ctx.NotFoundOrServerError("gitRepo.GetCommit", git.IsErrNotExist, err)
return
}
if len(commitID) != commit.ID.Type().FullLength() {
@@ -343,7 +339,7 @@ func Diff(ctx *context.Context) {
FileOnly: fileOnly,
}, files...)
if err != nil {
- ctx.NotFound("GetDiff", err)
+ ctx.ServerError("GetDiff", err)
return
}
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index b4c673ffd7..e45abd3952 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -1260,7 +1260,11 @@ func NewIssuePost(ctx *context.Context) {
if err := issue_service.NewIssue(ctx, repo, issue, labelIDs, attachments, assigneeIDs); err != nil {
if errors.Is(err, user_model.ErrBlockedByUser) {
- ctx.JSONError(ctx.Tr("repo.issues.blocked_by_user"))
+ if issue.IsPull {
+ ctx.JSONError(ctx.Tr("repo.pulls.blocked_by_user"))
+ } else {
+ ctx.JSONError(ctx.Tr("repo.issues.blocked_by_user"))
+ }
return
} else if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) {
ctx.Error(http.StatusBadRequest, "UserDoesNotHaveAccessToRepo", err.Error())
@@ -1830,8 +1834,7 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["LatestCloseCommentID"] = latestCloseCommentID
// Combine multiple label assignments into a single comment
- combineLabelComments(issue)
- combineRequestReviewComments(issue)
+ issues_model.CombineCommentsHistory(issue, time.Now().Unix())
getBranchData(ctx, issue)
if issue.IsPull {
@@ -2081,6 +2084,7 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["OpenGraphDescription"] = issue.Content
ctx.Data["OpenGraphImageURL"] = issue.SummaryCardURL()
ctx.Data["OpenGraphImageAltText"] = ctx.Tr("repo.issues.summary_card_alt", issue.Title, issue.Repo.FullName())
+ ctx.Data["IsBlocked"] = ctx.Doer != nil && user_model.IsBlockedMultiple(ctx, []int64{issue.PosterID, issue.Repo.OwnerID}, ctx.Doer.ID)
prepareHiddenCommentType(ctx)
if ctx.Written() {
@@ -3199,6 +3203,15 @@ func NewComment(ctx *context.Context) {
} else {
isClosed := form.Status == "close"
if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil {
+ if errors.Is(err, user_model.ErrBlockedByUser) {
+ if issue.IsPull {
+ ctx.JSONError(ctx.Tr("repo.pulls.blocked_by_user"))
+ } else {
+ ctx.JSONError(ctx.Tr("repo.issues.blocked_by_user"))
+ }
+ return
+ }
+
log.Error("ChangeStatus: %v", err)
if issues_model.IsErrDependenciesLeft(err) {
@@ -3240,7 +3253,11 @@ func NewComment(ctx *context.Context) {
comment, err := issue_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Content, attachments)
if err != nil {
if errors.Is(err, user_model.ErrBlockedByUser) {
- ctx.JSONError(ctx.Tr("repo.issues.comment.blocked_by_user"))
+ if issue.IsPull {
+ ctx.JSONError(ctx.Tr("repo.pulls.comment.blocked_by_user"))
+ } else {
+ ctx.JSONError(ctx.Tr("repo.issues.comment.blocked_by_user"))
+ }
} else {
ctx.ServerError("CreateIssueComment", err)
}
@@ -3692,194 +3709,6 @@ func attachmentsHTML(ctx *context.Context, attachments []*repo_model.Attachment,
return attachHTML
}
-type RequestReviewTarget struct {
- user *user_model.User
- team *organization.Team
-}
-
-func (t *RequestReviewTarget) ID() int64 {
- if t.user != nil {
- return t.user.ID
- }
- return t.team.ID
-}
-
-func (t *RequestReviewTarget) Name() string {
- if t.user != nil {
- return t.user.GetDisplayName()
- }
- return t.team.Name
-}
-
-func (t *RequestReviewTarget) Type() string {
- if t.user != nil {
- return "user"
- }
- return "team"
-}
-
-// combineRequestReviewComments combine the nearby request review comments as one.
-func combineRequestReviewComments(issue *issues_model.Issue) {
- var prev, cur *issues_model.Comment
- for i := 0; i < len(issue.Comments); i++ {
- cur = issue.Comments[i]
- if i > 0 {
- prev = issue.Comments[i-1]
- }
- if i == 0 || cur.Type != issues_model.CommentTypeReviewRequest ||
- (prev != nil && prev.PosterID != cur.PosterID) ||
- (prev != nil && cur.CreatedUnix-prev.CreatedUnix >= 60) {
- if cur.Type == issues_model.CommentTypeReviewRequest && (cur.Assignee != nil || cur.AssigneeTeam != nil) {
- if cur.RemovedAssignee {
- if cur.AssigneeTeam != nil {
- cur.RemovedRequestReview = append(cur.RemovedRequestReview, &RequestReviewTarget{team: cur.AssigneeTeam})
- } else {
- cur.RemovedRequestReview = append(cur.RemovedRequestReview, &RequestReviewTarget{user: cur.Assignee})
- }
- } else {
- if cur.AssigneeTeam != nil {
- cur.AddedRequestReview = append(cur.AddedRequestReview, &RequestReviewTarget{team: cur.AssigneeTeam})
- } else {
- cur.AddedRequestReview = append(cur.AddedRequestReview, &RequestReviewTarget{user: cur.Assignee})
- }
- }
- }
- continue
- }
-
- // Previous comment is not a review request, so cannot group. Start a new group.
- if prev.Type != issues_model.CommentTypeReviewRequest {
- if cur.RemovedAssignee {
- if cur.AssigneeTeam != nil {
- cur.RemovedRequestReview = append(cur.RemovedRequestReview, &RequestReviewTarget{team: cur.AssigneeTeam})
- } else {
- cur.RemovedRequestReview = append(cur.RemovedRequestReview, &RequestReviewTarget{user: cur.Assignee})
- }
- } else {
- if cur.AssigneeTeam != nil {
- cur.AddedRequestReview = append(cur.AddedRequestReview, &RequestReviewTarget{team: cur.AssigneeTeam})
- } else {
- cur.AddedRequestReview = append(cur.AddedRequestReview, &RequestReviewTarget{user: cur.Assignee})
- }
- }
- continue
- }
-
- // Start grouping.
- if cur.RemovedAssignee {
- addedIndex := slices.IndexFunc(prev.AddedRequestReview, func(t issues_model.RequestReviewTarget) bool {
- if cur.AssigneeTeam != nil {
- return cur.AssigneeTeam.ID == t.ID() && t.Type() == "team"
- }
- return cur.Assignee.ID == t.ID() && t.Type() == "user"
- })
-
- // If for this target a AddedRequestReview, then we remove that entry. If it's not found, then add it to the RemovedRequestReview.
- if addedIndex == -1 {
- if cur.AssigneeTeam != nil {
- prev.RemovedRequestReview = append(prev.RemovedRequestReview, &RequestReviewTarget{team: cur.AssigneeTeam})
- } else {
- prev.RemovedRequestReview = append(prev.RemovedRequestReview, &RequestReviewTarget{user: cur.Assignee})
- }
- } else {
- prev.AddedRequestReview = slices.Delete(prev.AddedRequestReview, addedIndex, addedIndex+1)
- }
- } else {
- removedIndex := slices.IndexFunc(prev.RemovedRequestReview, func(t issues_model.RequestReviewTarget) bool {
- if cur.AssigneeTeam != nil {
- return cur.AssigneeTeam.ID == t.ID() && t.Type() == "team"
- }
- return cur.Assignee.ID == t.ID() && t.Type() == "user"
- })
-
- // If for this target a RemovedRequestReview, then we remove that entry. If it's not found, then add it to the AddedRequestReview.
- if removedIndex == -1 {
- if cur.AssigneeTeam != nil {
- prev.AddedRequestReview = append(prev.AddedRequestReview, &RequestReviewTarget{team: cur.AssigneeTeam})
- } else {
- prev.AddedRequestReview = append(prev.AddedRequestReview, &RequestReviewTarget{user: cur.Assignee})
- }
- } else {
- prev.RemovedRequestReview = slices.Delete(prev.RemovedRequestReview, removedIndex, removedIndex+1)
- }
- }
-
- // Propagate creation time.
- prev.CreatedUnix = cur.CreatedUnix
-
- // Remove the current comment since it has been combined to prev comment
- issue.Comments = append(issue.Comments[:i], issue.Comments[i+1:]...)
- i--
- }
-}
-
-// combineLabelComments combine the nearby label comments as one.
-func combineLabelComments(issue *issues_model.Issue) {
- var prev, cur *issues_model.Comment
- for i := 0; i < len(issue.Comments); i++ {
- cur = issue.Comments[i]
- if i > 0 {
- prev = issue.Comments[i-1]
- }
- if i == 0 || cur.Type != issues_model.CommentTypeLabel ||
- (prev != nil && prev.PosterID != cur.PosterID) ||
- (prev != nil && cur.CreatedUnix-prev.CreatedUnix >= 60) {
- if cur.Type == issues_model.CommentTypeLabel && cur.Label != nil {
- if cur.Content != "1" {
- cur.RemovedLabels = append(cur.RemovedLabels, cur.Label)
- } else {
- cur.AddedLabels = append(cur.AddedLabels, cur.Label)
- }
- }
- continue
- }
-
- if cur.Label != nil { // now cur MUST be label comment
- if prev.Type == issues_model.CommentTypeLabel { // we can combine them only prev is a label comment
- if cur.Content != "1" {
- // remove labels from the AddedLabels list if the label that was removed is already
- // in this list, and if it's not in this list, add the label to RemovedLabels
- addedAndRemoved := false
- for i, label := range prev.AddedLabels {
- if cur.Label.ID == label.ID {
- prev.AddedLabels = append(prev.AddedLabels[:i], prev.AddedLabels[i+1:]...)
- addedAndRemoved = true
- break
- }
- }
- if !addedAndRemoved {
- prev.RemovedLabels = append(prev.RemovedLabels, cur.Label)
- }
- } else {
- // remove labels from the RemovedLabels list if the label that was added is already
- // in this list, and if it's not in this list, add the label to AddedLabels
- removedAndAdded := false
- for i, label := range prev.RemovedLabels {
- if cur.Label.ID == label.ID {
- prev.RemovedLabels = append(prev.RemovedLabels[:i], prev.RemovedLabels[i+1:]...)
- removedAndAdded = true
- break
- }
- }
- if !removedAndAdded {
- prev.AddedLabels = append(prev.AddedLabels, cur.Label)
- }
- }
- prev.CreatedUnix = cur.CreatedUnix
- // remove the current comment since it has been combined to prev comment
- issue.Comments = append(issue.Comments[:i], issue.Comments[i+1:]...)
- i--
- } else { // if prev is not a label comment, start a new group
- if cur.Content != "1" {
- cur.RemovedLabels = append(cur.RemovedLabels, cur.Label)
- } else {
- cur.AddedLabels = append(cur.AddedLabels, cur.Label)
- }
- }
- }
- }
-}
-
// get all teams that current user can mention
func handleTeamMentions(ctx *context.Context) {
if ctx.Doer == nil || !ctx.Repo.Owner.IsOrganization() {
diff --git a/routers/web/repo/issue_test.go b/routers/web/repo/issue_test.go
deleted file mode 100644
index d642c14b5f..0000000000
--- a/routers/web/repo/issue_test.go
+++ /dev/null
@@ -1,806 +0,0 @@
-// Copyright 2020 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package repo
-
-import (
- "testing"
-
- issues_model "code.gitea.io/gitea/models/issues"
- org_model "code.gitea.io/gitea/models/organization"
- user_model "code.gitea.io/gitea/models/user"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCombineLabelComments(t *testing.T) {
- kases := []struct {
- name string
- beforeCombined []*issues_model.Comment
- afterCombined []*issues_model.Comment
- }{
- {
- name: "kase 1",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 1,
- Content: "test",
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- CreatedUnix: 0,
- AddedLabels: []*issues_model.Label{},
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 1,
- Content: "test",
- CreatedUnix: 0,
- },
- },
- },
- {
- name: "kase 2",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 70,
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 1,
- Content: "test",
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- CreatedUnix: 0,
- AddedLabels: []*issues_model.Label{
- {
- Name: "kind/bug",
- },
- },
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "",
- CreatedUnix: 70,
- RemovedLabels: []*issues_model.Label{
- {
- Name: "kind/bug",
- },
- },
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 1,
- Content: "test",
- CreatedUnix: 0,
- },
- },
- },
- {
- name: "kase 3",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 2,
- Content: "",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 1,
- Content: "test",
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- CreatedUnix: 0,
- AddedLabels: []*issues_model.Label{
- {
- Name: "kind/bug",
- },
- },
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 2,
- Content: "",
- CreatedUnix: 0,
- RemovedLabels: []*issues_model.Label{
- {
- Name: "kind/bug",
- },
- },
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 1,
- Content: "test",
- CreatedUnix: 0,
- },
- },
- },
- {
- name: "kase 4",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "kind/backport",
- },
- CreatedUnix: 10,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- CreatedUnix: 10,
- AddedLabels: []*issues_model.Label{
- {
- Name: "kind/bug",
- },
- {
- Name: "kind/backport",
- },
- },
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- },
- },
- },
- {
- name: "kase 5",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 2,
- Content: "testtest",
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- AddedLabels: []*issues_model.Label{
- {
- Name: "kind/bug",
- },
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 2,
- Content: "testtest",
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "",
- RemovedLabels: []*issues_model.Label{
- {
- Name: "kind/bug",
- },
- },
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- },
- },
- {
- name: "kase 6",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "reviewed/confirmed",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "kind/feature",
- },
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeLabel,
- PosterID: 1,
- Content: "1",
- Label: &issues_model.Label{
- Name: "kind/bug",
- },
- AddedLabels: []*issues_model.Label{
- {
- Name: "reviewed/confirmed",
- },
- {
- Name: "kind/feature",
- },
- },
- CreatedUnix: 0,
- },
- },
- },
- }
-
- for _, kase := range kases {
- t.Run(kase.name, func(t *testing.T) {
- issue := issues_model.Issue{
- Comments: kase.beforeCombined,
- }
- combineLabelComments(&issue)
- assert.EqualValues(t, kase.afterCombined, issue.Comments)
- })
- }
-}
-
-func TestCombineReviewRequests(t *testing.T) {
- testCases := []struct {
- name string
- beforeCombined []*issues_model.Comment
- afterCombined []*issues_model.Comment
- }{
- {
- name: "case 1",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- RemovedAssignee: true,
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 1,
- Content: "test",
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- CreatedUnix: 0,
- AddedRequestReview: []issues_model.RequestReviewTarget{},
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 1,
- Content: "test",
- CreatedUnix: 0,
- },
- },
- },
- {
- name: "case 2",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- Assignee: &user_model.User{
- ID: 2,
- Name: "Ghost 2",
- },
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- CreatedUnix: 0,
- AddedRequestReview: []issues_model.RequestReviewTarget{
- &RequestReviewTarget{
- user: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- },
- &RequestReviewTarget{
- user: &user_model.User{
- ID: 2,
- Name: "Ghost 2",
- },
- },
- },
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- },
- },
- },
- {
- name: "case 3",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- RemovedAssignee: true,
- AssigneeTeam: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- CreatedUnix: 0,
- AddedRequestReview: []issues_model.RequestReviewTarget{
- &RequestReviewTarget{
- user: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- },
- },
- RemovedRequestReview: []issues_model.RequestReviewTarget{
- &RequestReviewTarget{
- team: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- },
- },
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- },
- },
- },
- {
- name: "case 4",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- RemovedAssignee: true,
- AssigneeTeam: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- AssigneeTeam: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- CreatedUnix: 0,
- AddedRequestReview: []issues_model.RequestReviewTarget{
- &RequestReviewTarget{
- user: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- },
- },
- RemovedRequestReview: []issues_model.RequestReviewTarget{},
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- },
- },
- },
- {
- name: "case 5",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- RemovedAssignee: true,
- AssigneeTeam: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- AssigneeTeam: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- RemovedAssignee: true,
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- CreatedUnix: 0,
- AddedRequestReview: []issues_model.RequestReviewTarget{},
- RemovedRequestReview: []issues_model.RequestReviewTarget{},
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- },
- },
- },
- {
- name: "case 6",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- RemovedAssignee: true,
- AssigneeTeam: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 1,
- Content: "test",
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- AssigneeTeam: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- RemovedAssignee: true,
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- CreatedUnix: 0,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- CreatedUnix: 0,
- RemovedRequestReview: []issues_model.RequestReviewTarget{&RequestReviewTarget{
- team: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- }},
- AddedRequestReview: []issues_model.RequestReviewTarget{&RequestReviewTarget{
- user: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- }},
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- },
- {
- Type: issues_model.CommentTypeComment,
- PosterID: 1,
- Content: "test",
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- CreatedUnix: 0,
- AddedRequestReview: []issues_model.RequestReviewTarget{&RequestReviewTarget{
- team: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- }},
- RemovedRequestReview: []issues_model.RequestReviewTarget{&RequestReviewTarget{
- user: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- }},
- AssigneeTeam: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- },
- },
- },
- {
- name: "case 7",
- beforeCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- CreatedUnix: 0,
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- AssigneeTeam: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- CreatedUnix: 61,
- },
- },
- afterCombined: []*issues_model.Comment{
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- CreatedUnix: 0,
- AddedRequestReview: []issues_model.RequestReviewTarget{&RequestReviewTarget{
- user: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- }},
- Assignee: &user_model.User{
- ID: 1,
- Name: "Ghost",
- },
- },
- {
- Type: issues_model.CommentTypeReviewRequest,
- PosterID: 1,
- CreatedUnix: 0,
- RemovedRequestReview: []issues_model.RequestReviewTarget{&RequestReviewTarget{
- team: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- }},
- AssigneeTeam: &org_model.Team{
- ID: 1,
- Name: "Team 1",
- },
- },
- },
- },
- }
-
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- issue := issues_model.Issue{
- Comments: testCase.beforeCombined,
- }
- combineRequestReviewComments(&issue)
- assert.EqualValues(t, testCase.afterCombined[0], issue.Comments[0])
- })
- }
-}
diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go
index e8a3c48d7f..eb8dd83d9c 100644
--- a/routers/web/repo/pull_review.go
+++ b/routers/web/repo/pull_review.go
@@ -82,6 +82,24 @@ func CreateCodeComment(ctx *context.Context) {
attachments = form.Files
}
+ // If the reply is made to a comment that is part of a pending review, then
+ // this comment also should be seen as part of that pending review. Consider
+ // it to be a pending review by default, except when `single_review` was
+ // passed.
+ pendingReview := !form.SingleReview
+ if form.Reply > 0 {
+ r, err := issues_model.GetReviewByID(ctx, form.Reply)
+ if err != nil {
+ ctx.ServerError("GetReviewByID", err)
+ return
+ }
+ if r.IssueID != issue.ID {
+ ctx.NotFound("Review does not belong to pull request", nil)
+ return
+ }
+ pendingReview = r.Type == issues_model.ReviewTypePending
+ }
+
comment, err := pull_service.CreateCodeComment(ctx,
ctx.Doer,
ctx.Repo.GitRepo,
@@ -89,7 +107,7 @@ func CreateCodeComment(ctx *context.Context) {
signedLine,
form.Content,
form.TreePath,
- !form.SingleReview,
+ pendingReview,
form.Reply,
form.LatestCommitID,
attachments,
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index 1c4fb39546..2e8ca61bf5 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -474,7 +474,7 @@ func Download(ctx *context.Context) {
uri := ctx.Params("*")
ext, tp, err := archiver_service.ParseFileName(uri)
if err != nil {
- ctx.ServerError("ParseFileName", err)
+ ctx.NotFound("ParseFileName", err)
return
}
aReq, err := archiver_service.NewRequest(ctx, ctx.Repo.Repository.ID, ctx.Repo.GitRepo, strings.TrimSuffix(uri, ext), tp)
@@ -554,7 +554,7 @@ func InitiateDownload(ctx *context.Context) {
uri := ctx.Params("*")
ext, tp, err := archiver_service.ParseFileName(uri)
if err != nil {
- ctx.ServerError("ParseFileName", err)
+ ctx.NotFound("ParseFileName", err)
return
}
aReq, err := archiver_service.NewRequest(ctx, ctx.Repo.Repository.ID, ctx.Repo.GitRepo, strings.TrimSuffix(uri, ext), tp)
diff --git a/routers/web/shared/storage_overview.go b/routers/web/shared/storage_overview.go
new file mode 100644
index 0000000000..3bebdfb688
--- /dev/null
+++ b/routers/web/shared/storage_overview.go
@@ -0,0 +1,90 @@
+// Copyright 2024 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package shared
+
+import (
+ "html/template"
+ "net/http"
+
+ quota_model "code.gitea.io/gitea/models/quota"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/services/context"
+)
+
+// StorageOverview render a size overview of the user, as well as relevant
+// quota limits of the instance.
+func StorageOverview(ctx *context.Context, userID int64, tpl base.TplName) {
+ if !setting.Quota.Enabled {
+ ctx.NotFound("MustEnableQuota", nil)
+ }
+ ctx.Data["Title"] = ctx.Tr("settings.storage_overview")
+ ctx.Data["PageIsStorageOverview"] = true
+
+ ctx.Data["Color"] = func(subject quota_model.LimitSubject) float64 {
+ return float64(subject) * 137.50776405003785 // Golden angle.
+ }
+
+ ctx.Data["PrettySubject"] = func(subject quota_model.LimitSubject) template.HTML {
+ switch subject {
+ case quota_model.LimitSubjectSizeAll:
+ return ctx.Locale.Tr("settings.quota.sizes.all")
+ case quota_model.LimitSubjectSizeReposAll:
+ return ctx.Locale.Tr("settings.quota.sizes.repos.all")
+ case quota_model.LimitSubjectSizeReposPublic:
+ return ctx.Locale.Tr("settings.quota.sizes.repos.public")
+ case quota_model.LimitSubjectSizeReposPrivate:
+ return ctx.Locale.Tr("settings.quota.sizes.repos.private")
+ case quota_model.LimitSubjectSizeGitAll:
+ return ctx.Locale.Tr("settings.quota.sizes.git.all")
+ case quota_model.LimitSubjectSizeGitLFS:
+ return ctx.Locale.Tr("settings.quota.sizes.git.lfs")
+ case quota_model.LimitSubjectSizeAssetsAll:
+ return ctx.Locale.Tr("settings.quota.sizes.assets.all")
+ case quota_model.LimitSubjectSizeAssetsAttachmentsAll:
+ return ctx.Locale.Tr("settings.quota.sizes.assets.attachments.all")
+ case quota_model.LimitSubjectSizeAssetsAttachmentsIssues:
+ return ctx.Locale.Tr("settings.quota.sizes.assets.attachments.issues")
+ case quota_model.LimitSubjectSizeAssetsAttachmentsReleases:
+ return ctx.Locale.Tr("settings.quota.sizes.assets.attachments.releases")
+ case quota_model.LimitSubjectSizeAssetsArtifacts:
+ return ctx.Locale.Tr("settings.quota.sizes.assets.artifacts")
+ case quota_model.LimitSubjectSizeAssetsPackagesAll:
+ return ctx.Locale.Tr("settings.quota.sizes.assets.packages.all")
+ case quota_model.LimitSubjectSizeWiki:
+ return ctx.Locale.Tr("settings.quota.sizes.wiki")
+ default:
+ panic("unrecognized subject: " + subject.String())
+ }
+ }
+
+ sizeUsed, err := quota_model.GetUsedForUser(ctx, userID)
+ if err != nil {
+ ctx.ServerError("GetUsedForUser", err)
+ return
+ }
+ ctx.Data["SizeUsed"] = sizeUsed
+
+ quotaGroups, err := quota_model.GetGroupsForUser(ctx, userID)
+ if err != nil {
+ ctx.ServerError("GetGroupsForUser", err)
+ return
+ }
+ if len(quotaGroups) == 0 {
+ quotaGroups = append(quotaGroups, "a_model.Group{
+ Name: "Global quota",
+ Rules: []quota_model.Rule{
+ {
+ Name: "Default",
+ Limit: setting.Quota.Default.Total,
+ Subjects: quota_model.LimitSubjects{quota_model.LimitSubjectSizeAll},
+ },
+ },
+ },
+ )
+ }
+ ctx.Data["QuotaGroups"] = quotaGroups
+
+ ctx.HTML(http.StatusOK, tpl)
+}
diff --git a/routers/web/user/setting/applications.go b/routers/web/user/setting/applications.go
index 24ebf9b922..4dfd859a44 100644
--- a/routers/web/user/setting/applications.go
+++ b/routers/web/user/setting/applications.go
@@ -10,6 +10,7 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
@@ -87,6 +88,23 @@ func DeleteApplication(ctx *context.Context) {
ctx.JSONRedirect(setting.AppSubURL + "/user/settings/applications")
}
+// RegenerateApplication response for regenerating user access token
+func RegenerateApplication(ctx *context.Context) {
+ if t, err := auth_model.RegenerateAccessTokenByID(ctx, ctx.FormInt64("id"), ctx.Doer.ID); err != nil {
+ if auth_model.IsErrAccessTokenNotExist(err) {
+ ctx.Flash.Error(ctx.Tr("error.not_found"))
+ } else {
+ ctx.Flash.Error(ctx.Tr("error.server_internal"))
+ log.Error("DeleteAccessTokenByID", err)
+ }
+ } else {
+ ctx.Flash.Success(ctx.Tr("settings.regenerate_token_success"))
+ ctx.Flash.Info(t.Token)
+ }
+
+ ctx.JSONRedirect(setting.AppSubURL + "/user/settings/applications")
+}
+
func loadApplicationsData(ctx *context.Context) {
ctx.Data["AccessTokenScopePublicOnly"] = auth_model.AccessTokenScopePublicOnly
tokens, err := db.Find[auth_model.AccessToken](ctx, auth_model.ListAccessTokensOptions{UserID: ctx.Doer.ID})
diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go
index 33b2919d69..271621872f 100644
--- a/routers/web/user/setting/profile.go
+++ b/routers/web/user/setting/profile.go
@@ -12,7 +12,6 @@ import (
"net/http"
"os"
"path/filepath"
- "slices"
"strings"
"time"
@@ -42,8 +41,7 @@ const (
tplSettingsRepositories base.TplName = "user/settings/repos"
)
-// must be kept in sync with `web_src/js/features/user-settings.js`
-var recognisedPronouns = []string{"", "he/him", "she/her", "they/them", "it/its", "any pronouns"}
+var commonPronouns = []string{"he/him", "she/her", "they/them", "it/its", "any pronouns"}
// Profile render user's profile page
func Profile(ctx *context.Context) {
@@ -51,8 +49,8 @@ func Profile(ctx *context.Context) {
ctx.Data["PageIsSettingsProfile"] = true
ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
ctx.Data["DisableGravatar"] = setting.Config().Picture.DisableGravatar.Value(ctx)
- ctx.Data["PronounsAreCustom"] = !slices.Contains(recognisedPronouns, ctx.Doer.Pronouns)
ctx.Data["CooldownPeriod"] = setting.Service.UsernameCooldownPeriod
+ ctx.Data["CommonPronouns"] = commonPronouns
ctx.HTML(http.StatusOK, tplSettingsProfile)
}
@@ -63,8 +61,8 @@ func ProfilePost(ctx *context.Context) {
ctx.Data["PageIsSettingsProfile"] = true
ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
ctx.Data["DisableGravatar"] = setting.Config().Picture.DisableGravatar.Value(ctx)
- ctx.Data["PronounsAreCustom"] = !slices.Contains(recognisedPronouns, ctx.Doer.Pronouns)
ctx.Data["CooldownPeriod"] = setting.Service.UsernameCooldownPeriod
+ ctx.Data["CommonPronouns"] = commonPronouns
if ctx.HasError() {
ctx.HTML(http.StatusOK, tplSettingsProfile)
@@ -331,6 +329,14 @@ func Repos(ctx *context.Context) {
func Appearance(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings.appearance")
ctx.Data["PageIsSettingsAppearance"] = true
+ ctx.Data["AllThemes"] = setting.UI.Themes
+ ctx.Data["ThemeName"] = func(themeName string) string {
+ fullThemeName := "themes.names." + themeName
+ if ctx.Locale.HasKey(fullThemeName) {
+ return ctx.Locale.TrString(fullThemeName)
+ }
+ return themeName
+ }
var hiddenCommentTypes *big.Int
val, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes)
diff --git a/routers/web/user/setting/storage_overview.go b/routers/web/user/setting/storage_overview.go
new file mode 100644
index 0000000000..8a0c773077
--- /dev/null
+++ b/routers/web/user/setting/storage_overview.go
@@ -0,0 +1,20 @@
+// Copyright 2024 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package setting
+
+import (
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/routers/web/shared"
+ "code.gitea.io/gitea/services/context"
+)
+
+const (
+ tplSettingsStorageOverview base.TplName = "user/settings/storage_overview"
+)
+
+// StorageOverview render a size overview of the user, as well as relevant
+// quota limits of the instance.
+func StorageOverview(ctx *context.Context) {
+ shared.StorageOverview(ctx, ctx.Doer.ID, tplSettingsStorageOverview)
+}
diff --git a/routers/web/web.go b/routers/web/web.go
index 93ca5ba828..62eee92bbd 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -8,8 +8,6 @@ import (
"net/http"
"strings"
- auth_model "code.gitea.io/gitea/models/auth"
- "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
quota_model "code.gitea.io/gitea/models/quota"
"code.gitea.io/gitea/models/unit"
@@ -111,10 +109,6 @@ func buildAuthGroup() *auth_service.Group {
}
group.Add(&auth_service.Session{})
- if setting.IsWindows && auth_model.IsSSPIEnabled(db.DefaultContext) {
- group.Add(&auth_service.SSPI{}) // it MUST be the last, see the comment of SSPI
- }
-
return group
}
@@ -593,6 +587,7 @@ func registerRoutes(m *web.Route) {
m.Combo("").Get(user_setting.Applications).
Post(web.Bind(forms.NewAccessTokenForm{}), user_setting.ApplicationsPost)
m.Post("/delete", user_setting.DeleteApplication)
+ m.Post("/regenerate", user_setting.RegenerateApplication)
})
m.Combo("/keys").Get(user_setting.Keys).
@@ -645,7 +640,8 @@ func registerRoutes(m *web.Route) {
m.Get("", user_setting.BlockedUsers)
m.Post("/unblock", user_setting.UnblockUser)
})
- }, reqSignIn, ctxDataSet("PageIsUserSettings", true, "AllThemes", setting.UI.Themes, "EnablePackages", setting.Packages.Enabled))
+ m.Get("/storage_overview", user_setting.StorageOverview)
+ }, reqSignIn, ctxDataSet("PageIsUserSettings", true, "EnablePackages", setting.Packages.Enabled, "EnableQuota", setting.Quota.Enabled))
m.Group("/user", func() {
m.Get("/activate", auth.Activate)
@@ -931,6 +927,7 @@ func registerRoutes(m *web.Route) {
m.Post("/block", org_setting.BlockedUsersBlock)
m.Post("/unblock", org_setting.BlockedUsersUnblock)
})
+ m.Get("/storage_overview", org_setting.StorageOverview)
m.Group("/packages", func() {
m.Get("", org.Packages)
@@ -950,7 +947,7 @@ func registerRoutes(m *web.Route) {
m.Post("/rebuild", org.RebuildCargoIndex)
})
}, packagesEnabled)
- }, ctxDataSet("EnableOAuth2", setting.OAuth2.Enabled, "EnablePackages", setting.Packages.Enabled, "PageIsOrgSettings", true))
+ }, ctxDataSet("EnableOAuth2", setting.OAuth2.Enabled, "EnablePackages", setting.Packages.Enabled, "EnableQuota", setting.Quota.Enabled, "PageIsOrgSettings", true))
}, context.OrgAssignment(true, true))
}, reqSignIn)
// ***** END: Organization *****
diff --git a/services/actions/context_test.go b/services/actions/context_test.go
index a80d2d84e3..4cd8825870 100644
--- a/services/actions/context_test.go
+++ b/services/actions/context_test.go
@@ -4,7 +4,6 @@
package actions
import (
- "context"
"testing"
actions_model "code.gitea.io/gitea/models/actions"
@@ -20,7 +19,7 @@ func TestFindTaskNeeds(t *testing.T) {
task := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 51})
job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: task.JobID})
- ret, err := FindTaskNeeds(context.Background(), job)
+ ret, err := FindTaskNeeds(t.Context(), job)
require.NoError(t, err)
assert.Len(t, ret, 1)
assert.Contains(t, ret, "job1")
diff --git a/services/actions/task.go b/services/actions/task.go
new file mode 100644
index 0000000000..bc54ade347
--- /dev/null
+++ b/services/actions/task.go
@@ -0,0 +1,107 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+ "context"
+ "fmt"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ "code.gitea.io/gitea/models/db"
+ secret_model "code.gitea.io/gitea/models/secret"
+
+ runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
+ "google.golang.org/protobuf/types/known/structpb"
+)
+
+func PickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv1.Task, bool, error) {
+ var (
+ task *runnerv1.Task
+ job *actions_model.ActionRunJob
+ )
+
+ if err := db.WithTx(ctx, func(ctx context.Context) error {
+ t, ok, err := actions_model.CreateTaskForRunner(ctx, runner)
+ if err != nil {
+ return fmt.Errorf("CreateTaskForRunner: %w", err)
+ }
+ if !ok {
+ return nil
+ }
+
+ if err := t.LoadAttributes(ctx); err != nil {
+ return fmt.Errorf("task LoadAttributes: %w", err)
+ }
+ job = t.Job
+
+ secrets, err := secret_model.GetSecretsOfTask(ctx, t)
+ if err != nil {
+ return fmt.Errorf("GetSecretsOfTask: %w", err)
+ }
+
+ vars, err := actions_model.GetVariablesOfRun(ctx, t.Job.Run)
+ if err != nil {
+ return fmt.Errorf("GetVariablesOfRun: %w", err)
+ }
+
+ needs, err := findTaskNeeds(ctx, job)
+ if err != nil {
+ return fmt.Errorf("findTaskNeeds: %w", err)
+ }
+
+ taskContext, err := generateTaskContext(t)
+ if err != nil {
+ return fmt.Errorf("generateTaskContext: %w", err)
+ }
+
+ task = &runnerv1.Task{
+ Id: t.ID,
+ WorkflowPayload: t.Job.WorkflowPayload,
+ Context: taskContext,
+ Secrets: secrets,
+ Vars: vars,
+ Needs: needs,
+ }
+
+ return nil
+ }); err != nil {
+ return nil, false, err
+ }
+
+ if task == nil {
+ return nil, false, nil
+ }
+
+ CreateCommitStatus(ctx, job)
+
+ return task, true, nil
+}
+
+func generateTaskContext(t *actions_model.ActionTask) (*structpb.Struct, error) {
+ giteaRuntimeToken, err := CreateAuthorizationToken(t.ID, t.Job.RunID, t.JobID)
+ if err != nil {
+ return nil, err
+ }
+
+ gitCtx := GenerateGiteaContext(t.Job.Run, t.Job)
+ gitCtx["token"] = t.Token
+ gitCtx["gitea_runtime_token"] = giteaRuntimeToken
+
+ return structpb.NewStruct(gitCtx)
+}
+
+func findTaskNeeds(ctx context.Context, taskJob *actions_model.ActionRunJob) (map[string]*runnerv1.TaskNeed, error) {
+ taskNeeds, err := FindTaskNeeds(ctx, taskJob)
+ if err != nil {
+ return nil, err
+ }
+ ret := make(map[string]*runnerv1.TaskNeed, len(taskNeeds))
+ for jobID, taskNeed := range taskNeeds {
+ ret[jobID] = &runnerv1.TaskNeed{
+ Outputs: taskNeed.Outputs,
+ Result: runnerv1.Result(taskNeed.Result),
+ }
+ }
+ return ret, nil
+}
diff --git a/services/auth/oauth2_test.go b/services/auth/oauth2_test.go
index c9b4ed06cc..90e2fe4517 100644
--- a/services/auth/oauth2_test.go
+++ b/services/auth/oauth2_test.go
@@ -4,7 +4,6 @@
package auth
import (
- "context"
"testing"
"code.gitea.io/gitea/models/unittest"
@@ -27,7 +26,7 @@ func TestUserIDFromToken(t *testing.T) {
ds := make(middleware.ContextData)
o := OAuth2{}
- uid := o.userIDFromToken(context.Background(), token, ds)
+ uid := o.userIDFromToken(t.Context(), token, ds)
assert.Equal(t, int64(user_model.ActionsUserID), uid)
assert.Equal(t, true, ds["IsActionsToken"])
assert.Equal(t, ds["ActionsTaskID"], int64(RunningTaskID))
@@ -48,7 +47,7 @@ func TestCheckTaskIsRunning(t *testing.T) {
for name := range cases {
c := cases[name]
t.Run(name, func(t *testing.T) {
- actual := CheckTaskIsRunning(context.Background(), c.TaskID)
+ actual := CheckTaskIsRunning(t.Context(), c.TaskID)
assert.Equal(t, c.Expected, actual)
})
}
diff --git a/services/auth/signin.go b/services/auth/signin.go
index e116a088e0..7c69da8f94 100644
--- a/services/auth/signin.go
+++ b/services/auth/signin.go
@@ -18,7 +18,6 @@ import (
_ "code.gitea.io/gitea/services/auth/source/db" // register the sources (and below)
_ "code.gitea.io/gitea/services/auth/source/ldap" // register the ldap source
_ "code.gitea.io/gitea/services/auth/source/pam" // register the pam source
- _ "code.gitea.io/gitea/services/auth/source/sspi" // register the sspi source
)
// UserSignIn validates user name and password.
diff --git a/services/auth/source/sspi/assert_interface_test.go b/services/auth/source/sspi/assert_interface_test.go
deleted file mode 100644
index 03d836dd6f..0000000000
--- a/services/auth/source/sspi/assert_interface_test.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2021 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package sspi_test
-
-import (
- "code.gitea.io/gitea/models/auth"
- "code.gitea.io/gitea/services/auth/source/sspi"
-)
-
-// This test file exists to assert that our Source exposes the interfaces that we expect
-// It tightly binds the interfaces and implementation without breaking go import cycles
-
-type sourceInterface interface {
- auth.Config
-}
-
-var _ (sourceInterface) = &sspi.Source{}
diff --git a/services/auth/source/sspi/source.go b/services/auth/source/sspi/source.go
deleted file mode 100644
index bdd6ef451c..0000000000
--- a/services/auth/source/sspi/source.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2021 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package sspi
-
-import (
- "code.gitea.io/gitea/models/auth"
- "code.gitea.io/gitea/modules/json"
-)
-
-// _________ ___________________.___
-// / _____// _____/\______ \ |
-// \_____ \ \_____ \ | ___/ |
-// / \/ \ | | | |
-// /_______ /_______ / |____| |___|
-// \/ \/
-
-// Source holds configuration for SSPI single sign-on.
-type Source struct {
- AutoCreateUsers bool
- AutoActivateUsers bool
- StripDomainNames bool
- SeparatorReplacement string
- DefaultLanguage string
-}
-
-// FromDB fills up an SSPIConfig from serialized format.
-func (cfg *Source) FromDB(bs []byte) error {
- return json.UnmarshalHandleDoubleEncode(bs, &cfg)
-}
-
-// ToDB exports an SSPIConfig to a serialized format.
-func (cfg *Source) ToDB() ([]byte, error) {
- return json.Marshal(cfg)
-}
-
-func init() {
- auth.RegisterTypeConfig(auth.SSPI, &Source{})
-}
diff --git a/services/auth/sspi.go b/services/auth/sspi.go
deleted file mode 100644
index 64a127e97a..0000000000
--- a/services/auth/sspi.go
+++ /dev/null
@@ -1,223 +0,0 @@
-// Copyright 2019 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package auth
-
-import (
- "context"
- "errors"
- "net/http"
- "strings"
- "sync"
-
- "code.gitea.io/gitea/models/auth"
- "code.gitea.io/gitea/models/db"
- 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/optional"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/web/middleware"
- "code.gitea.io/gitea/services/auth/source/sspi"
- gitea_context "code.gitea.io/gitea/services/context"
-
- gouuid "github.com/google/uuid"
-)
-
-const (
- tplSignIn base.TplName = "user/auth/signin"
-)
-
-type SSPIAuth interface {
- AppendAuthenticateHeader(w http.ResponseWriter, data string)
- Authenticate(r *http.Request, w http.ResponseWriter) (userInfo *SSPIUserInfo, outToken string, err error)
-}
-
-var (
- sspiAuth SSPIAuth // a global instance of the websspi authenticator to avoid acquiring the server credential handle on every request
- sspiAuthOnce sync.Once
- sspiAuthErrInit error
-
- // Ensure the struct implements the interface.
- _ Method = &SSPI{}
-)
-
-// SSPI implements the SingleSignOn interface and authenticates requests
-// via the built-in SSPI module in Windows for SPNEGO authentication.
-// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation
-// fails (or if negotiation should continue), which would prevent other authentication methods
-// to execute at all.
-type SSPI struct{}
-
-// Name represents the name of auth method
-func (s *SSPI) Name() string {
- return "sspi"
-}
-
-// Verify uses SSPI (Windows implementation of SPNEGO) to authenticate the request.
-// If authentication is successful, returns the corresponding user object.
-// If negotiation should continue or authentication fails, immediately returns a 401 HTTP
-// response code, as required by the SPNEGO protocol.
-func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) {
- sspiAuthOnce.Do(func() { sspiAuthErrInit = sspiAuthInit() })
- if sspiAuthErrInit != nil {
- return nil, sspiAuthErrInit
- }
- if !s.shouldAuthenticate(req) {
- return nil, nil
- }
-
- cfg, err := s.getConfig(req.Context())
- if err != nil {
- log.Error("could not get SSPI config: %v", err)
- return nil, err
- }
-
- log.Trace("SSPI Authorization: Attempting to authenticate")
- userInfo, outToken, err := sspiAuth.Authenticate(req, w)
- if err != nil {
- log.Warn("Authentication failed with error: %v\n", err)
- sspiAuth.AppendAuthenticateHeader(w, outToken)
-
- // Include the user login page in the 401 response to allow the user
- // to login with another authentication method if SSPI authentication
- // fails
- store.GetData()["Flash"] = map[string]string{
- "ErrorMsg": err.Error(),
- }
- store.GetData()["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn
- store.GetData()["EnableSSPI"] = true
- // in this case, the Verify function is called in Gitea's web context
- // FIXME: it doesn't look good to render the page here, why not redirect?
- gitea_context.GetWebContext(req).HTML(http.StatusUnauthorized, tplSignIn)
- return nil, err
- }
- if outToken != "" {
- sspiAuth.AppendAuthenticateHeader(w, outToken)
- }
-
- username := sanitizeUsername(userInfo.Username, cfg)
- if len(username) == 0 {
- return nil, nil
- }
- log.Info("Authenticated as %s\n", username)
-
- user, err := user_model.GetUserByName(req.Context(), username)
- if err != nil {
- if !user_model.IsErrUserNotExist(err) {
- log.Error("GetUserByName: %v", err)
- return nil, err
- }
- if !cfg.AutoCreateUsers {
- log.Error("User '%s' not found", username)
- return nil, nil
- }
- user, err = s.newUser(req.Context(), username, cfg)
- if err != nil {
- log.Error("CreateUser: %v", err)
- return nil, err
- }
- }
-
- // Make sure requests to API paths and PWA resources do not create a new session
- if !middleware.IsAPIPath(req) && !isAttachmentDownload(req) {
- handleSignIn(w, req, sess, user)
- }
-
- log.Trace("SSPI Authorization: Logged in user %-v", user)
- return user, nil
-}
-
-// getConfig retrieves the SSPI configuration from login sources
-func (s *SSPI) getConfig(ctx context.Context) (*sspi.Source, error) {
- sources, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{
- IsActive: optional.Some(true),
- LoginType: auth.SSPI,
- })
- if err != nil {
- return nil, err
- }
- if len(sources) == 0 {
- return nil, errors.New("no active login sources of type SSPI found")
- }
- if len(sources) > 1 {
- return nil, errors.New("more than one active login source of type SSPI found")
- }
- return sources[0].Cfg.(*sspi.Source), nil
-}
-
-func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) {
- shouldAuth = false
- path := strings.TrimSuffix(req.URL.Path, "/")
- if path == "/user/login" {
- if req.FormValue("user_name") != "" && req.FormValue("password") != "" {
- shouldAuth = false
- } else if req.FormValue("auth_with_sspi") == "1" {
- shouldAuth = true
- }
- } else if middleware.IsAPIPath(req) || isAttachmentDownload(req) {
- shouldAuth = true
- }
- return shouldAuth
-}
-
-// newUser creates a new user object for the purpose of automatic registration
-// and populates its name and email with the information present in request headers.
-func (s *SSPI) newUser(ctx context.Context, username string, cfg *sspi.Source) (*user_model.User, error) {
- email := gouuid.New().String() + "@localhost.localdomain"
- user := &user_model.User{
- Name: username,
- Email: email,
- Language: cfg.DefaultLanguage,
- }
- emailNotificationPreference := user_model.EmailNotificationsDisabled
- overwriteDefault := &user_model.CreateUserOverwriteOptions{
- IsActive: optional.Some(cfg.AutoActivateUsers),
- KeepEmailPrivate: optional.Some(true),
- EmailNotificationsPreference: &emailNotificationPreference,
- }
- if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil {
- return nil, err
- }
-
- return user, nil
-}
-
-// stripDomainNames removes NETBIOS domain name and separator from down-level logon names
-// (eg. "DOMAIN\user" becomes "user"), and removes the UPN suffix (domain name) and separator
-// from UPNs (eg. "user@domain.local" becomes "user")
-func stripDomainNames(username string) string {
- if strings.Contains(username, "\\") {
- parts := strings.SplitN(username, "\\", 2)
- if len(parts) > 1 {
- username = parts[1]
- }
- } else if strings.Contains(username, "@") {
- parts := strings.Split(username, "@")
- if len(parts) > 1 {
- username = parts[0]
- }
- }
- return username
-}
-
-func replaceSeparators(username string, cfg *sspi.Source) string {
- newSep := cfg.SeparatorReplacement
- username = strings.ReplaceAll(username, "\\", newSep)
- username = strings.ReplaceAll(username, "/", newSep)
- username = strings.ReplaceAll(username, "@", newSep)
- return username
-}
-
-func sanitizeUsername(username string, cfg *sspi.Source) string {
- if len(username) == 0 {
- return ""
- }
- if cfg.StripDomainNames {
- username = stripDomainNames(username)
- }
- // Replace separators even if we have already stripped the domain name part,
- // as the username can contain several separators: eg. "MICROSOFT\useremail@live.com"
- username = replaceSeparators(username, cfg)
- return username
-}
diff --git a/services/auth/sspiauth_posix.go b/services/auth/sspiauth_posix.go
deleted file mode 100644
index 49b0ed4a52..0000000000
--- a/services/auth/sspiauth_posix.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-//go:build !windows
-
-package auth
-
-import (
- "errors"
- "net/http"
-)
-
-type SSPIUserInfo struct {
- Username string // Name of user, usually in the form DOMAIN\User
- Groups []string // The global groups the user is a member of
-}
-
-type sspiAuthMock struct{}
-
-func (s sspiAuthMock) AppendAuthenticateHeader(w http.ResponseWriter, data string) {
-}
-
-func (s sspiAuthMock) Authenticate(r *http.Request, w http.ResponseWriter) (userInfo *SSPIUserInfo, outToken string, err error) {
- return nil, "", errors.New("not implemented")
-}
-
-func sspiAuthInit() error {
- sspiAuth = &sspiAuthMock{} // TODO: we can mock the SSPI auth in tests
- return nil
-}
diff --git a/services/cron/tasks_basic.go b/services/cron/tasks_basic.go
index 2a213ae515..23eb0dd291 100644
--- a/services/cron/tasks_basic.go
+++ b/services/cron/tasks_basic.go
@@ -54,7 +54,7 @@ func registerRepoHealthCheck() {
RunAtStart: false,
Schedule: "@midnight",
},
- Timeout: 60 * time.Second,
+ Timeout: time.Duration(setting.Git.Timeout.Default) * time.Second,
Args: []string{},
}, func(ctx context.Context, _ *user_model.User, config Config) error {
rhcConfig := config.(*RepoHealthCheckConfig)
diff --git a/services/f3/driver/repository.go b/services/f3/driver/repository.go
index da968b4c47..21f826e551 100644
--- a/services/f3/driver/repository.go
+++ b/services/f3/driver/repository.go
@@ -71,7 +71,7 @@ func (o *repository) upsert(ctx context.Context) generic.NodeID {
return generic.NewNodeID(o.f.Name)
}
-func (o *repository) SetFetchFunc(fetchFunc func(ctx context.Context, destination string)) {
+func (o *repository) SetFetchFunc(fetchFunc func(ctx context.Context, destination string, internalRefs []string)) {
o.f.FetchFunc = fetchFunc
}
@@ -92,6 +92,10 @@ func (o *repository) GetRepositoryPushURL() string {
return o.getURL()
}
+func (o *repository) GetRepositoryInternalRefs() []string {
+ return []string{}
+}
+
func newRepository(_ context.Context) generic.NodeDriverInterface {
r := &repository{
f: &f3.Repository{},
diff --git a/services/forms/auth_form.go b/services/forms/auth_form.go
index 39aae51756..21443ff6a5 100644
--- a/services/forms/auth_form.go
+++ b/services/forms/auth_form.go
@@ -77,11 +77,6 @@ type AuthenticationForm struct {
Oauth2GroupTeamMapRemoval bool
Oauth2AttributeSSHPublicKey string
SkipLocalTwoFA bool
- SSPIAutoCreateUsers bool
- SSPIAutoActivateUsers bool
- SSPIStripDomainNames bool
- SSPISeparatorReplacement string `binding:"AlphaDashDot;MaxSize(5)"`
- SSPIDefaultLanguage string
GroupTeamMap string `binding:"ValidGroupTeamMap"`
GroupTeamMapRemoval bool
}
diff --git a/services/mailer/incoming/incoming.go b/services/mailer/incoming/incoming.go
index 249dac66cd..1b1be4c656 100644
--- a/services/mailer/incoming/incoming.go
+++ b/services/mailer/incoming/incoming.go
@@ -7,8 +7,10 @@ import (
"context"
"crypto/tls"
"fmt"
+ "mime"
net_mail "net/mail"
"regexp"
+ "slices"
"strings"
"time"
@@ -297,6 +299,10 @@ func isAutomaticReply(env *enmime.Envelope) bool {
if autoReply == "yes" {
return true
}
+ precedence := env.GetHeader("Precedence")
+ if precedence == "auto_reply" {
+ return true
+ }
autoRespond := env.GetHeader("X-Autorespond")
return autoRespond != ""
}
@@ -370,25 +376,56 @@ type Attachment struct {
// getContentFromMailReader grabs the plain content and the attachments from the mail.
// A potential reply/signature gets stripped from the content.
func getContentFromMailReader(env *enmime.Envelope) *MailContent {
+ // get attachments
attachments := make([]*Attachment, 0, len(env.Attachments))
for _, attachment := range env.Attachments {
attachments = append(attachments, &Attachment{
- Name: attachment.FileName,
+ Name: constructFilename(attachment),
Content: attachment.Content,
})
}
+ // get inlines
inlineAttachments := make([]*Attachment, 0, len(env.Inlines))
for _, inline := range env.Inlines {
if inline.FileName != "" && inline.ContentType != "text/plain" {
inlineAttachments = append(inlineAttachments, &Attachment{
- Name: inline.FileName,
+ Name: constructFilename(inline),
Content: inline.Content,
})
}
}
+ // get other parts (mostly multipart/related files, these are for example embedded images in an html mail)
+ otherParts := make([]*Attachment, 0, len(env.Inlines))
+ for _, otherPart := range env.OtherParts {
+ otherParts = append(otherParts, &Attachment{
+ Name: constructFilename(otherPart),
+ Content: otherPart.Content,
+ })
+ }
return &MailContent{
Content: reply.FromText(env.Text),
- Attachments: append(attachments, inlineAttachments...),
+ Attachments: slices.Concat(attachments, inlineAttachments, otherParts),
}
}
+
+// constructFilename interprets the mime part as an (inline) attachment and returns its filename
+// If no filename is given it guesses a sensible filename for it based on the filetype.
+func constructFilename(part *enmime.Part) string {
+ if strings.TrimSpace(part.FileName) != "" {
+ return part.FileName
+ }
+
+ filenameWOExtension := "unnamed_file"
+ if strings.TrimSpace(part.ContentID) != "" {
+ filenameWOExtension = part.ContentID
+ }
+
+ fileExtension := ".unknown"
+ mimeExtensions, err := mime.ExtensionsByType(part.ContentType)
+ if err == nil && len(mimeExtensions) != 0 {
+ // just use the first one we find
+ fileExtension = mimeExtensions[0]
+ }
+ return filenameWOExtension + fileExtension
+}
diff --git a/services/mailer/incoming/incoming_test.go b/services/mailer/incoming/incoming_test.go
index 6101bc7e32..2ffaac57ae 100644
--- a/services/mailer/incoming/incoming_test.go
+++ b/services/mailer/incoming/incoming_test.go
@@ -4,6 +4,7 @@
package incoming
import (
+ "encoding/base64"
"strings"
"testing"
@@ -65,6 +66,12 @@ func TestIsAutomaticReply(t *testing.T) {
},
Expected: true,
},
+ {
+ Headers: map[string]string{
+ "Precedence": "auto_reply",
+ },
+ Expected: true,
+ },
}
for _, c := range cases {
@@ -188,4 +195,191 @@ func TestGetContentFromMailReader(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, "mail content without signature", content.Content)
assert.Empty(t, content.Attachments)
+
+ // Some versions of Outlook send inline attachments like this, inside a multipart/related part.
+ // the attached image is from: https://openmoji.org/library/emoji-1F684
+ mailString = "Content-Type: multipart/related; boundary=\"=_related boundary=\"\r\n" +
+ "\r\n" +
+ "This text is for clients unable to decode multipart/related with multipart/alternative.\r\n" +
+ "\r\n" +
+ "--=_related boundary=\r\n" +
+ "Content-Type: multipart/alternative; boundary=\"=_alternative boundary=\"\r\n" +
+ "\r\n" +
+ "\r\n" +
+ "\r\n" +
+ "--=_alternative boundary=\r\n" +
+ "Content-Type: text/plain\r\n" +
+ "\r\n" +
+ "This is the plaintext.\r\n" +
+ "\r\n" +
+ "--=_alternative boundary=\r\n" +
+ "Content-Type: text/html\r\n" +
+ "\r\n" +
+ "This is a mail with multipart/related. Here is an image sent with a filename.
\r\n" + + "This is a mail with multipart/related. Here is an image sent without a filename.
\r\n" + + "{{ctx.Locale.Tr "admin.auths.sspi_auto_create_users_helper"}}
-{{ctx.Locale.Tr "admin.auths.sspi_auto_activate_users_helper"}}
-{{ctx.Locale.Tr "admin.auths.sspi_strip_domain_names_helper"}}
-{{ctx.Locale.Tr "admin.auths.sspi_separator_replacement_helper"}}
-{{ctx.Locale.Tr "admin.auths.sspi_default_language_helper"}}
-{{ctx.Locale.Tr "admin.auths.sspi_auto_create_users_helper"}}
-{{ctx.Locale.Tr "admin.auths.sspi_auto_activate_users_helper"}}
-{{ctx.Locale.Tr "admin.auths.sspi_strip_domain_names_helper"}}
-{{ctx.Locale.Tr "admin.auths.sspi_separator_replacement_helper"}}
-{{ctx.Locale.Tr "admin.auths.sspi_default_language_helper"}}
-{{ctx.Locale.Tr "repo.issues.filter_no_results_placeholder"}}
+{{ctx.Locale.Tr "settings.access_token_regeneration_desc"}}
+{{ctx.Locale.Tr "settings.access_token_deletion_desc"}}
{{ctx.Locale.Tr "settings.ssh_token_help"}}
-{{printf "echo -n '%s' | ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey" $.TokenToSign}}
echo -n '{{$.TokenToSign}}' | ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey
cmd /c "<NUL set /p=`"{{$.TokenToSign}}`"| ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey"
set /p={{$.TokenToSign}}| ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey