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 = ` - + ` + id + ` + ` + title + ` + ` + language + ` ` + semver + ` ` + authors + ` + ` + owners + ` + ` + copyright + ` + true true ` + projectURL + ` + ` + licenseURL + ` + ` + iconURL + ` ` + description + ` ` + releaseNotes + ` README.md + ` + tags + ` @@ -142,12 +158,22 @@ func TestParsePackageMetaData(t *testing.T) { assert.Equal(t, DependencyPackage, np.PackageType) assert.Equal(t, id, np.ID) + assert.Equal(t, title, np.Metadata.Title) + assert.Equal(t, language, np.Metadata.Language) assert.Equal(t, semver, np.Version) assert.Equal(t, authors, np.Metadata.Authors) + assert.Equal(t, owners, np.Metadata.Owners) + assert.Equal(t, copyright, np.Metadata.Copyright) + assert.True(t, np.Metadata.DevelopmentDependency) + assert.True(t, np.Metadata.RequireLicenseAcceptance) assert.Equal(t, projectURL, np.Metadata.ProjectURL) + assert.Equal(t, licenseURL, np.Metadata.LicenseURL) + assert.Equal(t, iconURL, np.Metadata.IconURL) assert.Equal(t, description, np.Metadata.Description) assert.Equal(t, releaseNotes, np.Metadata.ReleaseNotes) assert.Equal(t, readme, np.Metadata.Readme) + assert.Equal(t, tags, np.Metadata.Tags) + assert.Equal(t, minClientVersion, np.Metadata.MinClientVersion) assert.Equal(t, repositoryURL, np.Metadata.RepositoryURL) assert.Len(t, np.Metadata.Dependencies, 1) assert.Contains(t, np.Metadata.Dependencies, targetFramework) diff --git a/modules/process/manager_stacktraces_test.go b/modules/process/manager_stacktraces_test.go index d00fbc5ec8..509b424d8b 100644 --- a/modules/process/manager_stacktraces_test.go +++ b/modules/process/manager_stacktraces_test.go @@ -4,7 +4,6 @@ package process import ( - "context" "testing" "github.com/stretchr/testify/assert" @@ -12,13 +11,13 @@ import ( ) func TestProcessStacktraces(t *testing.T) { - _, _, finish := GetManager().AddContext(context.Background(), "Normal process") + _, _, finish := GetManager().AddContext(t.Context(), "Normal process") defer finish() - parentCtx, _, finish := GetManager().AddContext(context.Background(), "Children normal process") + parentCtx, _, finish := GetManager().AddContext(t.Context(), "Children normal process") defer finish() _, _, finish = GetManager().AddContext(parentCtx, "Children process") defer finish() - _, _, finish = GetManager().AddTypedContext(context.Background(), "System process", SystemProcessType, true) + _, _, finish = GetManager().AddTypedContext(t.Context(), "System process", SystemProcessType, true) defer finish() t.Run("No flat with no system process", func(t *testing.T) { diff --git a/modules/process/manager_test.go b/modules/process/manager_test.go index 36b2a912ea..0d637c8acc 100644 --- a/modules/process/manager_test.go +++ b/modules/process/manager_test.go @@ -23,7 +23,7 @@ func TestGetManager(t *testing.T) { func TestManager_AddContext(t *testing.T) { pm := Manager{processMap: make(map[IDType]*process), next: 1} - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() p1Ctx, _, finished := pm.AddContext(ctx, "foo") @@ -42,7 +42,7 @@ func TestManager_AddContext(t *testing.T) { func TestManager_Cancel(t *testing.T) { pm := Manager{processMap: make(map[IDType]*process), next: 1} - ctx, _, finished := pm.AddContext(context.Background(), "foo") + ctx, _, finished := pm.AddContext(t.Context(), "foo") defer finished() pm.Cancel(GetPID(ctx)) @@ -54,7 +54,7 @@ func TestManager_Cancel(t *testing.T) { } finished() - ctx, cancel, finished := pm.AddContext(context.Background(), "foo") + ctx, cancel, finished := pm.AddContext(t.Context(), "foo") defer finished() cancel() @@ -70,7 +70,7 @@ func TestManager_Cancel(t *testing.T) { func TestManager_Remove(t *testing.T) { pm := Manager{processMap: make(map[IDType]*process), next: 1} - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() p1Ctx, _, finished := pm.AddContext(ctx, "foo") diff --git a/modules/process/manager_unix.go b/modules/process/manager_unix.go index c5be906b35..54dd6dc485 100644 --- a/modules/process/manager_unix.go +++ b/modules/process/manager_unix.go @@ -1,8 +1,6 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -//go:build !windows - package process import ( diff --git a/modules/queue/base_levelqueue.go b/modules/queue/base_levelqueue.go index efc57c9c9c..06cb5f4819 100644 --- a/modules/queue/base_levelqueue.go +++ b/modules/queue/base_levelqueue.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/modules/nosql" "code.gitea.io/gitea/modules/queue/lqinternal" - "gitea.com/lunny/levelqueue" + "code.forgejo.org/forgejo/levelqueue" "github.com/syndtr/goleveldb/leveldb" ) diff --git a/modules/queue/base_levelqueue_common.go b/modules/queue/base_levelqueue_common.go index 78d3b85a8a..ee334c4571 100644 --- a/modules/queue/base_levelqueue_common.go +++ b/modules/queue/base_levelqueue_common.go @@ -13,7 +13,7 @@ import ( "code.gitea.io/gitea/modules/nosql" - "gitea.com/lunny/levelqueue" + "code.forgejo.org/forgejo/levelqueue" "github.com/syndtr/goleveldb/leveldb" ) diff --git a/modules/queue/base_levelqueue_test.go b/modules/queue/base_levelqueue_test.go index b65b570c4b..a4dc7a3062 100644 --- a/modules/queue/base_levelqueue_test.go +++ b/modules/queue/base_levelqueue_test.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/modules/queue/lqinternal" "code.gitea.io/gitea/modules/setting" - "gitea.com/lunny/levelqueue" + "code.forgejo.org/forgejo/levelqueue" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/syndtr/goleveldb/leveldb" diff --git a/modules/queue/base_levelqueue_unique.go b/modules/queue/base_levelqueue_unique.go index 968a4e98d4..ac133bdbf4 100644 --- a/modules/queue/base_levelqueue_unique.go +++ b/modules/queue/base_levelqueue_unique.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/nosql" "code.gitea.io/gitea/modules/queue/lqinternal" - "gitea.com/lunny/levelqueue" + "code.forgejo.org/forgejo/levelqueue" "github.com/syndtr/goleveldb/leveldb" ) diff --git a/modules/queue/base_test.go b/modules/queue/base_test.go index a5600fea63..d852a80b16 100644 --- a/modules/queue/base_test.go +++ b/modules/queue/base_test.go @@ -18,7 +18,7 @@ func testQueueBasic(t *testing.T, newFn func(cfg *BaseConfig) (baseQueue, error) q, err := newFn(cfg) require.NoError(t, err) - ctx := context.Background() + ctx := t.Context() _ = q.RemoveAll(ctx) cnt, err := q.Len(ctx) require.NoError(t, err) @@ -122,7 +122,7 @@ func TestBaseDummy(t *testing.T) { q, err := newBaseDummy(&BaseConfig{}, true) require.NoError(t, err) - ctx := context.Background() + ctx := t.Context() require.NoError(t, q.PushItem(ctx, []byte("foo"))) cnt, err := q.Len(ctx) diff --git a/modules/queue/manager_test.go b/modules/queue/manager_test.go index a76c238752..5806cbd6c9 100644 --- a/modules/queue/manager_test.go +++ b/modules/queue/manager_test.go @@ -4,7 +4,6 @@ package queue import ( - "context" "path/filepath" "testing" @@ -81,7 +80,7 @@ MAX_WORKERS = 123 require.NoError(t, err) - q1 := createWorkerPoolQueue[string](context.Background(), "no-such", cfgProvider, nil, false) + q1 := createWorkerPoolQueue[string](t.Context(), "no-such", cfgProvider, nil, false) assert.Equal(t, "no-such", q1.GetName()) assert.Equal(t, "dummy", q1.GetType()) // no handler, so it becomes dummy assert.Equal(t, filepath.Join(setting.AppDataPath, "queues/dir1"), q1.baseConfig.DataFullDir) @@ -97,7 +96,7 @@ MAX_WORKERS = 123 assert.Equal(t, "string", q1.GetItemTypeName()) qid1 := GetManager().qidCounter - q2 := createWorkerPoolQueue(context.Background(), "sub", cfgProvider, func(s ...int) (unhandled []int) { return nil }, false) + q2 := createWorkerPoolQueue(t.Context(), "sub", cfgProvider, func(s ...int) (unhandled []int) { return nil }, false) assert.Equal(t, "sub", q2.GetName()) assert.Equal(t, "level", q2.GetType()) assert.Equal(t, filepath.Join(setting.AppDataPath, "queues/dir2"), q2.baseConfig.DataFullDir) @@ -119,7 +118,7 @@ MAX_WORKERS = 123 assert.Equal(t, 120, q1.workerMaxNum) stop := runWorkerPoolQueue(q2) - require.NoError(t, GetManager().GetManagedQueue(qid2).FlushWithContext(context.Background(), 0)) - require.NoError(t, GetManager().FlushAll(context.Background(), 0)) + require.NoError(t, GetManager().GetManagedQueue(qid2).FlushWithContext(t.Context(), 0)) + require.NoError(t, GetManager().FlushAll(t.Context(), 0)) stop() } diff --git a/modules/queue/workerqueue_test.go b/modules/queue/workerqueue_test.go index 4cfe8ede97..0060d88ec6 100644 --- a/modules/queue/workerqueue_test.go +++ b/modules/queue/workerqueue_test.go @@ -5,7 +5,6 @@ package queue import ( "bytes" - "context" "runtime" "strconv" "sync" @@ -59,7 +58,7 @@ func TestWorkerPoolQueueUnhandled(t *testing.T) { testRecorder.Record("push:%v", i) require.NoError(t, q.Push(i)) } - require.NoError(t, q.FlushWithContext(context.Background(), 0)) + require.NoError(t, q.FlushWithContext(t.Context(), 0)) stop() ok := true @@ -167,7 +166,7 @@ func testWorkerPoolQueuePersistence(t *testing.T, queueSetting setting.QueueSett q, _ := newWorkerPoolQueueForTest("pr_patch_checker_test", queueSetting, testHandler, true) stop := runWorkerPoolQueue(q) - require.NoError(t, q.FlushWithContext(context.Background(), 0)) + require.NoError(t, q.FlushWithContext(t.Context(), 0)) stop() } diff --git a/modules/repository/hooks.go b/modules/repository/hooks.go index 95849789ab..75a21a09dd 100644 --- a/modules/repository/hooks.go +++ b/modules/repository/hooks.go @@ -7,7 +7,6 @@ import ( "fmt" "os" "path/filepath" - "runtime" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -146,10 +145,6 @@ func CreateDelegateHooks(repoPath string) (err error) { } func checkExecutable(filename string) bool { - // windows has no concept of a executable bit - if runtime.GOOS == "windows" { - return true - } fileInfo, err := os.Stat(filename) if err != nil { return false diff --git a/modules/secret/secret.go b/modules/secret/secret.go index e3557b91b9..fc63ec521b 100644 --- a/modules/secret/secret.go +++ b/modules/secret/secret.go @@ -27,7 +27,7 @@ func AesEncrypt(key, text []byte) ([]byte, error) { if _, err = io.ReadFull(rand.Reader, iv); err != nil { return nil, fmt.Errorf("AesEncrypt unable to read IV: %w", err) } - cfb := cipher.NewCFBEncrypter(block, iv) + cfb := cipher.NewCFBEncrypter(block, iv) //nolint:staticcheck cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b)) return ciphertext, nil } @@ -43,7 +43,7 @@ func AesDecrypt(key, text []byte) ([]byte, error) { } iv := text[:aes.BlockSize] text = text[aes.BlockSize:] - cfb := cipher.NewCFBDecrypter(block, iv) + cfb := cipher.NewCFBDecrypter(block, iv) //nolint:staticcheck cfb.XORKeyStream(text, text) data, err := base64.StdEncoding.DecodeString(string(text)) if err != nil { diff --git a/modules/setting/path.go b/modules/setting/path.go index 85d0e06302..b99f1977bb 100644 --- a/modules/setting/path.go +++ b/modules/setting/path.go @@ -34,11 +34,7 @@ var ( func getAppPath() (string, error) { var appPath string var err error - if IsWindows && filepath.IsAbs(os.Args[0]) { - appPath = filepath.Clean(os.Args[0]) - } else { - appPath, err = exec.LookPath(os.Args[0]) - } + appPath, err = exec.LookPath(os.Args[0]) if err != nil { if !errors.Is(err, exec.ErrDot) { return "", err diff --git a/modules/setting/server.go b/modules/setting/server.go index 5cc33f6fc4..c874a58069 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -265,7 +265,7 @@ func loadServerFrom(rootCfg ConfigProvider) { } UnixSocketPermission = uint32(UnixSocketPermissionParsed) - if !filepath.IsAbs(HTTPAddr) { + if HTTPAddr[0] != '@' && !filepath.IsAbs(HTTPAddr) { HTTPAddr = filepath.Join(AppWorkPath, HTTPAddr) } } diff --git a/modules/setting/server_test.go b/modules/setting/server_test.go index 7054c474ff..4b95961a26 100644 --- a/modules/setting/server_test.go +++ b/modules/setting/server_test.go @@ -73,3 +73,16 @@ MAX_USER_REDIRECTS = 8` assert.EqualValues(t, 3, Service.UsernameCooldownPeriod) assert.EqualValues(t, 8, Service.MaxUserRedirects) } + +func TestUnixSocketAbstractNamespace(t *testing.T) { + iniStr := ` + [server] + PROTOCOL=http+unix + HTTP_ADDR=@forgejo + ` + cfg, err := NewConfigProviderFromData(iniStr) + require.NoError(t, err) + loadServerFrom(cfg) + + assert.EqualValues(t, "@forgejo", HTTPAddr) +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 8350b914c5..487f2bb0d5 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -8,7 +8,6 @@ package setting import ( "fmt" "os" - "runtime" "strings" "time" @@ -34,7 +33,6 @@ var ( RunMode string RunUser string IsProd bool - IsWindows bool // IsInTesting indicates whether the testing is running. A lot of unreliable code causes a lot of nonsense error logs during testing // TODO: this is only a temporary solution, we should make the test code more reliable @@ -42,22 +40,18 @@ var ( ) func init() { - IsWindows = runtime.GOOS == "windows" if AppVer == "" { AppVer = "dev" } - // We can rely on log.CanColorStdout being set properly because modules/log/console_windows.go comes before modules/setting/setting.go lexicographically // By default set this logger at Info - we'll change it later, but we need to start with something. log.SetConsoleLogger(log.DEFAULT, "console", log.INFO) } // IsRunUserMatchCurrentUser returns false if configured run user does not match // actual user that runs the app. The first return value is the actual user name. -// This check is ignored under Windows since SSH remote login is not the main -// method to login on Windows. func IsRunUserMatchCurrentUser(runUser string) (string, bool) { - if IsWindows || SSH.StartBuiltinServer { + if SSH.StartBuiltinServer { return "", true } diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go index 028cd2ba76..25a41f02c0 100644 --- a/modules/templates/util_render_test.go +++ b/modules/templates/util_render_test.go @@ -46,12 +46,12 @@ var testMetas = map[string]string{ } func TestApostrophesInMentions(t *testing.T) { - rendered := RenderMarkdownToHtml(context.Background(), "@mention-user's comment") + rendered := RenderMarkdownToHtml(t.Context(), "@mention-user's comment") assert.EqualValues(t, template.HTML("

@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 space code :+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.
Maglagay ng absolute path kapag tinatakbo mo ang Forgejo bilang serbisyo. reinstall_confirm_check_3 = Kinukumprima mo na sigurado ka talaga na ang Forgejo na ito ay tumatakbo sa tamang app.ini na lokasyon at sigurado ka na kailangan mo mag-reinstall. Kinukumpirma mo na kilalanin ang mga panganib sa itaas. -err_empty_db_path = Hindi maaring walang laman ang path ng SQLite database. -no_admin_and_disable_registration = Hindi mo maaring i-disable ang user self-registration nang hindi gumawa ng isang tagapangasiwa na account. -err_empty_admin_password = Hindi maaring walang laman ang password ng tagapangasiwa. -err_empty_admin_email = Hindi maaring walang laman ang email ng tagapangasiwa. +err_empty_db_path = Hindi maaaring walang laman ang path ng SQLite database. +no_admin_and_disable_registration = Hindi mo maaaring i-disable ang user self-registration nang hindi gumawa ng isang tagapangasiwa na account. +err_empty_admin_password = Hindi maaaring walang laman ang password ng tagapangasiwa. +err_empty_admin_email = Hindi maaaring walang laman ang email ng tagapangasiwa. err_admin_name_is_reserved = Hindi angkop ang username ng tagapangasiwa, naka-reserba ang username err_admin_name_is_invalid = Hindi angkop ang username ng tagapangasiwa general_title = Mga General Setting @@ -250,9 +250,9 @@ domain_helper = Domain o host para sa server na ito. ssh_port = Port ng SSH Server http_port = Listen port sa HTTP lfs_path_helper = Ang mga file na naka-track sa Git LFS ay ilalagay sa directory na ito. Iwanang walang laman para i-disable. -reinstall_confirm_message = Ang pag-install muli na may umiiral na Forgejo database ay maaring magdulot ng mga problema. Sa karamihan ng mga kaso, dapat mong gamitin ang iyong umiiral na "app.ini" para patakbuhin ang Forgejo. Kung alam mo ang ginagawa mo, kumpirmahin ang mga sumusunod: -reinstall_confirm_check_1 = Ang data na naka-encrypt sa pamamagitan ng SECRET_KEY sa app.ini ay maaring mawala: baka hindi maka-log in ang mga user gamit ng 2FA/OTP at ang mga mirror ay maaring hindi gumana mg maayos. Sa pamamagitan ng pag-check ng box na ito kinukumpirma mo na ang kasalukuyang app.ini file ay naglalaman ng tamang SECRET_KEY. -reinstall_confirm_check_2 = Ang mga repositoryo at mga setting ay maaring kailangang i-resynchronize. Sa pamamagitan ng pag-check ng box na ito kinukumprima mo na ire-resynchronize mo ang mga hook para sa mga repositoryo at authorized_keys ng mano-mano. Kinukumpirma mo na sisiguraduhin mo na tama ang mga setting ng repositoryo at mirror. +reinstall_confirm_message = Ang pag-install muli na may umiiral na Forgejo database ay maaaring magdulot ng mga problema. Sa karamihan ng mga kaso, dapat mong gamitin ang iyong umiiral na "app.ini" para patakbuhin ang Forgejo. Kung alam mo ang ginagawa mo, kumpirmahin ang mga sumusunod: +reinstall_confirm_check_1 = Ang data na naka-encrypt sa pamamagitan ng SECRET_KEY sa app.ini ay maaaring mawala: baka hindi maka-log in ang mga user gamit ng 2FA/OTP at ang mga mirror ay maaaring hindi gumana mg maayos. Sa pamamagitan ng pag-check ng box na ito kinukumpirma mo na ang kasalukuyang app.ini file ay naglalaman ng tamang SECRET_KEY. +reinstall_confirm_check_2 = Ang mga repositoryo at mga setting ay maaaring kailangang i-resynchronize. Sa pamamagitan ng pag-check ng box na ito kinukumprima mo na ire-resynchronize mo ang mga hook para sa mga repositoryo at authorized_keys ng mano-mano. Kinukumpirma mo na sisiguraduhin mo na tama ang mga setting ng repositoryo at mirror. err_admin_name_pattern_not_allowed = Hindi angkop ang username ng tagapangasiwa, ang username ay tumutugma sa reserved pattern ssh_port_helper = Numero ng port na gagamitin ng SSH server. Iwanang walang laman para i-disable ang SSH server. server_service_title = Mga setting ng server at third-party na serbisyo @@ -362,6 +362,10 @@ table_modal.placeholder.content = Nilalaman table_modal.header = Magdagdag ng table table_modal.label.rows = Mga Row table_modal.label.columns = Mga Column +link_modal.header = Magdagdag ng link +link_modal.url = Url +link_modal.description = Deskripsyon +link_modal.paste_reminder = Pahiwatig: Kapag may URL sa clipboard, maari mong direktang i-paste sa editor para gumawa ng link. [filter] string.asc = A - Z @@ -565,7 +569,7 @@ SSPISeparatorReplacement = Pang-hiwalay SSPIDefaultLanguage = Default na wika CommitSummary = Pangkalahatang-ideya ng commit glob_pattern_error = ` hindi angkop ang glob pattern: %s` -require_error = ` hindi maaring walang laman.` +require_error = ` hindi maaaring walang laman.` alpha_dash_error = ` dapat maglaman lamang ng alphanumeric, dash ("-") at underscore ("_") na mga character.` alpha_dash_dot_error = ` dapat maglaman lamang ng alphanumeric, dash ("-"), underscore ("_") at tuldok (".") na mga character.` git_ref_name_error = ` dapat na mahusay na nabuong pangalan ng Git reference` @@ -613,8 +617,8 @@ unset_password = Hindi nagtakda ng password ang login user. unsupported_login_type = Hindi sinusuportahan ang uri ng pag-login para burahin ang account. user_not_exist = Hindi umiiral ang user. team_not_exist = Hindi umiiral ang koponan. -last_org_owner = Hindi mo maaring tanggalin ang pinakahuling user sa "mga may-ari" na koponan. Kailangan may kahit isang may-ari para sa organisasyon. -cannot_add_org_to_team = Hindi maaring madagdag ang isang organisasyon bilang miyembro ng koponan. +last_org_owner = Hindi mo maaaring tanggalin ang pinakahuling user sa "mga may-ari" na koponan. Kailangan may kahit isang may-ari para sa organisasyon. +cannot_add_org_to_team = Hindi maaaring madagdag ang isang organisasyon bilang miyembro ng koponan. duplicate_invite_to_team = Inimbita na ang user bilang miyembro ng koponan. organization_leave_success = Matagumpay kang umalis sa organisasyon na %s. invalid_ssh_key = Hindi ma-verify ang iyong SSH key: %s @@ -629,7 +633,7 @@ still_own_packages = Ang iyong account ay nagmamay-ari ng isa o higit pang packa org_still_own_repo = Ang organisasyon na ito ay nagmamay-ari ng isa o higit pang mga repositoryo, burahin o ilipat sila muna. org_still_own_packages = Ang organisasyon na ito ay nagmamay-ari ng isa o higit pang mga package, burahin sila muna. target_branch_not_exist = Hindi umiiral ang target branch. -admin_cannot_delete_self = Hindi mo maaring burahin ang sarili mo kapag isa kang tagapangasiwa. Paki-tanggal ang iyong pribilehiyong tagapangasiwa muna. +admin_cannot_delete_self = Hindi mo maaaring burahin ang sarili mo kapag isa kang tagapangasiwa. Paki-tanggal ang iyong pribilehiyong tagapangasiwa muna. required_prefix = Ang input ay dapat magsimula sa "%s" FullName = Buong pangalan Description = Paglalarawan @@ -762,8 +766,8 @@ gpg_token_code = echo "%s" | gpg -a --default-key %s --detach-sig delete_token_success = Nabura na ang token. Ang mga application na gumagamit nito ay hindi na maa-access ang iyong account. add_email_confirmation_sent = Ang isang email na pang-kumpirma ay ipinadala sa %s. Para kumpirmahin ang iyong email address, pakisuri ang iyong inbox at sundan ang ibinigay na link sa loob ng %s. key_content_ssh_placeholder = Nagsisimula sa "ssh-ed25519", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "sk-ecdsa-sha2-nistp256@openssh.com", o "sk-ssh-ed25519@openssh.com" -gpg_key_verified_long = Na-verify ang key na ito gamit ng isang token at maaring gamitin para i-verify ang mga commit na tumutugma sa anumang mga naka-activate na email address para sa user na ito kasama ang mga tumutugmang pagkakakilanlan para sa key na ito. -ssh_key_verified_long = Ang key na ito ay na-verify gamit ng isang token at maaring gamitin para i-verify ang mga commit na tumutugma na email address para sa user na ito. +gpg_key_verified_long = Na-verify ang key na ito gamit ng isang token at maaaring gamitin para i-verify ang mga commit na tumutugma sa anumang mga naka-activate na email address para sa user na ito kasama ang mga tumutugmang pagkakakilanlan para sa key na ito. +ssh_key_verified_long = Ang key na ito ay na-verify gamit ng isang token at maaaring gamitin para i-verify ang mga commit na tumutugma na email address para sa user na ito. add_principal_success = Idinagdag na ang SSH certificate principal na "%s". ssh_key_deletion_desc = Ang pagtanggal ng SSH key ay matatanggihan ang pag-access sa iyong account. Magpatuloy? no_activity = Walang kamakilang aktibidad @@ -822,7 +826,7 @@ keep_email_private = Itago ang email address openid_desc = Hinahayaan ka ng OpenID na mag-delegate ng pagpapatunay sa isang panlabas na tagabigay ng serbisyo. ssh_desc = Ang mga pampublikong SSH key na ito ay nauugnay sa iyong account. Pinapayagan ng kaukulang pribadong key ang buong pag-access sa iyong mga repositoryo. Ang mga SSH key na na-verify ay maaaring magamit upang mapatunayan ang mga naka-sign na Git commit sa pamamagitan ng SSH. principal_desc = Ang mga SSH principal na ito ay nauugnay sa iyong account at pinapayagan ang buong pag-access sa iyong mga repositoryo. -ssh_helper = Kailangan ng tulong? Tignan ang guide sa paggawa ng sarili mong mga SSH key o ilutas ang mga karaniwang problema na maaring moong matagpo gamit ng SSH. +ssh_helper = Kailangan ng tulong? Tignan ang guide sa paggawa ng sarili mong mga SSH key o ilutas ang mga karaniwang problema na maaaring moong matagpo gamit ng SSH. gpg_helper = Kailangan ng tulong? Tignan ang guide tungkol sa GPG. add_new_key = Magdagdag ng SSH key add_new_gpg_key = Magdagdag ng GPG key @@ -832,7 +836,7 @@ ssh_key_been_used = Idinagdag na ang SSH key na ito sa server. ssh_key_name_used = Ang isang SSH key na may katulad na pangalan ay umiiral na sa iyong account. ssh_principal_been_used = Idinagdag na ang principal na ito sa server. gpg_key_matched_identities = Mga Tumutugma na Pagkakakilanlan: -gpg_key_matched_identities_long = Ang mga naka-embed na pagkakakilanlan sa key na ito ay tumutugma sa mga sumusunod na naka-activate na email address para sa user na ito. Ang mga commit na tumutugma sa mga email address na ito ay maaring i-verify gamit ng key na ito. +gpg_key_matched_identities_long = Ang mga naka-embed na pagkakakilanlan sa key na ito ay tumutugma sa mga sumusunod na naka-activate na email address para sa user na ito. Ang mga commit na tumutugma sa mga email address na ito ay maaaring i-verify gamit ng key na ito. gpg_key_verified = Naka-verify na key gpg_key_verify = I-verify gpg_invalid_token_signature = Ang ibinigay na GPG key, signature, at token ay hindi tumutugma o luma. @@ -984,7 +988,7 @@ manage_account_links_desc = Ang mga panlabas na account na ito ay naka-link sa i hooks.desc = Magdagdag ng mga webhook na mati-trigger para sa lahat ng mga repositoryo na minamay-ari mo. orgs_none = Hindi ka isang miyembro ng anumang mga organisasyon. oauth2_application_create_description = Ang mga OAuth2 application ay pinapayagan ang mga third-party na aplikasyon na i-access ang mga user account sa instansya na ito. -oauth2_application_locked = Ang Forgejo ay pini-pre register ang ibang mga OAuth2 application sa startup kapag naka-enable sa config. Para iwasan ang hindi inaasahang gawain, hindi ito maaring i-edit o tanggalin. Mangyaring sumangguni sa dokumentasyon ng OAuth2 para sa karagdagang impormasyon. +oauth2_application_locked = Ang Forgejo ay pini-pre register ang ibang mga OAuth2 application sa startup kapag naka-enable sa config. Para iwasan ang hindi inaasahang gawain, hindi ito maaaring i-edit o tanggalin. Mangyaring sumangguni sa dokumentasyon ng OAuth2 para sa karagdagang impormasyon. remove_account_link_desc = Ang pagtanggal ng naka-link na account ay babawiin ang pag-access nito sa iyong Forgejo account. Magpatuloy? visibility.public_tooltip = Makikita ng lahat hints = Mga Pahiwatig @@ -1000,11 +1004,31 @@ keep_activity_private.description = Makikita mo lang at mga tagapangasiwa ng ins language.description = Mase-save ang wika sa iyong account at gagamitin bilang default pagkatapos mong mag-log in. language.localization_project = Tulungan kaming isalin ang Forgejo sa iyong wika! Matuto pa. pronouns_custom_label = Mga pasadyang pronoun -user_block_yourself = Hindi mo maaring harangan ang sarili mo. +user_block_yourself = Hindi mo maaaring harangan ang sarili mo. change_username_redirect_prompt.with_cooldown.one = Magiging available ang lumang username sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw, maari mo pa ring ma-claim muli ang lumang username sa panahon ng panahon ng cooldown. change_username_redirect_prompt.with_cooldown.few = Magiging available ang lumang username sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw, maari mo pa ring ma-claim muli ang lumang username sa panahon ng panahon ng cooldown. keep_pronouns_private = Ipakita lang ang mga panghalip sa mga naka-authenticate na user keep_pronouns_private.description = Itatago nito ang iyong mga panghalip mula sa mga bisita na hindi naka-log in. +quota.applies_to_user = Nag-aapply ang mga sumusunod na panuntunan ng quota sa iyong account +quota.sizes.assets.attachments.issues = Mga attachment sa isyu +quota.applies_to_org = Ang mga sumusunod na panuntunan sa quota ay nalalapat sa organisasyong ito +storage_overview = Buod ng Storage +quota = Quota +quota.rule.exceeded = Nalampasan +quota.rule.exceeded.helper = Ang kabuuang sukat ng mga bagay para sa panuntunang ito ay lumampas sa quota. +quota.rule.no_limit = Walang limitasyon +quota.sizes.all = Lahat +quota.sizes.repos.all = Mga repositoryo +quota.sizes.repos.public = Mga pampublikong repositoryo +quota.sizes.repos.private = Mga pribadong repositoryo +quota.sizes.git.all = Nilalaman ng Git +quota.sizes.git.lfs = Git LFS +quota.sizes.assets.all = Mga asset +quota.sizes.assets.attachments.all = Mga attachment +quota.sizes.assets.attachments.releases = Mga attachment sa release +quota.sizes.assets.artifacts = Mga artifact +quota.sizes.assets.packages.all = Mga package +quota.sizes.wiki = Wiki [repo] template_description = Ang mga template na repositoryo ay pinapayagan ang mga gumagamit na mag-generate ng mga bagong repositoryo na may magkatulad na istraktura ng direktoryo, mga file, at opsyonal na mga setting. @@ -1017,7 +1041,7 @@ admin.enabled_flags = Mga flag na naka-enable para sa repositoryo: admin.update_flags = I-update ang mga flag admin.flags_replaced = Napalitan ang mga flag ng repositoryo owner = May-ari -owner_helper = Maaring hindi mapapakita ang ibang organisasyon sa dropdown dahil sa pinakamataas na bilang ng repositoryo na limitasyon. +owner_helper = Maaaring hindi mapapakita ang ibang organisasyon sa dropdown dahil sa pinakamataas na bilang ng repositoryo na limitasyon. repo_name = Pangalan ng repositoryo repo_name_helper = Ang mga magandang pangalan ng repositoryo ay gumagamit ng maliit, makakaalala, at unique na mga keyword. repo_size = Laki ng Repositoryo @@ -1033,7 +1057,7 @@ fork_repo = I-fork ang repositoryo fork_from = I-fork mula sa already_forked = Na-fork mo na ang %s fork_to_different_account = Mag-fork sa ibang account -fork_visibility_helper = Ang visibility ng isang naka-fork na repositoryo ay hindi maaring baguhin. +fork_visibility_helper = Ang visibility ng isang naka-fork na repositoryo ay hindi maaaring baguhin. open_with_editor = Buksan gamit ang %s download_bundle = I-download ang BUNDLE repo_gitignore_helper_desc = Piliin kung anong mga file na hindi susubaybayin sa listahan ng mga template para sa mga karaniwang wika. Ang mga tipikal na artifact na ginagawa ng mga build tool ng wika ay kasama sa .gitignore ng default. @@ -1118,7 +1142,7 @@ stars = Mga bitwin migrate_options_mirror_helper = Magiging salamin ang repositoryong ito migrate_options_lfs_endpoint.description.local = Sinusuporta rin ang lokal na server path. editor.this_file_locked = Nakakandado ang file -editor.filename_cannot_be_empty = Hindi maaring walang laman ang pangalan ng file. +editor.filename_cannot_be_empty = Hindi maaaring walang laman ang pangalan ng file. commits.message = Mensahe commits.newer = Mas bago commits.date = Petsa @@ -1136,8 +1160,8 @@ tree_path_not_found_commit = Hindi umiiral ang path na %[1]s sa commit %[2]s tree_path_not_found_branch = Hindi umiiral ang daanang %[1]s sa branch %[2]s migrate_items_pullrequests = Mga hiling sa paghila archive.pull.nocomment = Naka-archive ang repositoryong ito. Hindi ka makakakomento sa mga pull request. -archive.title = Naka-archive ang repositoryong ito. Maari mong itignan ang mga file at i-clone ito, pero hindi ka makakagawa ng anumang pagbabago sa estado ng repositoryong ito, tulad ng pagtulak at paggawa ng mga isyu, pull request o mga komento. -archive.title_date = Naka-archive ang repositoryo na ito noong %s. Maari mong itignan ang mga file at i-clone ito, pero hindi ka makakagawa ng anumang pagbabago sa estado ng repositoryong ito, tulad ng pagtulak o paggawa ng mga bagong isyu, mga pull request, o komento. +archive.title = Naka-archive ang repositoryong ito. Maari mong itignan ang mga file at i-clone ito, pero hindi ka makakagawa ng anumang pagbabago sa estado ito, tulad ng pagtulak at paggawa ng mga isyu, pull request o mga komento. +archive.title_date = Naka-archive ang repositoryo na ito noong %s. Maari mong itignan ang mga file at i-clone ito, pero hindi ka makakagawa ng anumang pagbabago sa estado nito, tulad ng pagtulak o paggawa ng mga bagong isyu, mga pull request, o komento. pulls = Mga hiling sa paghila activity.merged_prs_count_n = Mga naisamang hiling sa paghila wiki.last_updated = Huling binago %s @@ -1175,7 +1199,7 @@ template.avatar = Avatar migrate_options = Mga opsyon sa paglipat migrate.clone_address_desc = Ang HTTP(S) o Git "clone" URL ng umiiral na repositoryo need_auth = Awtorisasyon -migrate.github_token_desc = Maari kang maglagay ng isa o higit pang mga token na hinihiwalay ng kuwit dito upang gawing mas-mabilis ang pagmigrate dahil sa rate limit ng GitHub API. BABALA: Ang pagabuso ng feature na ito ay maaring maglabag sa patakaran ng tagapagbigay ng serbisyo at maaring magdulot ng pag-block ng account. +migrate.github_token_desc = Maaari kang maglagay ng isa o higit pang mga token na hinihiwalay ng kuwit dito upang gawing mas-mabilis ang pagmigrate dahil sa rate limit ng GitHub API. BABALA: Ang pagabuso ng feature na ito ay maaaring maglabag sa patakaran ng tagapagbigay ng serbisyo at maaaring magdulot ng pag-block ng account. template.invalid = Kailangang pumili ng kahit isang template na repositoryo migrate_options_lfs_endpoint.description = Susubukan ng migration na gamitin ang iyong Git remote upang matukoy ang LFS server. Maari mong magtiyak ng custom na endpoint kapag ang LFS data ng repositoryo ay nakalagay sa ibang lugar. blame.ignore_revs.failed = Nabigong hindi pansinin ang mga rebisyon sa .git-blame-ignore-revs. @@ -1208,7 +1232,7 @@ adopt_preexisting_success = Pinagtibay ang mga file at ginawa ang repositoryo mu delete_preexisting_success = Burahin ang mga hindi pinatibay na file sa %s blame_prior = Tignan ang blame bago ang pagbabago na ito migrate.permission_denied = Hindi ka pinapayagang mag-import ng mga lokal na repositoryo. -migrate.permission_denied_blocked = Hindi ka maaring mag-import mula sa mga hindi pinapayagang host, magyaring magtanong sa pangangasiwa na suriin ang ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS na mga setting. +migrate.permission_denied_blocked = Hindi ka maaaring mag-import mula sa mga hindi pinapayagang host, magyaring magtanong sa pangangasiwa na suriin ang ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS na mga setting. migrate.invalid_local_path = Hindi wasto ang lokal na path. Hindi ito umiiral o hindi isang direktoryo. migrate.invalid_lfs_endpoint = Hindi wasto ang LFS endpoint. migrate.migrating_failed = Nabigo ang pag-migrate mula sa %s. @@ -1257,7 +1281,7 @@ file_follow = Sundan ang symlink file_view_source = Tignan ang source file_view_rendered = Tignan ng naka-render ambiguous_runes_header = `Naglalaman ng file na ito ng mga hindi tiyak na Unicode character` -ambiguous_runes_description = `Ang file na ito ay naglalaman ng mga Unicode character na maaring malilito sa ibang mga character. Kung sa tingin mo ay sinasadya ito, maari mong ligtas na hindi pansinin ang babala ito. Gamitin ang I-escape na button para ipakita sila.` +ambiguous_runes_description = `Ang file na ito ay naglalaman ng mga Unicode character na maaaring malilito sa ibang mga character. Kung sa tingin mo ay sinasadya ito, maaari mong ligtas na hindi pansinin ang babala ito. Gamitin ang I-escape na button para ipakita sila.` file_copy_permalink = Kopyahin ang permalink view_git_blame = Tignan ang git blame video_not_supported_in_browser = Hindi sinusuportahan ng inyong browser ang HTML5 "video" tag. @@ -1287,7 +1311,7 @@ broken_message = Ang Git data na pinagbabatayan sa repositoryo na ito ay hindi m file_history = Kasaysayan invisible_runes_header = `Nalalaman ng file na ito ng mga hindi nakikitang Unicode character` file_too_large = Masyadong malaki ang file para ipakita. -invisible_runes_description = `Ang file na ito ay naglalaman ng mga hindi nakikitang Unicode character na hindi nakikilala ng mga tao ngunit maaring maproseso ng ibang paraan ng isang computer. Kung sa tingin mo ay sinasadya ito, maari mong ligtas na hindi pansinin ang babala na ito. Gamitin ang I-escape na button para ipakita sila.` +invisible_runes_description = `Ang file na ito ay naglalaman ng mga hindi nakikitang Unicode character na hindi nakikilala ng mga tao ngunit maaaring maproseso ng ibang paraan ng isang computer. Kung sa tingin mo ay sinasadya ito, maaari mong ligtas na hindi pansinin ang babala na ito. Gamitin ang I-escape na button para ipakita sila.` commit.contained_in_default_branch = Ang commit na ito ay bahagi ng default na branch migrate.migrating_labels = Nililipat ang mga label filter_branch_and_tag = I-filter ang branch o tag @@ -1321,7 +1345,7 @@ clone_this_repo = I-clone ang repositoryo na ito cite_this_repo = Banggitin ang repositoryo na ito create_new_repo_command = Paggawa ng bagong repositoryo sa command line code = Code -ambiguous_character = `Ang %[1]c [U+%04[1]X] ay maaring malito sa %[2]c [U+%04[2]X]` +ambiguous_character = `Ang %[1]c [U+%04[1]X] ay maaaring malito sa %[2]c [U+%04[2]X]` escape_control_characters = I-escape unescape_control_characters = I-unescape invisible_runes_line = `Ang linya na ito ay may mga hindi nakikitang Unicode character` @@ -1335,7 +1359,7 @@ editor.must_be_on_a_branch = Dapat nasa branch ka upang gumawa o magmunkahi ng m editor.new_branch_name_desc = Bagong pangalan ng branch… editor.cancel = Kanselahin issues.role.member = Miyembro -issues.remove_request_review_block = Hindi maaring tanggalin ang hiling sa pagsuri +issues.remove_request_review_block = Hindi maaaring tanggalin ang hiling sa pagsuri issues.edit = Baguhin issues.cancel = Kanselahin issues.save = IImbak @@ -1736,7 +1760,7 @@ issues.label_exclusive_desc = Pangalanan ang label na 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.
Introduza unha reinstall_confirm_message = A reinstalación cunha base de datos Forgejo existente pode causar varios problemas. Na maioría dos casos, deberías usar o teu "app.ini" existente para executar Forgejo. Se sabes o que estás facendo, confirma o seguinte: reinstall_confirm_check_1 = É posible que se perdan os datos cifrados pola SECRET_KEY en app.ini: é posible que os usuarios non poidan iniciar sesión con 2FA/OTP e que os espellos non funcionen correctamente. Ao marcar esta caixa, confirmas que o ficheiro app.ini actual contén a SECRET_KEY correcta. disable_gravatar.description = Desactiva o uso de Gravatar ou outras fontes de avatares de terceiros. As imaxes predeterminadas utilizaranse para os avatares dos usuarios a menos que carguen o seu propio avatar na instancia. -federated_avatar_lookup = Activar avatares federados \ No newline at end of file +federated_avatar_lookup = Activar avatares federados +repo_path = Ruta raíz do repositorio +run_user = O usuario co que executar +password = Contrasinal +repo_path_helper = Os repositorios Git remotos gardaránse neste directorio. +lfs_path = Ruta raíz de Git LFS +install = Instalación +db_title = Configuración da base de datos +db_name = Nome da base de datos +db_schema = Esquema +db_schema_helper = Déixao baleiro para a base de datos por defecto ("public"). +app_name = Título da instancia +user = Nome de usuario +general_title = Opcións xerais +app_name_helper = Escribe o nome da túa instancia aqui. Será amosado en cada páxina. +mailer_user = Usuario SMTP +mailer_password = Contrasinal SMTP +title = Configuración inicial +db_type = Tipo de base de datos +app_slogan = Slogan da instancia +app_slogan_helper = Escribe o slogan da túa instancia aqui. Ou deixao baleiro para desabilitala. +domain = Dominio do servidor +ssh_port = Porto do servidor SSH \ No newline at end of file diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 2150505c93..dade632016 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -7,7 +7,7 @@ logo=Logo sign_in=Pieteikties sign_in_with_provider=Pieteikties ar %s sign_in_or=vai -sign_out=Attekties +sign_out=Atteikties sign_up=Reģistrēties link_account=Sasaistīt kontu register=Reģistrēties @@ -112,7 +112,7 @@ preview=Priekšskatījums loading=Notiek ielāde… error=Kļūda -error404=Lapa, ko tiek mēģināts atvērt, vai nu nepastāv vai arī nav tiesību to aplūkot. +error404=Lapa, ko tiek mēģināts atvērt, vai nu nepastāv, vai ir noņemta vai arī nav tiesību to aplūkot. go_back=Atgriezties never=Nekad @@ -162,7 +162,7 @@ filter.not_archived = Nav arhivētas filter.is_fork = Atzarojumi filter.not_fork = Nav atzarojumi filter.is_mirror = Spoguļglabātavas -filter.public = Publiskas +filter.public = Atklātas filter.private = Privātas filter.clear = Notīrīt atlasi confirm_delete_artifact = Vai tiešām izdzēst artefaktu '%s'? @@ -206,6 +206,10 @@ buttons.indent.tooltip = Pārvietot vienumus vienu līmeni dziļāk buttons.unindent.tooltip = Pārvietot vienumus vienu līmeni augstāk buttons.new_table.tooltip = Pievienot tabulu table_modal.header = Pievienot tabulu +link_modal.header = Pievienot saiti +link_modal.url = URL +link_modal.description = Apraksts +link_modal.paste_reminder = Norāde: starpliktuvē esošu URL var ielīmēt uzreiz redaktorā, lai izveidotu saiti. [filter] string.asc=A - Z @@ -288,7 +292,7 @@ smtp_from=Sūtīt e-pasta ziņojumus kā smtp_from_helper=E-pasta adrese, ko izmantos Forgejo. Jāievada tikai e-pasta adrese vai jāizmanto pieraksts "Vārds" . mailer_user=SMTP lietotājvārds mailer_password=SMTP parole -register_confirm=Reģistrējoties pieprasīt apstiprināt e-pastu +register_confirm=Reģistrējoties pieprasīt e-pasta adreses apstiprināšanu mail_notify=Iespējot e-pasta paziņojumus server_service_title=Servera un trešo pušu pakalpojumu iestatījumi offline_mode=Iespējot bezsaistes režīmu @@ -298,7 +302,7 @@ disable_gravatar.description=Atspējot Gravatar un citu trešo pušu attēlu avo federated_avatar_lookup=Iespējot apvienotos profila attēlus federated_avatar_lookup.description=Uzmeklēt profila attēlus ar Libravatar. disable_registration=Atspējot pašreģistrēšanos -disable_registration.description=Tikai servera pārvaldītāji varēs izveidot jaunus lietotāju kontus. Ir ļoti ieteicams reģistrēšanos paturēt atspējotu, ja vien nav iecerēts mitināt visiem pieejamu publisku serveri un ir gatavība tikt galā ar lielu negodprātīgu kontu skaitu. +disable_registration.description=Tikai servera pārvaldītāji varēs izveidot jaunus lietotāju kontus. Ir ļoti ieteicams reģistrēšanos paturēt atspējotu, ja vien nav iecerēts mitināt visiem pieejamu serveri un ir gatavība tikt galā ar lielu negodprātīgu kontu skaitu. allow_only_external_registration.description=Lietotāji varēs izveidot jaunos kontus tikai izmantojot konfigurētus ārējos pakalpojumus. openid_signin=Iespējot pieteikšanos ar OpenID openid_signin.description=Ļaut lietotājiem pieteikties ar OpenID. @@ -370,9 +374,9 @@ show_only_archived=Attēlot tikai arhivētos show_only_unarchived=Attēlot tikai nearhivētos show_private=Privāts -show_both_private_public=Attēlot gan publiskos, gan privātos +show_both_private_public=Rāda gan atklātās, gan privātās show_only_private=Attēlot tikai privātos -show_only_public=Attēlot tikai publiskos +show_only_public=Attēlo tikai atklātās issues.in_your_repos=Manās glabātavās @@ -407,7 +411,7 @@ create_new_account=Izveidot kontu register_helper_msg=Jau ir konts? Piesakieties tagad! social_register_helper_msg=Jau ir konts? Piesaisti to! disable_register_prompt=Reģistrēšanās ir atspējota. Lūgums sazināties ar vietnes pārvaldītāju. -disable_register_mail=E-pasta apstiprināšana reģistrējoties ir atspējota. +disable_register_mail=E-pasta adreses apstiprināšana reģistrējoties ir atspējota. manual_activation_only=Jāsazinās ar vietnes pārvaldītāju, lai pabeigtu aktivēšanu. remember_me=Atcerēties šo ierīci remember_me.compromised=Pieteikšanās pilnvara vairs nav derīga, kas var norādīt uz ļaunprātīgām darbībām kontā. Lūgums pārbaudīt, vai kontā nav neparastu darbību. @@ -430,7 +434,7 @@ email_not_associate=Šī e-pasta adrese nav saistīta ar nevienu kontu. send_reset_mail=Nosūtīt atkopes e-pasta ziņojumu reset_password=Konta atkope invalid_code=Apstiprināšanas kods ir nederīgs, vai ir beidzies tā derīgums. -invalid_code_forgot_password=Apstiprināšanas kods ir nederīgs vai tā derīgums ir beidzies. Jāklikšķina šeit, lai uzsāktu jaunu sesiju. +invalid_code_forgot_password=Apstiprināšanas kods ir nederīgs, vai tā derīgums ir beidzies. Jāklikšķina šeit, lai uzsāktu jaunu sesiju. invalid_password=Parole neatbilst tai, kas tika izmantota konta izveidošanas laikā. reset_password_helper=Atjaunot paroli reset_password_wrong_user=Tu esi pieteicies kā %s, bet konta atkopes saite ir paredzēta %s @@ -470,7 +474,7 @@ authorize_title=Pilnvarot "%s" piekļuvi Tavam kontam? authorization_failed=Pilnvarošana neizdevās authorization_failed_desc=Pilnvarošana neizdevās, jo tika noteikts nederīgs pieprasījums. Lūgums sazināties ar lietotnes, no kuras tika veikts pilnvarošanas pieprasījums, uzturētāju. sspi_auth_failed=SSPI autentifikācija neizdevās -password_pwned=Izvēlētā parole ir nozagto paroļu sarakstā, kas iepriekš ir atklāts publiskās datu noplūdēs. Lūgums mēģināt vēlreiz ar citu paroli un apsvērt to nomainīt arī citur. +password_pwned=Izvēlētā parole ir nozagto paroļu sarakstā, kas iepriekš ir atklāts pieejamās datu noplūdēs. Lūgums mēģināt vēlreiz ar citu paroli un apsvērt to nomainīt arī citur. password_pwned_err=Neizdevās pabeigt pieprasījumu uz HaveIBeenPwned back_to_sign_in = Atpakaļ uz pieteikšanos unauthorized_credentials = Pieteikšanās dati ir nepareizi vai ir izbeigušies. Jāizpilda komanda atkārtoti vai jāizmanto %s, lai iegūtu vairāk informācijas @@ -686,7 +690,7 @@ email_domain_is_not_allowed = Lietotāja e-pasta adreses %s domēna vārd change_avatar=Mainīt profila attēlu… joined_on=Pievienojās %s repositories=Glabātavas -activity=Publiskie notikumi +activity=Atklāti notikumi followers_few=%d sekotāji starred=Izlasei pievienotās glabātavas watched=Vērotās glabātavas @@ -745,7 +749,7 @@ organization=Apvienības uid=UID webauthn=Divpakāpju pieteikšanās (drošības atslēgas) -public_profile=Publiskais profils +public_profile=Visiem pieejamais profils biography_placeholder=Pastāsti citiem mazliet par sevi! (Tiek atbalstīts Markdown) location_placeholder=Kopīgot savu aptuveno atrašanās vietu ar citiem profile_desc=Par Tevi @@ -859,7 +863,7 @@ add_new_principal=Pievienot identitāti ssh_key_been_used=Šī SSH atslēga jau ir pievienota šajā serverī. ssh_key_name_used=SSH atslēga ar tādu pašu nosaukumu jau ir kontā. ssh_principal_been_used=Šāda identitāte jau ir pievienota šājā serverī. -gpg_key_id_used=Jau pastāv publiskā GPG atslēga ar tādu pašu identifikatoru. +gpg_key_id_used=Jau pastāv publiska GPG atslēga ar tādu pašu identifikatoru. gpg_no_key_email_found=Šī GPG atslēga neatbilst nevienai ar kontu saistītajai e-pasta adresei. To joprojām var pievienot, ja tiek parakstīta norādītā pilnvara. gpg_key_matched_identities=Atbilstošās identitātes: gpg_key_matched_identities_long=Šajā atslēgā iegultās identitātes atbilst zemāk uzskaitītājām aktivētajām šī lietotāja e-pasta adresēm. Iesūtījumus, kas atbilst šīm e-pasta adresēm, var apliecināt ar šo atslēgu. @@ -936,8 +940,8 @@ access_token_deletion_confirm_action=Dzēst access_token_deletion_desc=Pilnvaras izdzēšana atsauks lietotņu, kas to izmanto, piekļuvi kontam. Šo darbību nevar atsaukt. Turpināt? delete_token_success=Pilnvara tika izdzēsta. Lietotnēm, kas to izmanto, vairs nav piekļuves kontam. repo_and_org_access=Glabātavas un apvienības piekļuve -permissions_public_only=Tikai publiskās -permissions_access_all=Visas (publiskā, privātās un ierobežotās) +permissions_public_only=Tikai atklātās +permissions_access_all=Visas (atklātās, privātās un ierobežotās) select_permissions=Atlasīt atļaujas permission_no_access=Nav piekļuves permission_read=Lasīt @@ -1031,14 +1035,14 @@ email_notifications.submit=Iestatīt e-pasta iestatījumus email_notifications.andyourown=Un manus paziņojumus visibility=Lietotāja redzamība -visibility.public=Publiska +visibility.public=Atklāta visibility.public_tooltip=Redzams ikvienam visibility.limited=Ierobežota visibility.limited_tooltip=Redzams tikai lietotājiem, kuri ir pieteikušies visibility.private=Privāta visibility.private_tooltip=Redzams tikai apvienību, kurās pievienojies, dalībniekiem change_password = Mainīt paroli -keep_activity_private.description = Tavas publiskās darbības būs redzamas tikai Tev un servera pārvaldītājiem. +keep_activity_private.description = Tavas atklātās darbības būs redzamas tikai Tev un servera pārvaldītājiem. update_hints = Atjaunināt norādes update_hints_success = Norādes tika atjauninātas. user_block_success = Lietotājs tika sekmīgi liegts. @@ -1061,6 +1065,26 @@ change_username_redirect_prompt.with_cooldown.one = Vecais lietotājvārds būs change_username_redirect_prompt.with_cooldown.few = Vecais lietotājvārds būs pieejams visiem pēc noilguma, kas ir %[1]d dienas. Šajā laikā ir iespējams to atkal sākt izmantot. keep_pronouns_private = Vietniekvārdus rādīt tikai lietotājiem, kuri ir pieteikušies keep_pronouns_private.description = Šis paslēps vietniekvārdus no apmeklētājiem, kuri nav pieteikušies. +quota.sizes.assets.all = Līdzekļi +quota.sizes.git.lfs = Git LFS +quota.applies_to_user = Uz kontu attiecas zemāk esošās ierobežojuma kārtulas +quota.rule.exceeded.helper = Kopējais šīs kārtulas objektu izmērs pārsniedz ierobežojumu. +quota.sizes.git.all = Git saturs +quota.rule.exceeded = Pārsniegts +quota.sizes.assets.attachments.all = Pielikumi +quota.sizes.assets.attachments.issues = Pieteikumu pielikumi +quota.sizes.assets.attachments.releases = Laidienu pielikumi +quota.sizes.assets.artifacts = Artefakti +quota.sizes.assets.packages.all = Pakotnes +quota.sizes.wiki = Vikivietne +storage_overview = Krātuves pārskats +quota = Ierobežojums +quota.applies_to_org = Uz apvienību attiecas zemāk esošās ierobežojuma kārtulas +quota.rule.no_limit = Neierobežots +quota.sizes.all = Viss +quota.sizes.repos.all = Glabātavas +quota.sizes.repos.public = Atklātās glabātavas +quota.sizes.repos.private = Privātās glabātavas [repo] new_repo_helper=Glabātava satur visas projekta datnes, tajā skaitā izmaiņu vēsturi. Jau tiek izmantota kaut kur citur? Pārcelt glabātavu. @@ -1167,7 +1191,7 @@ transfer.no_permission_to_accept=Nav atļaujas pieņemt šo nodošanu. transfer.no_permission_to_reject=Nav atļaujas noraidīt šo nodošanu. desc.private=Privāts -desc.public=Publisks +desc.public=Atklāts desc.template=Sagatave desc.internal=Iekšējs desc.archived=Arhivēts @@ -1184,8 +1208,8 @@ template.issue_labels=Pieteikumu iezīmes template.one_item=Jāatlasa vismaz viens sagataves vienums template.invalid=Jāatlasa sagataves glabātava -archive.title=Šī glabātava ir arhivēta. Tajā var apskatīt datnes, un to var klonēt, bet nevar aizgādāt izmaiņas vai izveidot pieteikumus vai izmaiņu pieprasījumus. -archive.title_date=Šī glabātava tika arhivēta %s. Tajā var apskatīt datnes, un to var klonēt, bet nevar aizgādāt izmaiņas vai izveidot pieteikumus vai izmaiņu pieprasījumus. +archive.title=Šī glabātava ir arhivēta. Tajā var apskatīt datnes, un to var klonēt, bet tajā nevar veikt jebkādas izmaiņas, piemēram, aizgādāt izmaiņas un izveidot jaunus pieteikumus, izmaiņu pieprasījumus vai piebildes. +archive.title_date=Šī glabātava tika arhivēta %s. Tajā var apskatīt datnes, un to var klonēt, bet tajā nevar veikt jebkādas izmaiņas, piemēram, aizgādāt izmaiņas un izveidot pieteikumus, izmaiņu pieprasījumus vai piebildes. archive.issue.nocomment=Šī glabātava ir arhivēta. Pieteikumiem nevar pievienot piebildes. archive.pull.nocomment=Šī glabātava ir arhivēta. Izmaiņu pieprasījumiem nevar pievienot piebildes. @@ -1513,7 +1537,7 @@ issues.choose.open_external_link=Atvērt issues.choose.blank=Noklusējuma issues.choose.blank_about=Izveidot pieteikumu no noklusējuma sagataves. issues.choose.ignore_invalid_templates=Kļūdainās sagataves tika izlaistas -issues.choose.invalid_templates=atrasta(s) %v ķļūdaina(s) sagatave(s) +issues.choose.invalid_templates=atrasta(s) %v nederīgas(s) sagatave(s) issues.choose.invalid_config=Pieteikumu konfigurācija satur kļūdas: issues.no_ref=Nav norādīts zars/birka issues.create=Izveidot pieteikumu @@ -1581,8 +1605,8 @@ issues.filter_sort.mostcomment=Visvairāk piebilžu issues.filter_sort.leastcomment=Vismazāk piebilžu issues.filter_sort.nearduedate=Tuvākais termiņš issues.filter_sort.farduedate=Tālākais termiņš -issues.filter_sort.moststars=Visvairāk atzīmētie -issues.filter_sort.feweststars=Vismazāk atzīmētie +issues.filter_sort.moststars=Visvairāk zvaigžņu +issues.filter_sort.feweststars=Vismazāk zvaigžņu issues.filter_sort.mostforks=Visvairāk atzarojumu issues.filter_sort.fewestforks=Vismazāk atzarojumu issues.keyword_search_unavailable=Meklēšana pēc atslēgvārda pašreiz nav pieejama. Lūgums sazināties ar vietnes administratoru. @@ -1594,7 +1618,7 @@ issues.action_milestone_no_select=Nav atskaites punkta issues.action_assignee=Atbildīgais issues.action_assignee_no_select=Nav atbildīgā issues.action_check=Atzīmēt/Notīrīt -issues.action_check_all=Atzīmēt/Notīrīt visus ierakstus +issues.action_check_all=Atzīmēt/Notīrīt visus vienumus issues.opened_by=%[3]s atvēra %[1]s pulls.merged_by=%[3]s iekļāva %[1]s pulls.merged_by_fake=%[2]s iekļāva %[1]s @@ -1708,21 +1732,21 @@ issues.delete=Izdzēst issues.delete.title=Izdzēst šo pieteikumu? issues.delete.text=Vai tiešām izdzēst šo pieteikumu? (Tas neatgriezeniski noņems visu saturu. Tā vietā vēlams apsvērt aizvēršanu, ja ir paredzēts paturēt to arhivētu) issues.tracker=Laika uzskaite -issues.start_tracking_short=Uzsākt laika skaitīšanu +issues.start_tracking_short=Uzsākt laika uzskaitīšanu issues.start_tracking=Uzsākt laika uzskaiti issues.start_tracking_history=` uzsāka darbu %s` issues.tracker_auto_close=Laika uzskaite tiks automātiski apturēta, kad šis pieteikums tiks aizvērts -issues.tracking_already_started=`Laika uzskaite jau ir uzsākta citā pieteikumā!` +issues.tracking_already_started=`Laika uzskaitīšana jau ir uzsākta citā pieteikumā!` issues.stop_tracking=Apturēt laika uzskaitīšanu issues.stop_tracking_history=` beidza strādāt %s` issues.cancel_tracking=Atmest issues.cancel_tracking_history=`atcēla laika uzskaitīšanu %s` issues.add_time=Pašrocīgi pievienot laiku -issues.del_time=Dzēst šo laika žurnāla ierakstu +issues.del_time=Izdzēst šo laika žurnāla ierakstu issues.add_time_short=Pievienot laiku issues.add_time_cancel=Atcelt issues.add_time_history=` pievienoja patērēto laiku %s` -issues.del_time_history=`dzēsts patērētais laiks %s` +issues.del_time_history=`izdzēsa patērēto laiku %s` issues.add_time_hours=Stundas issues.add_time_minutes=Minūtes issues.add_time_sum_to_small=Nav norādīts laiks. @@ -1792,10 +1816,10 @@ issues.review.add_review_request=pieprasīja izskatīšanu no %[1]s %[2]s issues.review.remove_review_request=noņēma izskatīšanas pieprasījumu %[1]s %[2]s issues.review.remove_review_request_self=atteicās izskatīt %s issues.review.pending=Nav iesūtīts -issues.review.pending.tooltip=Šī piebilde pagaidām nav redzama citiem lietotājiem. Lai iesniegtu savas ierindotās piebildes, jāatlasa "%s" -> "%s/%s/%s" lapas augšdaļā. +issues.review.pending.tooltip=Šī piebilde pagaidām nav redzama citiem lietotājiem. Lai iesniegtu savas ierindotās piebildes, lapas augšdaļā jāatlasa "%s" -> "%s/%s/%s". issues.review.review=Izskatīšana issues.review.reviewers=Izskatītāji -issues.review.outdated=Novecojis +issues.review.outdated=Novecojusi issues.review.outdated_description=Pēc šīs piebildes pievienošanas ir mainījies saturs issues.review.option.show_outdated_comments=Rādīt novecojušas piebildes issues.review.option.hide_outdated_comments=Paslēpt novecojušas piebildes @@ -1805,14 +1829,14 @@ issues.review.show_resolved=Rādīt atrisināto issues.review.hide_resolved=Paslēpt atrisināto issues.review.resolve_conversation=Atrisināt sarunu issues.review.un_resolve_conversation=Atcelt sarunas atrisinājumu -issues.review.resolved_by=atzīmēja sarunu kā atrisinātu +issues.review.resolved_by=atzīmēja šo sarunu kā atrisinātu issues.assignee.error=Ne visi atbildīgie tika pievienoti, jo radās neparedzēta kļūda. issues.reference_issue.body=Saturs -issues.content_history.deleted=dzēsts +issues.content_history.deleted=izdzēsts issues.content_history.edited=labots issues.content_history.created=izveidots -issues.content_history.delete_from_history=Dzēst no vēstures -issues.content_history.delete_from_history_confirm=Vai dzēst no vēstures? +issues.content_history.delete_from_history=Izdzēst no vēstures +issues.content_history.delete_from_history_confirm=Izdzēst no vēstures? issues.content_history.options=Iespējas issues.reference_link=Atsauce: %s @@ -1834,7 +1858,7 @@ pulls.expand_files=Izvērst visas datnes pulls.collapse_files=Savērst visas datnes pulls.compare_base=pamata pulls.compare_compare=atgādāt no -pulls.switch_comparison_type=Mainīt salīdzināšanas tipu +pulls.switch_comparison_type=Pārslēgt salīdzināšanas veidu pulls.switch_head_and_base=Apmainīt galotnes un pamata zarus pulls.filter_branch=Atlasīt zarus pulls.no_results=Nekas netika atrasts. @@ -1864,10 +1888,10 @@ pulls.manually_merged=Pašrocīgi apvienots pulls.merged_info_text=Zaru %s tagad var izdzēst. pulls.is_closed=Izmaiņu pieprasījums tika aizvērts. pulls.title_wip_desc=`Sākt virsrakstu ar %s, lai novērstu izmaiņu pieprasījuma nejaušu iekļaušanu.` -pulls.cannot_merge_work_in_progress=Šis izmaiņu pieprasījums ir atzīmēts, ka pie tā vēl notiek izstrāde. +pulls.cannot_merge_work_in_progress=Šis izmaiņu pieprasījums ir atzīmēts kā nepabeigts darbs. pulls.still_in_progress=Joprojām notiek izstrāde? -pulls.add_prefix=Pievienot %s prefiksu -pulls.remove_prefix=Noņemt %s prefiksu +pulls.add_prefix=Pievienot sākuma virkni %s +pulls.remove_prefix=Noņemt sākuma virkni %s pulls.data_broken=Šis izmaiņu pieprasījums ir bojāts trūkstošas atzarojuma informācijas dēļ. pulls.files_conflicted=Šī izmaiņu pieprasījuma izmaiņas nav saderīgas ar mērķa zaru. pulls.is_checking=Notiek apvienošanas nesaderību pārbaude. Pēc brīža jāmēģina vēlreiz. @@ -1920,12 +1944,12 @@ pulls.has_merged=Neizdevās: izmaiņu pieprasījums tika iekļauts, to nevar dar pulls.push_rejected=Aizgādāšana neizdevās: aizgādāšana tika noraidīta. Jāpārskata šīs glabātavas Git aizķeres. pulls.push_rejected_summary=Pilns noraidīšanas ziņojums pulls.push_rejected_no_message=Aizgādāšana neizdevās: aizgādāšana tika noraidīta, bet serveris neatgrieza ziņojumu. Jāpārskata šīs glabātavas Git aizķeres -pulls.open_unmerged_pull_exists=`Nevar veikt atkārtotas atvēršanas darbību, jo jau pastāv neapstiprināts izmaiņu pieprasījums (#%d) ar tieši tādām pašām pazīmēm.` +pulls.open_unmerged_pull_exists=`Nevar veikt atkārtotu atvēršanu, jo jau pastāv neapstiprināts izmaiņu pieprasījums (#%d) ar tieši tādām pašām pazīmēm.` pulls.status_checking=Dažas pārbaudes vēl tiek veiktas pulls.status_checks_success=Visas pārbaudes bija sekmīgas -pulls.status_checks_warning=Dažas pārbaudes ziņoja brīdinājumus +pulls.status_checks_warning=Dažas pārbaudes atgrieza brīdinājumus pulls.status_checks_failure=Dažas pārbaudes neizdevās izpildīt -pulls.status_checks_error=Dažu pārbaužu izpildes laikā, radās kļūdas +pulls.status_checks_error=Dažas pārbaudes atgrieza kļūdas pulls.status_checks_requested=Nepieciešama pulls.status_checks_details=Papildu informācija pulls.status_checks_hide_all=Paslēpt visas pārbaudes @@ -2000,7 +2024,7 @@ signing.wont_sign.error=Atgadījās kļūda pārbaudot, vai iesūtījums var tik signing.wont_sign.nokey=Nav pieejamas atslēgas, ar ko parakstīt šo iesūtījumu. signing.wont_sign.never=Iesūtījumi nekad netiek parakstīti. signing.wont_sign.always=Iesūtījumi vienmēr tiek parakstīti. -signing.wont_sign.pubkey=Iesūtījums netiks parakstīts, jo kontam nav piesaistīta publiskā atslēga. +signing.wont_sign.pubkey=Iesūtījums netiks parakstīts, jo kontam nav piesaistīta publiska atslēga. signing.wont_sign.twofa=Jābūt iespējotai divpakāpju autentificēšanai, lai parakstītu iesūtījumus. signing.wont_sign.parentsigned=Iesūtījums netiks parakstīts, jo nav parakstīts cilmes iesūtījums. signing.wont_sign.basesigned=Apvienošana netiks parakstīta, jo pamata iesūtījums nav parakstīts. @@ -2013,7 +2037,7 @@ ext_wiki=Ārēja vikivietne ext_wiki.desc=Ārējā vikivietne norāda uz ārējo vikivietnes adresi. wiki=Vikivietne -wiki.welcome=Laipni lūgti vikivietnē. +wiki.welcome=Laipni lūdzam vikivietnē. wiki.welcome_desc=Vikivietne ļauj rakstīt un kopīgot dokumentāciju ar līdzdalībniekiem. wiki.desc=Dokumentācijas rakstīšana un kopīgošana ar līdzdalībniekiem. wiki.create_first_page=Izveidot pirmo lapu @@ -2040,7 +2064,7 @@ wiki.page_name_desc=Jāievada šīs vikivietnes lapas nosaukums. Daži īpašie wiki.original_git_entry_tooltip=Rādīt sākotnējo Git datni, nevis izmantot draudzīgo saiti. activity=Notikumi -activity.period.filter_label=Laika periods: +activity.period.filter_label=Laika posms: activity.period.daily=1 diena activity.period.halfweekly=3 dienas activity.period.weekly=1 nedēļa @@ -2060,18 +2084,18 @@ activity.title.user_n=%d lietotāji activity.title.prs_1=%d izmaiņu pieprasījumu activity.title.prs_n=%d izmaiņu pieprasījumus activity.title.prs_merged_by=%s iekļāva %s -activity.title.prs_opened_by=%s piedāvāja %s +activity.title.prs_opened_by=%s ierosināja %s activity.merged_prs_label=Iekļauts -activity.opened_prs_label=Piedāvāts +activity.opened_prs_label=Ierosināts activity.active_issues_count_1=%d atvērts pieteikums activity.active_issues_count_n=%d atvērti pieteikumi activity.closed_issues_count_1=Aizvērts pieteikums activity.closed_issues_count_n=Aizvērti pieteikumi activity.title.issues_1=%d pieteikumu activity.title.issues_n=%d pieteikumus -activity.title.issues_closed_from=%s aizvērts no %s +activity.title.issues_closed_from=%s aizvēra %s activity.title.issues_created_by=%s izveidoja %s -activity.closed_issue_label=Aizvēra +activity.closed_issue_label=Aizvērts activity.new_issues_count_1=Jauns pieteikums activity.new_issues_count_n=Jauni pieteikumi activity.new_issue_label=Atvēra @@ -2081,7 +2105,7 @@ activity.unresolved_conv_desc=Šie nesen mainītie pieteikumi un izmaiņu piepra activity.unresolved_conv_label=Atvērts activity.title.releases_1=%d laidiens activity.title.releases_n=%d laidieni -activity.title.releases_published_by=%s publicēja %s +activity.title.releases_published_by=%s laida klājā %s activity.published_release_label=Laidiens activity.no_git_activity=Šajā laika periodā nav notikušas nekādas izmaiņas. activity.git_stats_exclude_merges=Neskaitot apvienošanas iesūtījumus, @@ -2102,8 +2126,8 @@ activity.git_stats_additions=un tika veiktas activity.git_stats_addition_1=%d pievienošana activity.git_stats_addition_n=%d pievienošanas activity.git_stats_and_deletions=un -activity.git_stats_deletion_1=%d dzēšana -activity.git_stats_deletion_n=%d dzēšanas +activity.git_stats_deletion_1=%d izdzēšana +activity.git_stats_deletion_n=%d izdzēšanas contributors.contribution_type.commits=Iesūtījumi @@ -2123,8 +2147,8 @@ settings.desc=Iestatījumi ir vieta, kur pārvaldīt glabātavas iestatījumus settings.options=Glabātava settings.collaboration=Līdzdalībnieki settings.collaboration.admin=Pārvaldītājs -settings.collaboration.write=Rakstīšanas -settings.collaboration.read=Skatīšanās +settings.collaboration.write=Rakstīt +settings.collaboration.read=Lasīt settings.collaboration.owner=Īpašnieks settings.collaboration.undefined=Nedefinētas settings.hooks=Tīmekļa aizķeres @@ -2175,14 +2199,14 @@ settings.use_external_issue_tracker=Izmantot ārēju pieteikumu izsekotāju settings.external_tracker_url=Ārējā pieteikumu izsekotāja URL settings.external_tracker_url_error=Ārējā pieteikumu izsekotāja URL nav derīgs URL. settings.external_tracker_url_desc=Apmeklētāji tiks novirzīti uz ārējā pieteikumu izsekotāja URL pēc klikšķināšanas uz pieteikumu cilnes. -settings.tracker_url_format=Ārējā pieteikumu izsekotāja URL veidols +settings.tracker_url_format=Ārējā pieteikumu izsekotāja URL uzbūve settings.tracker_url_format_error=Ārējā pieteikumu izsekotāja URL uzbūve neatbilst derīgam URL. -settings.tracker_issue_style=Ārējā pieteikumu izsekotāja numuru veidols +settings.tracker_issue_style=Ārējā pieteikumu izsekotāja numuru uzbūve settings.tracker_issue_style.numeric=Cipari settings.tracker_issue_style.alphanumeric=Burti un cipari settings.tracker_issue_style.regexp=Regulārā izteiksme -settings.tracker_issue_style.regexp_pattern=Regulārās izteiksmes šablons -settings.tracker_issue_style.regexp_pattern_desc=Pirmā iegultā grupa tiks izmantota {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 (/.well-known/openid-configuration) для автоматичної настройки входу OAuth auths.tip.twitter=Перейдіть на %s, створіть програму і переконайтеся, що включена опція «Дозволити цю програму для входу в систему за допомогою Twitter» auths.tip.discord=Зареєструйте новий додаток на %s -auths.tip.yandex=Створіть новий додаток на %s. Виберіть наступні дозволи з «Yandex.Passport API»: «Доступ до адреси електронної пошти», «Доступ до аватара» і «Доступ до імені користувача, імені та прізвища, статі» +auths.tip.yandex=Створіть новий додаток на %s. У розділі «Yandex.Passport API» виберіть такі дозволи: «Доступ до адреси електронної пошти», «Доступ до аватара» і «Доступ до імені користувача, імені та прізвища, статі» auths.tip.mastodon=Введіть URL спеціального екземпляра для екземпляра mastodon, який ви хочете автентифікувати за допомогою (або використовувати за замовчуванням) auths.edit=Редагувати джерело автентифікації auths.activated=Це джерело авторизації активоване @@ -3162,6 +3199,9 @@ auths.tip.gitlab_new = Зареєструйте новий додаток на % monitor.duration = Тривалість (с) users.reserved = Зарезервовано systemhooks.desc = Вебхуки автоматично сповіщають HTTP-сервер POST-запитами, коли в Forgejo відбуваються певні події. Вказані тут вебхуки спрацьовуватимуть для всіх репозиторіїв системи, тож врахуйте всі ймовірні наслідки для швидкодії. Докладніше — в посібнику з вебхуків. +dashboard.cleanup_actions = Очистити прострочені журнали й артефакти від дій +dashboard.gc_lfs = Виконати очистку сміття метаоб'єктів LFS +dashboard.new_version_hint = Вийшла %s версія Forgejo, ви використовуєте %s. Докладніше читайте у блозі. [action] @@ -3189,7 +3229,7 @@ mirror_sync_create=синхронізував нове посилання %[2]s на %[3]s із дзеркала approve_pull_request=`схвалив %[3]s#%[2]s` reject_pull_request=`запропонував зміни до %[3]s#%[2]s` -publish_release=`опублікував випуск "%[4]s" з %[3]s` +publish_release=`публікує випуск %[4]s з %[3]s` review_dismissed=`відхилив відгук від %[4]s для %[3]s#%[2]s` review_dismissed_reason=Причина: create_branch=створив гілку %[3]s в %[4]s @@ -3270,8 +3310,8 @@ arch.version.conflicts = Суперечки arch.version.replaces = Заміни arch.version.provides = Надає arch.version.groups = Група -conda.install = Аби встановити пакунок, використовуючи Conda, запустіть команду: -cargo.install = Аби встановити пакунок, використовуючи Cargo, запустіть команду: +conda.install = Аби встановити пакунок, використовуючи Conda, виконайте команду: +cargo.install = Аби встановити пакунок, використовуючи Cargo, виконайте команду: versions.view_all = Переглянути всі generic.download = Завантажте пакунок із командного рядка: details = Подробиці @@ -3279,7 +3319,7 @@ arch.version.optdepends = Необовʼязково залежить installation = Установлення details.license = Ліцензія filter.type.all = Усі -conan.install = Аби встановити пакунок, використовуючи Conan, запустіть команду: +conan.install = Аби встановити пакунок, використовуючи Conan, виконайте команду: container.layers = Шари образу details.project_site = Вебсторінка проєкту details.documentation_site = Вебсторінка документації @@ -3288,12 +3328,12 @@ requirements = Вимоги dependencies = Залежності empty.repo = Ви опублікували пакунок, але він не показаний тут? Перейдіть до налаштувань пакунків та привʼяжіть його до цього репозиторію. alpine.repository = Про репозиторій -alpine.install = Аби встановити цей пакунок, запустіть команду: -cran.install = Аби встановити пакунок, запустіть команду: +alpine.install = Аби встановити цей пакунок, виконайте команду: +cran.install = Аби встановити пакунок, виконайте команду: composer.dependencies.development = Залежності розробки container.labels.key = Ключ container.labels.value = Значення -composer.install = Аби встановити пакунок, використовуючи Composer, запустіть команду: +composer.install = Аби встановити пакунок, використовуючи Composer, виконайте команду: debian.repository.components = Складові filter.container.tagged = Відмічений filter.container.untagged = Невідмічений @@ -3303,20 +3343,20 @@ arch.pacman.sync = Синхронізуйте пакунок з pacman: arch.pacman.conf = Додайте сервер з повʼязаним дострибутивом та архітектурою до /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 数据库的文件路径。
如果以服务的方式运行 Forgejo,请输入绝对路径。 @@ -276,7 +280,7 @@ ssh_port_helper=SSH 服务器的端口号,为空则禁用它。 http_port=HTTP 服务端口 http_port_helper=Forgejos web 服务器将侦听的端口号。 app_url=基础URL -app_url_helper=用于 HTTP (S) 克隆和电子邮件通知的基本地址。 +app_url_helper=用于 HTTP(S) 克隆和电子邮件通知的基础URL。 log_root_path=日志路径 log_root_path_helper=日志文件将写入此目录。 @@ -317,7 +321,7 @@ admin_email=电子邮件地址 install_btn_confirm=立即安装 test_git_failed=无法识别 “git” 命令:%v sqlite3_not_available=当前 Forgejo 版本不支持 SQLite3。请从 %s 下载官方构建版(注:请勿下载标有 “gobuild” 的版本)。 -invalid_db_setting=数据库设置无效: %v +invalid_db_setting=数据库设置无效:%v invalid_db_table=数据库表 '%s' 无效: %v invalid_repo_path=仓库根目录设置无效:%v invalid_app_data_path=应用数据路径无效: %v @@ -325,8 +329,8 @@ run_user_not_match=运行用户名不是当前的用户名:%s -> %s internal_token_failed=生成内部令牌失败: %v secret_key_failed=生成密钥失败: %v save_config_failed=应用配置保存失败:%v -invalid_admin_setting=管理员帐户设置无效: %v -invalid_log_root_path=日志路径无效: %v +invalid_admin_setting=管理员帐户设置无效:%v +invalid_log_root_path=日志路径无效:%v default_keep_email_private=默认情况下隐藏电子邮件地址 default_keep_email_private.description=默认为新用户启用电子邮件地址隐藏,防止这些信息在注册后立即泄露。 default_allow_create_organization=默认情况下允许创建组织 @@ -536,8 +540,8 @@ release.new.text=@%[1]s 于 %[3]s 发布了 %[2]s release.title=标题: %s release.note=注释: release.downloads=下载: -release.download.zip=源代码 (ZIP) -release.download.targz=源代码 (TAR.GZ) +release.download.zip=源代码(ZIP) +release.download.targz=源代码(TAR.GZ) repo.transfer.subject_to=%s 想要将 "%s" 仓库转让给 %s repo.transfer.subject_to_you=%s 想要将 "%s" 仓库转让给你 @@ -641,7 +645,7 @@ password_complexity=密码未达到复杂程度要求: password_lowercase_one=至少一个小写字符 password_uppercase_one=至少一个大写字符 password_digit_one=至少一个数字 -password_special_one=至少一个特殊字符(标点符号,括号,引号等) +password_special_one=至少一个特殊字符(标点符号,括号,引号等) enterred_invalid_repo_name=输入的仓库名称不正确。 enterred_invalid_org_name=您输入的组织名称不正确。 enterred_invalid_owner_name=新的所有者名称无效。 @@ -653,8 +657,8 @@ cannot_add_org_to_team=组织不能被加入到团队中。 duplicate_invite_to_team=此用户已被邀请为团队成员。 organization_leave_success=您已成功离开组织 %s。 -invalid_ssh_key=无法验证您的 SSH 密钥: %s -invalid_gpg_key=无法验证您的 GPG 密钥: %s +invalid_ssh_key=无法验证您的 SSH 密钥:%s +invalid_gpg_key=无法验证您的 GPG 密钥:%s invalid_ssh_principal=无效的规则: %s must_use_public_key=您提供的密钥是私钥。不要在任何地方上传您的私钥,请改用您的公钥。 unable_verify_ssh_key=无法验证 SSH 密钥,请仔细检查是否有错误。 @@ -797,7 +801,7 @@ choose_new_avatar=选择新的头像 update_avatar=更新头像 delete_current_avatar=删除当前头像 uploaded_avatar_not_a_image=上传的文件不是一张图片。 -uploaded_avatar_is_too_big=上传的文件大小(%d KiB) 超过最大限制(%d KiB)。 +uploaded_avatar_is_too_big=上传的文件大小(%d KiB) 超过最大限制(%d KiB)。 update_avatar_success=您的头像已更新。 update_user_avatar_success=用户头像已更新。 @@ -813,7 +817,7 @@ emails=邮箱地址 manage_emails=管理邮箱地址 manage_themes=默认主题 manage_openid=OpenID 地址 -email_desc=您的主要电子邮件地址将用于通知、密码恢复,基于网页界面的Git操作(只要它不是设置为隐藏的)。 +email_desc=您的主要电子邮件地址将用于通知、密码恢复,基于网页界面的Git操作(只要它不是设置为隐藏的)。 theme_desc=此主题将在您已登录时被用于网页界面。 primary=主要 activated=已激活 @@ -938,7 +942,7 @@ access_token_deletion_desc=删除令牌将撤销程序对您账户的访问权 delete_token_success=令牌已经被删除。使用该令牌的应用将不再能够访问你的账号。 repo_and_org_access=仓库和组织访问权限 permissions_public_only=仅公开 -permissions_access_all=全部(公开、私有和受限) +permissions_access_all=全部(公开、私有和受限) select_permissions=选择权限 permission_no_access=无访问权限 permission_read=可读 @@ -1062,6 +1066,26 @@ change_username_redirect_prompt.with_cooldown.one = 旧的用户名将在%[1]d change_username_redirect_prompt.with_cooldown.few = 旧的用户名将在%[1]d天的保护期后对所有人可用,您仍可以在此期间重新认领旧的用户名。 keep_pronouns_private = 仅向已认证用户显示代词 keep_pronouns_private.description = 这将对未登录的访问者隐藏您的代词。 +quota = 配额 +quota.applies_to_org = 以下配额规则适用于此组织 +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.assets.all = 资产 +quota.sizes.assets.attachments.all = 附件 +quota.sizes.assets.attachments.issues = 工单附件 +quota.sizes.assets.attachments.releases = 版本发布附件 +quota.sizes.assets.artifacts = 制品 +quota.sizes.assets.packages.all = 软件包 +quota.sizes.wiki = 百科 +storage_overview = 存储概览 +quota.applies_to_user = 以下配额规则适用于您的账号 +quota.sizes.repos.public = 公开仓库 [repo] new_repo_helper=代码仓库包含了所有的项目文件,包括版本历史记录。已经在其他地方托管了?迁移仓库。 @@ -1096,7 +1120,7 @@ download_bundle=下载 BUNDLE generate_repo=生成仓库 generate_from=生成自 repo_desc=仓库描述 -repo_desc_helper=输入简要描述 (可选) +repo_desc_helper=输入简要描述(可选) repo_lang=仓库语言 repo_gitignore_helper=选择 .gitignore 模板 repo_gitignore_helper_desc=从常见语言的模板列表中选择忽略跟踪的文件。默认情况下,由开发或构建工具生成的特殊文件都包含在 .gitignore 中。 @@ -1129,14 +1153,14 @@ mirror_sync_on_commit=推送提交时同步 mirror_address=从 URL 克隆 mirror_address_desc=在授权框中输入必要的凭据。 mirror_address_url_invalid=URL无效。请检查您所输入的URL是否正确。 -mirror_address_protocol_invalid=提供的URL无效。只能使用http(s)://或git://地址进行镜像操作。 -mirror_lfs=大文件存储 (LFS) +mirror_address_protocol_invalid=提供的URL无效。只能使用http(s)://或git://地址进行镜像操作。 +mirror_lfs=大文件存储(LFS) mirror_lfs_desc=镜像 LFS 数据。 mirror_lfs_endpoint=LFS 网址 mirror_lfs_endpoint_desc=同步将尝试使用克隆网址来 确定 LFS 服务器。如果仓库 LFS 数据存储在其他位置,你还可以指定自定义网址。 mirror_last_synced=上次同步 -mirror_password_placeholder=(未更改) -mirror_password_blank_placeholder=(未设置) +mirror_password_placeholder=(未更改) +mirror_password_blank_placeholder=(未设置) mirror_password_help=更改用户名以删除已储存的密码。 watchers=关注者 stargazers=称赞者 @@ -1145,7 +1169,7 @@ forks=派生仓库 reactions_more=再加载 %d unit_disabled=站点管理员已禁用此仓库单元。 language_other=其它 -adopt_search=输入用户名以搜索未被收录的仓库... (留空以查找全部) +adopt_search=输入用户名以搜索未被收录的仓库…(留空以查找全部) adopt_preexisting_label=收录文件 adopt_preexisting=收录已存在的仓库 adopt_preexisting_content=从 %s 创建仓库 @@ -1177,7 +1201,7 @@ desc.internal=内部 desc.archived=已存档 desc.sha256 = SHA256 template.items=模板选项 -template.git_content=Git数据(默认分支) +template.git_content=Git数据(默认分支) template.git_hooks=Git 钩子 template.git_hooks_tooltip=你目前无法修改或删除被添加过的 Git Hook。仅当你信任模板仓库时才可以选择此项。 template.webhooks=Web 钩子 @@ -1187,8 +1211,8 @@ template.issue_labels=工单标签 template.one_item=必须至少选择一个模板项 template.invalid=必须选择一个模板仓库 -archive.title=此仓库已存档。您可以查看文件和克隆仓库,但不能推送、创建工单或合并请求。 -archive.title_date=该仓库已于 %s 存档。您可以查看文件或克隆它,但不能推送、创建工单或合并请求。 +archive.title=此仓库已存档。您可以查看文件和克隆仓库,但无法对其状态进行任何更改,例如推送和创建新工单、合并请求或评论。 +archive.title_date=此仓库已于 %s 存档。您可以查看文件或克隆它,但无法对其状态进行任何更改,例如推送和创建新工单、合并请求或评论。 archive.issue.nocomment=此仓库已存档,您不能在工单添加评论。 archive.pull.nocomment=此仓库已存档,您不能在合并请求添加评论。 @@ -1216,7 +1240,7 @@ migrate_items_merge_requests=合并请求 migrate_items_releases=版本发布 migrate_repo=迁移仓库 migrate.clone_address=从 URL 迁移/克隆 -migrate.clone_address_desc=现有仓库的 HTTP(s) 或 Git “clone” URL +migrate.clone_address_desc=现有仓库的 HTTP(s) 或 Git “clone” URL migrate.github_token_desc=由于 GitHub API 速率限制,您可以在此处放置一个或多个以逗号分隔的令牌,以加快迁移速度。 警告:滥用此功能可能会违反服务提供商的政策并导致帐户被封。 migrate.clone_local_path=或服务器本地路径 migrate.permission_denied=您没有获得导入本地仓库的权限。 @@ -1228,7 +1252,7 @@ migrate.migrate_items_options=需要访问令牌来迁移额外的内容 migrated_from=从 %[2]s 迁移 migrated_from_fake=从 %[1]s 迁移成功 migrate.migrate=从 %s 迁移 -migrate.migrating=正在从 %s 迁移... +migrate.migrating=正在从 %s 迁移… migrate.migrating_failed=从 %s 迁移失败。 migrate.migrating_failed.error=迁移失败:%s migrate.migrating_failed_no_addr=迁移失败。 @@ -1340,7 +1364,7 @@ download_file=下载文件 normal_view=普通视图 line=行 lines=行 -from_comment=(评论) +from_comment=(评论) editor.add_file=添加文件 editor.new_file=新建文件 @@ -1447,7 +1471,7 @@ ext_issues.desc=链接到外部工单跟踪系统。 projects=项目 projects.desc=在项目看板中管理工单和合并请求。 -projects.description=描述(可选) +projects.description=描述(可选) projects.description_placeholder=描述 projects.create=创建项目 projects.title=标题 @@ -1542,7 +1566,7 @@ issues.change_project_at=修改项目从 %s%s %s issues.remove_milestone_at=`%[2]s 删除了里程碑 %[1]s` issues.remove_project_at=`从 %s 项目 %s 中删除` issues.deleted_milestone=(已删除) -issues.deleted_project=`(已删除)` +issues.deleted_project=`(已删除)` issues.self_assign_at=`于 %s 指派给自己` issues.add_assignee_at=`于 %[2]s 被 %[1]s 指派` issues.remove_assignee_at=`%s 取消了指派在 %s` @@ -1710,7 +1734,7 @@ issues.unlock.title=解锁有关此问题的对话。 issues.comment_on_locked=您不能对锁定的问题发表评论。 issues.delete=删除 issues.delete.title=是否删除工单? -issues.delete.text=您真的要删除这个工单吗?(该操作将会永久删除所有内容。如果您需要保留,请关闭它) +issues.delete.text=您真的要删除这个工单吗?(该操作将会永久删除所有内容。如果您需要保留,请关闭它) issues.tracker=时间跟踪 issues.start_tracking_short=启动计时器 issues.start_tracking=开始时间跟踪 @@ -1852,7 +1876,7 @@ pulls.filter_changes_by_commit=按提交筛选 pulls.nothing_to_compare=分支内容相同,无需创建合并请求。 pulls.nothing_to_compare_have_tag = 所选分支/标签相同。 pulls.nothing_to_compare_and_allow_empty_pr=这些分支是相等的,此合并请求将为空。 -pulls.has_pull_request=这些分支之间的合并请求已存在: %[2]s#%[3]d +pulls.has_pull_request=这些分支之间的合并请求已存在:%[2]s#%[3]d pulls.create=创建合并请求 pulls.title_desc_few=请求将 %[1]d 次代码提交从 %[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 (/.well-known/openid-configuration) 来指定终点 +auths.tip.google_plus=从谷歌 API 控制台(%s) 获得 OAuth2 客户端凭据 +auths.tip.openid_connect=使用 OpenID 连接发现 URL(/.well-known/openid-configuration) 来指定终点 auths.tip.twitter=前往 %s,创建一个应用程序并确保启用了“允许此应用程序用于使用 Twitter 登录”选项 auths.tip.discord=在 %s 上注册新应用程序 auths.tip.gitea=注册一个新的 OAuth2 应用程序。可以访问 %s 查看帮助 auths.tip.yandex=在 %s 上创建一个新的应用程序。在“ Yandex.Passport API”这部分中选择以下权限:“访问电子邮件地址(Access to email address)”,“访问用户头像(Access to user avatar)”和“访问用户名,名字和姓氏,性别(Access to username, first name and surname, genderAccess to username, first name and surname, gender)” -auths.tip.mastodon=输入您想要认证的 mastodon 实例的自定义 URL (或使用默认值) +auths.tip.mastodon=输入您想要认证的 mastodon 实例的自定义 URL(或使用默认值) auths.edit=修改认证源 auths.activated=该认证源已经启用 auths.new_success=已添加身份验证 '%s'。 @@ -3352,7 +3380,7 @@ auths.deletion_success=认证源已经更新。 auths.login_source_exist=认证源 '%s' 已经存在。 auths.login_source_of_type_exist=此类型的认证源已存在。 auths.unable_to_initialize_openid=无法初始化 OpenID Connect 提供商: %s -auths.invalid_openIdConnectAutoDiscoveryURL=无效的 Auto Discovery URL (这必须是一个以 http:// 或 https://开头的有效的 URL) +auths.invalid_openIdConnectAutoDiscoveryURL=无效的 Auto Discovery URL(这必须是一个以 http:// 或 https://开头的有效的 URL) config.server_config=服务器配置 config.app_name=实例名称 @@ -3440,7 +3468,7 @@ config.mailer_sendmail_path=Sendmail 路径 config.mailer_sendmail_args=Sendmail 的额外参数 config.mailer_sendmail_timeout=Sendmail 超时 config.mailer_use_dummy=Dummy -config.test_email_placeholder=电子邮址 (例如,test@example.com) +config.test_email_placeholder=电子邮址(例如,test@example.com) config.send_test_mail=发送测试邮件 config.send_test_mail_submit=发送 config.test_mail_failed=发送测试邮件至 "%s" 时失败:%v @@ -3700,7 +3728,7 @@ alpine.repository=仓库信息 alpine.repository.branches=分支 alpine.repository.repositories=仓库管理 alpine.repository.architectures=架构 -cargo.registry=在 Cargo 配置文件中设置此注册中心(例如:~/.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" + + "\r\n" + + "\r\n" + + "--=_alternative boundary=--\r\n" + + "\r\n" + + "--=_related boundary=\r\n" + + "Content-Transfer-Encoding: base64\r\n" + + "Content-Type: image/png;\r\n" + + " name=\"image001.png\"\r\n" + + "Content-ID: <_1_2845>\r\n" + + "\r\n" + + "iVBORw0KGgoAAAANSUhEUgAAAEAAAAAiCAYAAADvVd+PAAAFLUlEQVRo3t2ZX0iTXxjHP3u35qvT\r\n" + + "6ZzhzKFuzPQq9WKQZS6FvLQf3Wh30ViBQXnViC5+LVKEiC6DjMQgCCy6NChoIKwghhcR1bJ5s5Ei\r\n" + + "LmtNs/05XYT7Vercaps/94Xn4uU95znvOc/3+XdehRBCsM1YXl7G6/Xi8Xh49uwZMzMzhEIhFhcX\r\n" + + "+fbtW87WbW1tRbVdmxZC8PTpU8bGxrh//z5fv37dcJxGo2HXrl1ZWVOhUPzybDAYUOSbAYlEgjt3\r\n" + + "7nD58mVmZ2cBkCSJ1tZWDhw4wP79+2lpaUGv16PX61Gr1Tm3RN7w/Plz0d7eLgABCKPRKJxOp3j/\r\n" + + "/r3YLuTlAD5+/ChOnDiR3HhdXZ24e/euiMfjYruRcxe4evUqV65c4fPnz6hUKrq7uzl06NA6v157\r\n" + + "19bWlrbueDzOq1evmJ6eJhQKZRww9+3blzsXWFpaEqdOnUpaPV2ZmJjYUveLFy+Ew+EQFRUVGev/\r\n" + + "WTQaTW4Y8OjRIxwOB4FAAEmS0Gq1lJWVpZwTjUaZm5vDZrPhdrs3HOP3+3E6nTx48IC1zy4uLqas\r\n" + + "rAy1Wr0uym8FnU6X3TT46dMnzp8/z82bNwHQarU0NTVRUlKScl44HMbn8wFQU1Oz7n0sFuP69etc\r\n" + + "unSJ5eVllEole/bswWAwbKk7FSRJyl4a/NnqSqWS+vp6jEZjSqskEglmZ2cJBoMIIbBYLExNTWEw\r\n" + + "GJJjvF4vDoeD6elpAKqrqzGbzVlJj5Ik/T0D/tTqS0tL+Hw+VlZWUKlUDAwMMDQ0RGlpKQArKyu4\r\n" + + "XC6uXbtGLBZDlmUaGxuprKzMajGmyrfVY7EYfr+fDx8+ANDS0sLo6ChWqzU5xu12c/r0aXw+HwqF\r\n" + + "gtraWkwmE0qlMutZSpVPq8/NzeH3+4lGo5SUlOByuRgcHESl+u8zLly4wMjICAClpaU0NTUlWZEL\r\n" + + "ZBwDfo/wDQ0NKa0ej8dZWFggEAgQiUQA6Onp4caNG5jN5l/GTk1N0dnZmTab8sqA+fl5jh07hsfj\r\n" + + "AUCWZXbv3g1AIBBYR/NoNEokEuHLly8kEgkATCYTQ0NDHD9+fFOGrKW2jfRmGxqNJr1CaHJyUuj1\r\n" + + "+j8qNiRJEp2dneL27dtidXU15TrhcFhYLJa/Km4ykeLi4tSF0O++Xl9fz5EjR9Dr9SlPtry8nKqq\r\n" + + "KsxmM1arFa1Wm7ZVQqEQDx8+5N27dznvTG022+YMmJycFEajUQBClmUxMjIiYrGYKDSwVQ3f3t4u\r\n" + + "3rx5k1LJy5cvhd1uF83NzaKoqChvFP5b6e3t/fUAMrX64uKiOHnypFAoFDtm0z9Ll14nVACRSIQz\r\n" + + "Z84wPj4OwMGDBxkbG6OxsXFT/7l37x6Dg4PMz89TJEn0VVXwT2U5dUVq1DlOXdmCsrwcVTQapaen\r\n" + + "B4/HgyzLDA8Pc+7cOSRJ2nTixYsXGR4eBsBaWsK/xmrqitTsSIyOjgpAmEwm8fbt27QCx969e3ck\r\n" + + "5TdyAfr6+gQgxsfH046ct27dEjqdbscfQG9vr1CtNRiZVMR2ux273U4hQOru7gbA5XLh9Xr5H/wn\r\n" + + "yS9WV1dFR0dHQfh0ptLR0fGjDgiHw8LpdIqGhoYdm9P/RCwWS3qXok+ePOHs2bO8fv06eZ3c39+X\r\n" + + "7AZ3MlK2wzMzMwwMDPD48WMAamtr6e/vo7m5uWBCwKYMWFhYoK2tjWAwiEaj4ejRXmw2W8oCqaAO\r\n" + + "wO1209XVhSzLHD5s+3F5UGAwGo2bt8OhUEjU1NQUdBDc8s9QMBhkYmIieVVVaLDZbHwHmmIQk3rD\r\n" + + "exgAAAAASUVORK5CYII=\r\n" + + "\r\n" + + "--=_related boundary=--\r\n" + + "\r\n" + + env, err = enmime.ReadEnvelope(strings.NewReader(mailString)) + require.NoError(t, err) + content = getContentFromMailReader(env) + assert.Equal(t, "This is the plaintext.", content.Content) + assert.Len(t, content.Attachments, 1) + assert.Equal(t, "image001.png", content.Attachments[0].Name) + expectedAttachment, err := base64.StdEncoding.DecodeString( + "iVBORw0KGgoAAAANSUhEUgAAAEAAAAAiCAYAAADvVd+PAAAFLUlEQVRo3t2ZX0iTXxjHP3u35qvT\r\n" + + "6ZzhzKFuzPQq9WKQZS6FvLQf3Wh30ViBQXnViC5+LVKEiC6DjMQgCCy6NChoIKwghhcR1bJ5s5Ei\r\n" + + "LmtNs/05XYT7Vercaps/94Xn4uU95znvOc/3+XdehRBCsM1YXl7G6/Xi8Xh49uwZMzMzhEIhFhcX\r\n" + + "+fbtW87WbW1tRbVdmxZC8PTpU8bGxrh//z5fv37dcJxGo2HXrl1ZWVOhUPzybDAYUOSbAYlEgjt3\r\n" + + "7nD58mVmZ2cBkCSJ1tZWDhw4wP79+2lpaUGv16PX61Gr1Tm3RN7w/Plz0d7eLgABCKPRKJxOp3j/\r\n" + + "/r3YLuTlAD5+/ChOnDiR3HhdXZ24e/euiMfjYruRcxe4evUqV65c4fPnz6hUKrq7uzl06NA6v157\r\n" + + "19bWlrbueDzOq1evmJ6eJhQKZRww9+3blzsXWFpaEqdOnUpaPV2ZmJjYUveLFy+Ew+EQFRUVGev/\r\n" + + "WTQaTW4Y8OjRIxwOB4FAAEmS0Gq1lJWVpZwTjUaZm5vDZrPhdrs3HOP3+3E6nTx48IC1zy4uLqas\r\n" + + "rAy1Wr0uym8FnU6X3TT46dMnzp8/z82bNwHQarU0NTVRUlKScl44HMbn8wFQU1Oz7n0sFuP69etc\r\n" + + "unSJ5eVllEole/bswWAwbKk7FSRJyl4a/NnqSqWS+vp6jEZjSqskEglmZ2cJBoMIIbBYLExNTWEw\r\n" + + "GJJjvF4vDoeD6elpAKqrqzGbzVlJj5Ik/T0D/tTqS0tL+Hw+VlZWUKlUDAwMMDQ0RGlpKQArKyu4\r\n" + + "XC6uXbtGLBZDlmUaGxuprKzMajGmyrfVY7EYfr+fDx8+ANDS0sLo6ChWqzU5xu12c/r0aXw+HwqF\r\n" + + "gtraWkwmE0qlMutZSpVPq8/NzeH3+4lGo5SUlOByuRgcHESl+u8zLly4wMjICAClpaU0NTUlWZEL\r\n" + + "ZBwDfo/wDQ0NKa0ej8dZWFggEAgQiUQA6Onp4caNG5jN5l/GTk1N0dnZmTab8sqA+fl5jh07hsfj\r\n" + + "AUCWZXbv3g1AIBBYR/NoNEokEuHLly8kEgkATCYTQ0NDHD9+fFOGrKW2jfRmGxqNJr1CaHJyUuj1\r\n" + + "+j8qNiRJEp2dneL27dtidXU15TrhcFhYLJa/Km4ykeLi4tSF0O++Xl9fz5EjR9Dr9SlPtry8nKqq\r\n" + + "KsxmM1arFa1Wm7ZVQqEQDx8+5N27dznvTG022+YMmJycFEajUQBClmUxMjIiYrGYKDSwVQ3f3t4u\r\n" + + "3rx5k1LJy5cvhd1uF83NzaKoqChvFP5b6e3t/fUAMrX64uKiOHnypFAoFDtm0z9Ll14nVACRSIQz\r\n" + + "Z84wPj4OwMGDBxkbG6OxsXFT/7l37x6Dg4PMz89TJEn0VVXwT2U5dUVq1DlOXdmCsrwcVTQapaen\r\n" + + "B4/HgyzLDA8Pc+7cOSRJ2nTixYsXGR4eBsBaWsK/xmrqitTsSIyOjgpAmEwm8fbt27QCx969e3ck\r\n" + + "5TdyAfr6+gQgxsfH046ct27dEjqdbscfQG9vr1CtNRiZVMR2ux273U4hQOru7gbA5XLh9Xr5H/wn\r\n" + + "yS9WV1dFR0dHQfh0ptLR0fGjDgiHw8LpdIqGhoYdm9P/RCwWS3qXok+ePOHs2bO8fv06eZ3c39+X\r\n" + + "7AZ3MlK2wzMzMwwMDPD48WMAamtr6e/vo7m5uWBCwKYMWFhYoK2tjWAwiEaj4ejRXmw2W8oCqaAO\r\n" + + "wO1209XVhSzLHD5s+3F5UGAwGo2bt8OhUEjU1NQUdBDc8s9QMBhkYmIieVVVaLDZbHwHmmIQk3rD\r\n" + + "exgAAAAASUVORK5CYII=\r\n") + require.NoError(t, err) + assert.Equal(t, expectedAttachment, content.Attachments[0].Content) + + // HCL Notes inlines attachments like this: without a filename. + // 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 without a filename.

\r\n" + + "\r\n" + + "\r\n" + + "--=_alternative boundary=--\r\n" + + "\r\n" + + "--=_related boundary=\r\n" + + "Content-Transfer-Encoding: base64\r\n" + + "Content-Type: image/png\r\n" + + "Content-ID: <_1_2845>\r\n" + + "\r\n" + + "iVBORw0KGgoAAAANSUhEUgAAAEAAAAAiCAYAAADvVd+PAAAFLUlEQVRo3t2ZX0iTXxjHP3u35qvT\r\n" + + "6ZzhzKFuzPQq9WKQZS6FvLQf3Wh30ViBQXnViC5+LVKEiC6DjMQgCCy6NChoIKwghhcR1bJ5s5Ei\r\n" + + "LmtNs/05XYT7Vercaps/94Xn4uU95znvOc/3+XdehRBCsM1YXl7G6/Xi8Xh49uwZMzMzhEIhFhcX\r\n" + + "+fbtW87WbW1tRbVdmxZC8PTpU8bGxrh//z5fv37dcJxGo2HXrl1ZWVOhUPzybDAYUOSbAYlEgjt3\r\n" + + "7nD58mVmZ2cBkCSJ1tZWDhw4wP79+2lpaUGv16PX61Gr1Tm3RN7w/Plz0d7eLgABCKPRKJxOp3j/\r\n" + + "/r3YLuTlAD5+/ChOnDiR3HhdXZ24e/euiMfjYruRcxe4evUqV65c4fPnz6hUKrq7uzl06NA6v157\r\n" + + "19bWlrbueDzOq1evmJ6eJhQKZRww9+3blzsXWFpaEqdOnUpaPV2ZmJjYUveLFy+Ew+EQFRUVGev/\r\n" + + "WTQaTW4Y8OjRIxwOB4FAAEmS0Gq1lJWVpZwTjUaZm5vDZrPhdrs3HOP3+3E6nTx48IC1zy4uLqas\r\n" + + "rAy1Wr0uym8FnU6X3TT46dMnzp8/z82bNwHQarU0NTVRUlKScl44HMbn8wFQU1Oz7n0sFuP69etc\r\n" + + "unSJ5eVllEole/bswWAwbKk7FSRJyl4a/NnqSqWS+vp6jEZjSqskEglmZ2cJBoMIIbBYLExNTWEw\r\n" + + "GJJjvF4vDoeD6elpAKqrqzGbzVlJj5Ik/T0D/tTqS0tL+Hw+VlZWUKlUDAwMMDQ0RGlpKQArKyu4\r\n" + + "XC6uXbtGLBZDlmUaGxuprKzMajGmyrfVY7EYfr+fDx8+ANDS0sLo6ChWqzU5xu12c/r0aXw+HwqF\r\n" + + "gtraWkwmE0qlMutZSpVPq8/NzeH3+4lGo5SUlOByuRgcHESl+u8zLly4wMjICAClpaU0NTUlWZEL\r\n" + + "ZBwDfo/wDQ0NKa0ej8dZWFggEAgQiUQA6Onp4caNG5jN5l/GTk1N0dnZmTab8sqA+fl5jh07hsfj\r\n" + + "AUCWZXbv3g1AIBBYR/NoNEokEuHLly8kEgkATCYTQ0NDHD9+fFOGrKW2jfRmGxqNJr1CaHJyUuj1\r\n" + + "+j8qNiRJEp2dneL27dtidXU15TrhcFhYLJa/Km4ykeLi4tSF0O++Xl9fz5EjR9Dr9SlPtry8nKqq\r\n" + + "KsxmM1arFa1Wm7ZVQqEQDx8+5N27dznvTG022+YMmJycFEajUQBClmUxMjIiYrGYKDSwVQ3f3t4u\r\n" + + "3rx5k1LJy5cvhd1uF83NzaKoqChvFP5b6e3t/fUAMrX64uKiOHnypFAoFDtm0z9Ll14nVACRSIQz\r\n" + + "Z84wPj4OwMGDBxkbG6OxsXFT/7l37x6Dg4PMz89TJEn0VVXwT2U5dUVq1DlOXdmCsrwcVTQapaen\r\n" + + "B4/HgyzLDA8Pc+7cOSRJ2nTixYsXGR4eBsBaWsK/xmrqitTsSIyOjgpAmEwm8fbt27QCx969e3ck\r\n" + + "5TdyAfr6+gQgxsfH046ct27dEjqdbscfQG9vr1CtNRiZVMR2ux273U4hQOru7gbA5XLh9Xr5H/wn\r\n" + + "yS9WV1dFR0dHQfh0ptLR0fGjDgiHw8LpdIqGhoYdm9P/RCwWS3qXok+ePOHs2bO8fv06eZ3c39+X\r\n" + + "7AZ3MlK2wzMzMwwMDPD48WMAamtr6e/vo7m5uWBCwKYMWFhYoK2tjWAwiEaj4ejRXmw2W8oCqaAO\r\n" + + "wO1209XVhSzLHD5s+3F5UGAwGo2bt8OhUEjU1NQUdBDc8s9QMBhkYmIieVVVaLDZbHwHmmIQk3rD\r\n" + + "exgAAAAASUVORK5CYII=\r\n" + + "\r\n" + + "--=_related boundary=--\r\n" + + "\r\n" + + env, err = enmime.ReadEnvelope(strings.NewReader(mailString)) + require.NoError(t, err) + content = getContentFromMailReader(env) + assert.Equal(t, "This is the plaintext.", content.Content) + assert.Len(t, content.Attachments, 1) + assert.Equal(t, "_1_2845.png", content.Attachments[0].Name) + expectedAttachment, err = base64.StdEncoding.DecodeString( + "iVBORw0KGgoAAAANSUhEUgAAAEAAAAAiCAYAAADvVd+PAAAFLUlEQVRo3t2ZX0iTXxjHP3u35qvT\r\n" + + "6ZzhzKFuzPQq9WKQZS6FvLQf3Wh30ViBQXnViC5+LVKEiC6DjMQgCCy6NChoIKwghhcR1bJ5s5Ei\r\n" + + "LmtNs/05XYT7Vercaps/94Xn4uU95znvOc/3+XdehRBCsM1YXl7G6/Xi8Xh49uwZMzMzhEIhFhcX\r\n" + + "+fbtW87WbW1tRbVdmxZC8PTpU8bGxrh//z5fv37dcJxGo2HXrl1ZWVOhUPzybDAYUOSbAYlEgjt3\r\n" + + "7nD58mVmZ2cBkCSJ1tZWDhw4wP79+2lpaUGv16PX61Gr1Tm3RN7w/Plz0d7eLgABCKPRKJxOp3j/\r\n" + + "/r3YLuTlAD5+/ChOnDiR3HhdXZ24e/euiMfjYruRcxe4evUqV65c4fPnz6hUKrq7uzl06NA6v157\r\n" + + "19bWlrbueDzOq1evmJ6eJhQKZRww9+3blzsXWFpaEqdOnUpaPV2ZmJjYUveLFy+Ew+EQFRUVGev/\r\n" + + "WTQaTW4Y8OjRIxwOB4FAAEmS0Gq1lJWVpZwTjUaZm5vDZrPhdrs3HOP3+3E6nTx48IC1zy4uLqas\r\n" + + "rAy1Wr0uym8FnU6X3TT46dMnzp8/z82bNwHQarU0NTVRUlKScl44HMbn8wFQU1Oz7n0sFuP69etc\r\n" + + "unSJ5eVllEole/bswWAwbKk7FSRJyl4a/NnqSqWS+vp6jEZjSqskEglmZ2cJBoMIIbBYLExNTWEw\r\n" + + "GJJjvF4vDoeD6elpAKqrqzGbzVlJj5Ik/T0D/tTqS0tL+Hw+VlZWUKlUDAwMMDQ0RGlpKQArKyu4\r\n" + + "XC6uXbtGLBZDlmUaGxuprKzMajGmyrfVY7EYfr+fDx8+ANDS0sLo6ChWqzU5xu12c/r0aXw+HwqF\r\n" + + "gtraWkwmE0qlMutZSpVPq8/NzeH3+4lGo5SUlOByuRgcHESl+u8zLly4wMjICAClpaU0NTUlWZEL\r\n" + + "ZBwDfo/wDQ0NKa0ej8dZWFggEAgQiUQA6Onp4caNG5jN5l/GTk1N0dnZmTab8sqA+fl5jh07hsfj\r\n" + + "AUCWZXbv3g1AIBBYR/NoNEokEuHLly8kEgkATCYTQ0NDHD9+fFOGrKW2jfRmGxqNJr1CaHJyUuj1\r\n" + + "+j8qNiRJEp2dneL27dtidXU15TrhcFhYLJa/Km4ykeLi4tSF0O++Xl9fz5EjR9Dr9SlPtry8nKqq\r\n" + + "KsxmM1arFa1Wm7ZVQqEQDx8+5N27dznvTG022+YMmJycFEajUQBClmUxMjIiYrGYKDSwVQ3f3t4u\r\n" + + "3rx5k1LJy5cvhd1uF83NzaKoqChvFP5b6e3t/fUAMrX64uKiOHnypFAoFDtm0z9Ll14nVACRSIQz\r\n" + + "Z84wPj4OwMGDBxkbG6OxsXFT/7l37x6Dg4PMz89TJEn0VVXwT2U5dUVq1DlOXdmCsrwcVTQapaen\r\n" + + "B4/HgyzLDA8Pc+7cOSRJ2nTixYsXGR4eBsBaWsK/xmrqitTsSIyOjgpAmEwm8fbt27QCx969e3ck\r\n" + + "5TdyAfr6+gQgxsfH046ct27dEjqdbscfQG9vr1CtNRiZVMR2ux273U4hQOru7gbA5XLh9Xr5H/wn\r\n" + + "yS9WV1dFR0dHQfh0ptLR0fGjDgiHw8LpdIqGhoYdm9P/RCwWS3qXok+ePOHs2bO8fv06eZ3c39+X\r\n" + + "7AZ3MlK2wzMzMwwMDPD48WMAamtr6e/vo7m5uWBCwKYMWFhYoK2tjWAwiEaj4ejRXmw2W8oCqaAO\r\n" + + "wO1209XVhSzLHD5s+3F5UGAwGo2bt8OhUEjU1NQUdBDc8s9QMBhkYmIieVVVaLDZbHwHmmIQk3rD\r\n" + + "exgAAAAASUVORK5CYII=\r\n") + require.NoError(t, err) + assert.Equal(t, expectedAttachment, content.Attachments[0].Content) } diff --git a/services/mailer/mail_admin_new_user_test.go b/services/mailer/mail_admin_new_user_test.go index f7f27832f9..765c8cb6c9 100644 --- a/services/mailer/mail_admin_new_user_test.go +++ b/services/mailer/mail_admin_new_user_test.go @@ -45,7 +45,7 @@ func cleanUpUsers(ctx context.Context, users []*user_model.User) { } func TestAdminNotificationMail_test(t *testing.T) { - ctx := context.Background() + ctx := t.Context() users := getTestUsers(t) diff --git a/services/mailer/mail_test.go b/services/mailer/mail_test.go index b2768a2bad..43e5d83890 100644 --- a/services/mailer/mail_test.go +++ b/services/mailer/mail_test.go @@ -79,7 +79,7 @@ func TestComposeIssueCommentMessage(t *testing.T) { recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}} msgs, err := composeIssueCommentMessages(&mailCommentContext{ - Context: context.TODO(), // TODO: use a correct context + Context: t.Context(), // TODO: use a correct context Issue: issue, Doer: doer, ActionType: activities_model.ActionCommentIssue, Content: fmt.Sprintf("test @%s %s#%d body", doer.Name, issue.Repo.FullName(), issue.Index), Comment: comment, @@ -123,7 +123,7 @@ func TestComposeIssueMessage(t *testing.T) { recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}} msgs, err := composeIssueCommentMessages(&mailCommentContext{ - Context: context.TODO(), // TODO: use a correct context + Context: t.Context(), // TODO: use a correct context Issue: issue, Doer: doer, ActionType: activities_model.ActionCreateIssue, Content: "test body", }, "en-US", recipients, false, "issue create") @@ -168,7 +168,7 @@ func TestMailerIssueTemplate(t *testing.T) { t.Helper() recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}} - ctx.Context = context.Background() + ctx.Context = t.Context() fromMention := false msgs, err := composeIssueCommentMessages(ctx, "en-US", recipients, fromMention, "TestMailerIssueTemplate") require.NoError(t, err) @@ -266,14 +266,14 @@ func TestTemplateSelection(t *testing.T) { } msg := testComposeIssueCommentMessage(t, &mailCommentContext{ - Context: context.TODO(), // TODO: use a correct context + Context: t.Context(), // TODO: use a correct context Issue: issue, Doer: doer, ActionType: activities_model.ActionCreateIssue, Content: "test body", }, recipients, false, "TestTemplateSelection") expect(t, msg, "issue/new/subject", "issue/new/body") msg = testComposeIssueCommentMessage(t, &mailCommentContext{ - Context: context.TODO(), // TODO: use a correct context + Context: t.Context(), // TODO: use a correct context Issue: issue, Doer: doer, ActionType: activities_model.ActionCommentIssue, Content: "test body", Comment: comment, }, recipients, false, "TestTemplateSelection") @@ -282,14 +282,14 @@ func TestTemplateSelection(t *testing.T) { pull := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2, Repo: repo, Poster: doer}) comment = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 4, Issue: pull}) msg = testComposeIssueCommentMessage(t, &mailCommentContext{ - Context: context.TODO(), // TODO: use a correct context + Context: t.Context(), // TODO: use a correct context Issue: pull, Doer: doer, ActionType: activities_model.ActionCommentPull, Content: "test body", Comment: comment, }, recipients, false, "TestTemplateSelection") expect(t, msg, "pull/comment/subject", "pull/comment/body") msg = testComposeIssueCommentMessage(t, &mailCommentContext{ - Context: context.TODO(), // TODO: use a correct context + Context: t.Context(), // TODO: use a correct context Issue: issue, Doer: doer, ActionType: activities_model.ActionCloseIssue, Content: "test body", Comment: comment, }, recipients, false, "TestTemplateSelection") @@ -309,7 +309,7 @@ func TestTemplateServices(t *testing.T) { recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}} msg := testComposeIssueCommentMessage(t, &mailCommentContext{ - Context: context.TODO(), // TODO: use a correct context + Context: t.Context(), // TODO: use a correct context Issue: issue, Doer: doer, ActionType: actionType, Content: "test body", Comment: comment, }, recipients, fromMention, "TestTemplateServices") @@ -353,7 +353,7 @@ func TestGenerateAdditionalHeaders(t *testing.T) { defer MockMailSettings(nil)() doer, _, issue, _ := prepareMailerTest(t) - ctx := &mailCommentContext{Context: context.TODO() /* TODO: use a correct context */, Issue: issue, Doer: doer} + ctx := &mailCommentContext{Context: t.Context() /* TODO: use a correct context */, Issue: issue, Doer: doer} recipient := &user_model.User{Name: "test", Email: "test@gitea.com"} headers := generateAdditionalHeaders(ctx, "dummy-reason", recipient) diff --git a/services/markup/processorhelper_test.go b/services/markup/processorhelper_test.go index fafde746d2..4d103048b5 100644 --- a/services/markup/processorhelper_test.go +++ b/services/markup/processorhelper_test.go @@ -4,7 +4,6 @@ package markup import ( - "context" "net/http" "net/http/httptest" "testing" @@ -33,10 +32,10 @@ func TestProcessorHelper(t *testing.T) { unittest.AssertCount(t, &user.User{Name: userNoSuch}, 0) // when using general context, use user's visibility to check - assert.True(t, ProcessorHelper().IsUsernameMentionable(context.Background(), userPublic)) - assert.False(t, ProcessorHelper().IsUsernameMentionable(context.Background(), userLimited)) - assert.False(t, ProcessorHelper().IsUsernameMentionable(context.Background(), userPrivate)) - assert.False(t, ProcessorHelper().IsUsernameMentionable(context.Background(), userNoSuch)) + assert.True(t, ProcessorHelper().IsUsernameMentionable(t.Context(), userPublic)) + assert.False(t, ProcessorHelper().IsUsernameMentionable(t.Context(), userLimited)) + assert.False(t, ProcessorHelper().IsUsernameMentionable(t.Context(), userPrivate)) + assert.False(t, ProcessorHelper().IsUsernameMentionable(t.Context(), userNoSuch)) // when using web context, use user.IsUserVisibleToViewer to check req, err := http.NewRequest("GET", "/", nil) diff --git a/services/migrations/codebase_test.go b/services/migrations/codebase_test.go index 23626d16d7..fbd4e70143 100644 --- a/services/migrations/codebase_test.go +++ b/services/migrations/codebase_test.go @@ -4,7 +4,6 @@ package migrations import ( - "context" "net/url" "os" "testing" @@ -33,7 +32,7 @@ func TestCodebaseDownloadRepo(t *testing.T) { } factory := &CodebaseDownloaderFactory{} - downloader, err := factory.New(context.Background(), base.MigrateOptions{ + downloader, err := factory.New(t.Context(), base.MigrateOptions{ CloneAddr: u.String(), AuthUsername: apiUser, AuthPassword: apiPassword, diff --git a/services/migrations/gitea_downloader_test.go b/services/migrations/gitea_downloader_test.go index 48306d7996..b9ddb9b431 100644 --- a/services/migrations/gitea_downloader_test.go +++ b/services/migrations/gitea_downloader_test.go @@ -4,7 +4,6 @@ package migrations import ( - "context" "os" "sort" "testing" @@ -24,7 +23,7 @@ func TestGiteaDownloadRepo(t *testing.T) { server := unittest.NewMockWebServer(t, "https://gitea.com", fixturePath, giteaToken != "") defer server.Close() - downloader, err := NewGiteaDownloader(context.Background(), server.URL, "gitea/test_repo", "", "", giteaToken) + downloader, err := NewGiteaDownloader(t.Context(), server.URL, "gitea/test_repo", "", "", giteaToken) if downloader == nil { t.Fatal("NewGitlabDownloader is nil") } diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index ad193b2253..e01f4664ba 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -5,7 +5,6 @@ package migrations import ( - "context" "fmt" "os" "path/filepath" @@ -40,7 +39,7 @@ func TestGiteaUploadRepo(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) var ( - ctx = context.Background() + ctx = t.Context() downloader = NewGithubDownloaderV3(ctx, "https://github.com", "", "", "", "go-xorm", "builder") repoName = "builder-" + time.Now().Format("2006-01-02-15-04-05") uploader = NewGiteaLocalUploader(graceful.GetManager().HammerContext(), user, user.Name, repoName) @@ -133,7 +132,7 @@ func TestGiteaUploadRemapLocalUser(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) repoName := "migrated" - uploader := NewGiteaLocalUploader(context.Background(), doer, doer.Name, repoName) + uploader := NewGiteaLocalUploader(t.Context(), doer, doer.Name, repoName) // call remapLocalUser uploader.sameApp = true @@ -182,7 +181,7 @@ func TestGiteaUploadRemapExternalUser(t *testing.T) { doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) repoName := "migrated" - uploader := NewGiteaLocalUploader(context.Background(), doer, doer.Name, repoName) + uploader := NewGiteaLocalUploader(t.Context(), doer, doer.Name, repoName) uploader.gitServiceType = structs.GiteaService // call remapExternalUser uploader.sameApp = false @@ -301,7 +300,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) { require.NoError(t, err) toRepoName := "migrated" - uploader := NewGiteaLocalUploader(context.Background(), fromRepoOwner, fromRepoOwner.Name, toRepoName) + uploader := NewGiteaLocalUploader(t.Context(), fromRepoOwner, fromRepoOwner.Name, toRepoName) uploader.gitServiceType = structs.GiteaService require.NoError(t, uploader.CreateRepo(&base.Repository{ Description: "description", diff --git a/services/migrations/github_test.go b/services/migrations/github_test.go index 9270d5d4c4..080fd497ca 100644 --- a/services/migrations/github_test.go +++ b/services/migrations/github_test.go @@ -5,7 +5,6 @@ package migrations import ( - "context" "os" "testing" "time" @@ -25,7 +24,7 @@ func TestGitHubDownloadRepo(t *testing.T) { server := unittest.NewMockWebServer(t, "https://api.github.com", fixturePath, token != "") defer server.Close() - downloader := NewGithubDownloaderV3(context.Background(), server.URL, "", "", token, "go-gitea", "test_repo") + downloader := NewGithubDownloaderV3(t.Context(), server.URL, "", "", token, "go-gitea", "test_repo") err := downloader.RefreshRate() require.NoError(t, err) diff --git a/services/migrations/gitlab.go b/services/migrations/gitlab.go index 8ae8fa9a23..78f2a59119 100644 --- a/services/migrations/gitlab.go +++ b/services/migrations/gitlab.go @@ -21,7 +21,7 @@ import ( base "code.gitea.io/gitea/modules/migration" "code.gitea.io/gitea/modules/structs" - "gitlab.com/gitlab-org/api/client-go" + gitlab "gitlab.com/gitlab-org/api/client-go" ) var ( diff --git a/services/migrations/gitlab_test.go b/services/migrations/gitlab_test.go index 9344311656..f1404d946d 100644 --- a/services/migrations/gitlab_test.go +++ b/services/migrations/gitlab_test.go @@ -4,7 +4,6 @@ package migrations import ( - "context" "fmt" "net/http" "net/http/httptest" @@ -19,7 +18,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gitlab.com/gitlab-org/api/client-go" + gitlab "gitlab.com/gitlab-org/api/client-go" ) func TestGitlabDownloadRepo(t *testing.T) { @@ -31,7 +30,7 @@ func TestGitlabDownloadRepo(t *testing.T) { server := unittest.NewMockWebServer(t, "https://gitlab.com", fixturePath, gitlabPersonalAccessToken != "") defer server.Close() - downloader, err := NewGitlabDownloader(context.Background(), server.URL, "forgejo/test_repo", "", "", gitlabPersonalAccessToken) + downloader, err := NewGitlabDownloader(t.Context(), server.URL, "forgejo/test_repo", "", "", gitlabPersonalAccessToken) if err != nil { t.Fatalf("NewGitlabDownloader is nil: %v", err) } @@ -331,7 +330,7 @@ func TestGitlabSkippedIssueNumber(t *testing.T) { server := unittest.NewMockWebServer(t, "https://gitlab.com", fixturePath, gitlabPersonalAccessToken != "") defer server.Close() - downloader, err := NewGitlabDownloader(context.Background(), server.URL, "troyengel/archbuild", "", "", gitlabPersonalAccessToken) + downloader, err := NewGitlabDownloader(t.Context(), server.URL, "troyengel/archbuild", "", "", gitlabPersonalAccessToken) if err != nil { t.Fatalf("NewGitlabDownloader is nil: %v", err) } @@ -454,7 +453,7 @@ func TestGitlabGetReviews(t *testing.T) { repoID := 1324 downloader := &GitlabDownloader{ - ctx: context.Background(), + ctx: t.Context(), client: client, repoID: repoID, } diff --git a/services/migrations/gogs_test.go b/services/migrations/gogs_test.go index 6c511a2bb5..450aeab5ef 100644 --- a/services/migrations/gogs_test.go +++ b/services/migrations/gogs_test.go @@ -4,7 +4,6 @@ package migrations import ( - "context" "net/http" "os" "testing" @@ -30,7 +29,7 @@ func TestGogsDownloadRepo(t *testing.T) { return } - downloader := NewGogsDownloader(context.Background(), "https://try.gogs.io", "", "", gogsPersonalAccessToken, "lunnytest", "TESTREPO") + downloader := NewGogsDownloader(t.Context(), "https://try.gogs.io", "", "", gogsPersonalAccessToken, "lunnytest", "TESTREPO") repo, err := downloader.GetRepoInfo() require.NoError(t, err) @@ -207,7 +206,7 @@ func TestGogsDownloaderFactory_New(t *testing.T) { AuthPassword: tt.args.AuthPassword, AuthToken: tt.args.AuthToken, } - got, err := f.New(context.Background(), opts) + got, err := f.New(t.Context(), opts) if (err != nil) != tt.wantErr { t.Errorf("GogsDownloaderFactory.New() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/services/migrations/onedev_test.go b/services/migrations/onedev_test.go index 80c26130cc..46e3eb8d18 100644 --- a/services/migrations/onedev_test.go +++ b/services/migrations/onedev_test.go @@ -4,7 +4,6 @@ package migrations import ( - "context" "net/http" "net/url" "testing" @@ -23,7 +22,7 @@ func TestOneDevDownloadRepo(t *testing.T) { } u, _ := url.Parse("https://code.onedev.io") - downloader := NewOneDevDownloader(context.Background(), u, "", "", "go-gitea-test_repo") + downloader := NewOneDevDownloader(t.Context(), u, "", "", "go-gitea-test_repo") if err != nil { t.Fatalf("NewOneDevDownloader is nil: %v", err) } diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index b180cf498f..085995df4f 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -135,7 +135,9 @@ func parseRemoteUpdateOutput(output, remoteName string) []*mirrorSyncResult { case strings.HasPrefix(lines[i], " - "): // Delete reference isTag := !strings.HasPrefix(refName, remoteName+"/") var refFullName git.RefName - if isTag { + if strings.HasPrefix(refName, "refs/") { + refFullName = git.RefName(refName) + } else if isTag { refFullName = git.RefNameFromTag(refName) } else { refFullName = git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/")) @@ -158,8 +160,15 @@ func parseRemoteUpdateOutput(output, remoteName string) []*mirrorSyncResult { log.Error("Expect two SHAs but not what found: %q", lines[i]) continue } + var refFullName git.RefName + if strings.HasPrefix(refName, "refs/") { + refFullName = git.RefName(refName) + } else { + refFullName = git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/")) + } + results = append(results, &mirrorSyncResult{ - refName: git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/")), + refName: refFullName, oldCommitID: shas[0], newCommitID: shas[1], }) diff --git a/services/mirror/mirror_test.go b/services/mirror/mirror_test.go index e26204e2ec..76632b6872 100644 --- a/services/mirror/mirror_test.go +++ b/services/mirror/mirror_test.go @@ -17,11 +17,13 @@ func Test_parseRemoteUpdateOutput(t *testing.T) { - [deleted] (none) -> tag1 + f895a1e...957a993 test2 -> origin/test2 (forced update) 957a993..a87ba5f test3 -> origin/test3 - * [new ref] refs/pull/27/merge -> refs/pull/27/merge - * [new ref] refs/pull/516/head -> refs/pull/516/head - ` + * [new ref] refs/pull/26595/head -> refs/pull/26595/head + * [new ref] refs/pull/26595/merge -> refs/pull/26595/merge + e0639e38fb..6db2410489 refs/pull/25873/head -> refs/pull/25873/head + + 1c97ebc746...976d27d52f refs/pull/25873/merge -> refs/pull/25873/merge (forced update) +` results := parseRemoteUpdateOutput(output, "origin") - assert.Len(t, results, 8) + assert.Len(t, results, 10) assert.EqualValues(t, "refs/tags/v0.1.8", results[0].refName.String()) assert.EqualValues(t, gitShortEmptySha, results[0].oldCommitID) assert.EqualValues(t, "", results[0].newCommitID) @@ -46,11 +48,19 @@ func Test_parseRemoteUpdateOutput(t *testing.T) { assert.EqualValues(t, "957a993", results[5].oldCommitID) assert.EqualValues(t, "a87ba5f", results[5].newCommitID) - assert.EqualValues(t, "refs/pull/27/merge", results[6].refName.String()) + assert.EqualValues(t, "refs/pull/26595/head", results[6].refName.String()) assert.EqualValues(t, gitShortEmptySha, results[6].oldCommitID) assert.EqualValues(t, "", results[6].newCommitID) - assert.EqualValues(t, "refs/pull/516/head", results[7].refName.String()) + assert.EqualValues(t, "refs/pull/26595/merge", results[7].refName.String()) assert.EqualValues(t, gitShortEmptySha, results[7].oldCommitID) assert.EqualValues(t, "", results[7].newCommitID) + + assert.EqualValues(t, "refs/pull/25873/head", results[8].refName.String()) + assert.EqualValues(t, "e0639e38fb", results[8].oldCommitID) + assert.EqualValues(t, "6db2410489", results[8].newCommitID) + + assert.EqualValues(t, "refs/pull/25873/merge", results[9].refName.String()) + assert.EqualValues(t, "1c97ebc746", results[9].oldCommitID) + assert.EqualValues(t, "976d27d52f", results[9].newCommitID) } diff --git a/services/packages/package_update.go b/services/packages/package_update.go new file mode 100644 index 0000000000..4a22ee7a62 --- /dev/null +++ b/services/packages/package_update.go @@ -0,0 +1,79 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package packages + +import ( + "context" + "fmt" + + org_model "code.gitea.io/gitea/models/organization" + packages_model "code.gitea.io/gitea/models/packages" + access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/util" +) + +func LinkToRepository(ctx context.Context, pkg *packages_model.Package, repo *repo_model.Repository, doer *user_model.User) error { + if pkg.OwnerID != repo.OwnerID { + return util.ErrPermissionDenied + } + if pkg.RepoID > 0 { + return util.ErrInvalidArgument + } + + perms, err := access_model.GetUserRepoPermission(ctx, repo, doer) + if err != nil { + return fmt.Errorf("error getting permissions for user %d on repository %d: %w", doer.ID, repo.ID, err) + } + if !perms.CanWrite(unit.TypePackages) { + return util.ErrPermissionDenied + } + + if err := packages_model.SetRepositoryLink(ctx, pkg.ID, repo.ID); err != nil { + return fmt.Errorf("error while linking package '%v' to repo '%v' : %w", pkg.Name, repo.FullName(), err) + } + return nil +} + +func UnlinkFromRepository(ctx context.Context, pkg *packages_model.Package, doer *user_model.User) error { + if pkg.RepoID == 0 { + return util.ErrInvalidArgument + } + + repo, err := repo_model.GetRepositoryByID(ctx, pkg.RepoID) + if err != nil && !repo_model.IsErrRepoNotExist(err) { + return fmt.Errorf("error getting repository %d: %w", pkg.RepoID, err) + } + if err == nil { + perms, err := access_model.GetUserRepoPermission(ctx, repo, doer) + if err != nil { + return fmt.Errorf("error getting permissions for user %d on repository %d: %w", doer.ID, repo.ID, err) + } + if !perms.CanWrite(unit.TypePackages) { + return util.ErrPermissionDenied + } + } + + user, err := user_model.GetUserByID(ctx, pkg.OwnerID) + if err != nil { + return err + } + if !doer.IsAdmin { + if !user.IsOrganization() { + if doer.ID != pkg.OwnerID { + return fmt.Errorf("no permission to unlink package '%v' from its repository, or packages are disabled", pkg.Name) + } + } else { + isOrgAdmin, err := org_model.OrgFromUser(user).IsOrgAdmin(ctx, doer.ID) + if err != nil { + return err + } else if !isOrgAdmin { + return fmt.Errorf("no permission to unlink package '%v' from its repository, or packages are disabled", pkg.Name) + } + } + } + return packages_model.UnlinkRepository(ctx, pkg.ID) +} diff --git a/services/pull/check_test.go b/services/pull/check_test.go index b99cf01ee1..dfb8ff708b 100644 --- a/services/pull/check_test.go +++ b/services/pull/check_test.go @@ -5,7 +5,6 @@ package pull import ( - "context" "strconv" "testing" "time" @@ -34,7 +33,7 @@ func TestPullRequest_AddToTaskQueue(t *testing.T) { cfg, err := setting.GetQueueSettings(setting.CfgProvider, "pr_patch_checker") require.NoError(t, err) - prPatchCheckerQueue, err = queue.NewWorkerPoolQueueWithContext(context.Background(), "pr_patch_checker", cfg, testHandler, true) + prPatchCheckerQueue, err = queue.NewWorkerPoolQueueWithContext(t.Context(), "pr_patch_checker", cfg, testHandler, true) require.NoError(t, err) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) diff --git a/services/repository/delete.go b/services/repository/delete.go index 6e84194750..09213e5c65 100644 --- a/services/repository/delete.go +++ b/services/repository/delete.go @@ -16,6 +16,7 @@ import ( git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" + packages_model "code.gitea.io/gitea/models/packages" access_model "code.gitea.io/gitea/models/perm/access" project_model "code.gitea.io/gitea/models/project" repo_model "code.gitea.io/gitea/models/repo" @@ -28,6 +29,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + federation_service "code.gitea.io/gitea/services/federation" "xorm.io/builder" ) @@ -289,6 +291,15 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID return err } + if err := federation_service.DeleteFollowingRepos(ctx, repo.ID); err != nil { + return err + } + + // unlink packages linked to this repository + if err = packages_model.UnlinkRepositoryFromAllPackages(ctx, repoID); err != nil { + return err + } + if err = committer.Commit(); err != nil { return err } diff --git a/services/repository/lfs_test.go b/services/repository/lfs_test.go index a0c01dff8f..838386d845 100644 --- a/services/repository/lfs_test.go +++ b/services/repository/lfs_test.go @@ -5,7 +5,6 @@ package repository_test import ( "bytes" - "context" "testing" "time" @@ -41,7 +40,7 @@ func TestGarbageCollectLFSMetaObjects(t *testing.T) { lfsOid := storeObjectInRepo(t, repo.ID, &lfsContent) // gc - err = repo_service.GarbageCollectLFSMetaObjects(context.Background(), repo_service.GarbageCollectLFSMetaObjectsOptions{ + err = repo_service.GarbageCollectLFSMetaObjects(t.Context(), repo_service.GarbageCollectLFSMetaObjectsOptions{ AutoFix: true, OlderThan: time.Now().Add(7 * 24 * time.Hour).Add(5 * 24 * time.Hour), UpdatedLessRecentlyThan: time.Time{}, // ensure that the models/fixtures/lfs_meta_object.yml objects are considered as well diff --git a/services/repository/repository.go b/services/repository/repository.go index 116e24151b..35bcdfd528 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" - packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" system_model "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/models/unit" @@ -22,7 +21,6 @@ import ( repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" - federation_service "code.gitea.io/gitea/services/federation" notify_service "code.gitea.io/gitea/services/notify" pull_service "code.gitea.io/gitea/services/pull" ) @@ -64,15 +62,7 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod notify_service.DeleteRepository(ctx, doer, repo) } - if err := DeleteRepositoryDirectly(ctx, doer, repo.ID); err != nil { - return err - } - - if err := federation_service.DeleteFollowingRepos(ctx, repo.ID); err != nil { - return err - } - - return packages_model.UnlinkRepositoryFromAllPackages(ctx, repo.ID) + return DeleteRepositoryDirectly(ctx, doer, repo.ID) } // PushCreateRepo creates a repository when a new repository is pushed to an appropriate namespace diff --git a/services/user/block_test.go b/services/user/block_test.go index f9e95ed7f7..13959e56b4 100644 --- a/services/user/block_test.go +++ b/services/user/block_test.go @@ -8,6 +8,7 @@ import ( model "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -89,4 +90,24 @@ func TestBlockUser(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3, OwnerID: blockedUser.ID}) assert.Equal(t, repo_model.RepositoryReady, repo.Status) }) + + t.Run("Issues", func(t *testing.T) { + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + defer user_model.UnblockUser(db.DefaultContext, doer.ID, blockedUser.ID) + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerID: doer.ID}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4, RepoID: repo.ID}, "is_closed = true") + + _, err := issues_model.ChangeIssueStatus(db.DefaultContext, issue, blockedUser, false) + require.NoError(t, err) + + _, err = issues_model.ChangeIssueStatus(db.DefaultContext, issue, doer, true) + require.NoError(t, err) + + require.NoError(t, BlockUser(db.DefaultContext, doer.ID, blockedUser.ID)) + + _, err = issues_model.ChangeIssueStatus(db.DefaultContext, issue, blockedUser, false) + require.Error(t, err) + }) } diff --git a/services/webhook/default_test.go b/services/webhook/default_test.go index f3e2848659..7056e77b47 100644 --- a/services/webhook/default_test.go +++ b/services/webhook/default_test.go @@ -4,7 +4,6 @@ package webhook import ( - "context" "testing" webhook_model "code.gitea.io/gitea/models/webhook" @@ -45,7 +44,7 @@ func TestGiteaPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := dh.NewRequest(context.Background(), hook, task) + req, reqBody, err := dh.NewRequest(t.Context(), hook, task) require.NoError(t, err) require.NotNil(t, req) require.NotNil(t, reqBody) @@ -74,7 +73,7 @@ func TestGiteaPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := dh.NewRequest(context.Background(), hook, task) + req, reqBody, err := dh.NewRequest(t.Context(), hook, task) require.NoError(t, err) require.NotNil(t, req) require.NotNil(t, reqBody) @@ -103,7 +102,7 @@ func TestGiteaPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := dh.NewRequest(context.Background(), hook, task) + req, reqBody, err := dh.NewRequest(t.Context(), hook, task) require.NoError(t, err) require.NotNil(t, req) require.NotNil(t, reqBody) @@ -148,7 +147,7 @@ func TestForgejoPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := dh.NewRequest(context.Background(), hook, task) + req, reqBody, err := dh.NewRequest(t.Context(), hook, task) require.NoError(t, err) require.NotNil(t, req) require.NotNil(t, reqBody) @@ -177,7 +176,7 @@ func TestForgejoPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := dh.NewRequest(context.Background(), hook, task) + req, reqBody, err := dh.NewRequest(t.Context(), hook, task) require.NoError(t, err) require.NotNil(t, req) require.NotNil(t, reqBody) @@ -206,7 +205,7 @@ func TestForgejoPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := dh.NewRequest(context.Background(), hook, task) + req, reqBody, err := dh.NewRequest(t.Context(), hook, task) require.NoError(t, err) require.NotNil(t, req) require.NotNil(t, reqBody) diff --git a/services/webhook/deliver_test.go b/services/webhook/deliver_test.go index 17b7bf7f3e..c6d1cb60dc 100644 --- a/services/webhook/deliver_test.go +++ b/services/webhook/deliver_test.go @@ -4,12 +4,10 @@ package webhook import ( - "context" "io" "net/http" "net/http/httptest" "net/url" - "os" "strings" "testing" "time" @@ -19,6 +17,7 @@ import ( webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/hostmatcher" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" @@ -26,16 +25,9 @@ import ( ) func TestWebhookProxy(t *testing.T) { - oldWebhook := setting.Webhook - oldHTTPProxy := os.Getenv("http_proxy") - oldHTTPSProxy := os.Getenv("https_proxy") - t.Cleanup(func() { - setting.Webhook = oldWebhook - os.Setenv("http_proxy", oldHTTPProxy) - os.Setenv("https_proxy", oldHTTPSProxy) - }) - os.Unsetenv("http_proxy") - os.Unsetenv("https_proxy") + defer test.MockProtect(&setting.Webhook)() + t.Setenv("http_proxy", "") + t.Setenv("https_proxy", "") setting.Webhook.ProxyURL = "http://localhost:8080" setting.Webhook.ProxyURLFixed, _ = url.Parse(setting.Webhook.ProxyURL) @@ -124,7 +116,7 @@ func TestWebhookDeliverAuthorizationHeader(t *testing.T) { require.NoError(t, err) assert.NotNil(t, hookTask) - require.NoError(t, Deliver(context.Background(), hookTask)) + require.NoError(t, Deliver(t.Context(), hookTask)) select { case <-done: case <-time.After(5 * time.Second): @@ -190,7 +182,7 @@ func TestWebhookDeliverHookTask(t *testing.T) { require.NoError(t, err) assert.NotNil(t, hookTask) - require.NoError(t, Deliver(context.Background(), hookTask)) + require.NoError(t, Deliver(t.Context(), hookTask)) select { case <-done: case <-time.After(5 * time.Second): @@ -216,7 +208,7 @@ func TestWebhookDeliverHookTask(t *testing.T) { require.NoError(t, err) assert.NotNil(t, hookTask) - require.NoError(t, Deliver(context.Background(), hookTask)) + require.NoError(t, Deliver(t.Context(), hookTask)) select { case <-done: case <-time.After(5 * time.Second): @@ -317,7 +309,7 @@ func TestWebhookDeliverSpecificTypes(t *testing.T) { require.NoError(t, err) assert.NotNil(t, hookTask) - require.NoError(t, Deliver(context.Background(), hookTask)) + require.NoError(t, Deliver(t.Context(), hookTask)) select { case gotBody := <-hc.gotBody: assert.NotEqual(t, string(data), string(gotBody), "request body must be different from the event payload") diff --git a/services/webhook/dingtalk_test.go b/services/webhook/dingtalk_test.go index d0a2d48908..762d29dddc 100644 --- a/services/webhook/dingtalk_test.go +++ b/services/webhook/dingtalk_test.go @@ -4,7 +4,6 @@ package webhook import ( - "context" "net/url" "testing" @@ -236,7 +235,7 @@ func TestDingTalkJSONPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := dingtalkHandler{}.NewRequest(context.Background(), hook, task) + req, reqBody, err := dingtalkHandler{}.NewRequest(t.Context(), hook, task) require.NotNil(t, req) require.NotNil(t, reqBody) require.NoError(t, err) diff --git a/services/webhook/discord_test.go b/services/webhook/discord_test.go index 4edd06bd76..e0bb2225f7 100644 --- a/services/webhook/discord_test.go +++ b/services/webhook/discord_test.go @@ -4,7 +4,6 @@ package webhook import ( - "context" "testing" webhook_model "code.gitea.io/gitea/models/webhook" @@ -346,7 +345,7 @@ func TestDiscordJSONPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := discordHandler{}.NewRequest(context.Background(), hook, task) + req, reqBody, err := discordHandler{}.NewRequest(t.Context(), hook, task) require.NotNil(t, req) require.NotNil(t, reqBody) require.NoError(t, err) diff --git a/services/webhook/feishu_test.go b/services/webhook/feishu_test.go index 9744571b39..614e0f1ef4 100644 --- a/services/webhook/feishu_test.go +++ b/services/webhook/feishu_test.go @@ -4,7 +4,6 @@ package webhook import ( - "context" "testing" webhook_model "code.gitea.io/gitea/models/webhook" @@ -177,7 +176,7 @@ func TestFeishuJSONPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := feishuHandler{}.NewRequest(context.Background(), hook, task) + req, reqBody, err := feishuHandler{}.NewRequest(t.Context(), hook, task) require.NotNil(t, req) require.NotNil(t, reqBody) require.NoError(t, err) diff --git a/services/webhook/matrix_test.go b/services/webhook/matrix_test.go index a941486f9f..46e0041a34 100644 --- a/services/webhook/matrix_test.go +++ b/services/webhook/matrix_test.go @@ -4,7 +4,6 @@ package webhook import ( - "context" "testing" webhook_model "code.gitea.io/gitea/models/webhook" @@ -211,7 +210,7 @@ func TestMatrixJSONPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := matrixHandler{}.NewRequest(context.Background(), hook, task) + req, reqBody, err := matrixHandler{}.NewRequest(t.Context(), hook, task) require.NotNil(t, req) require.NotNil(t, reqBody) require.NoError(t, err) diff --git a/services/webhook/msteams_test.go b/services/webhook/msteams_test.go index a97e9f3de3..d9a9724e5b 100644 --- a/services/webhook/msteams_test.go +++ b/services/webhook/msteams_test.go @@ -4,7 +4,6 @@ package webhook import ( - "context" "testing" webhook_model "code.gitea.io/gitea/models/webhook" @@ -439,7 +438,7 @@ func TestMSTeamsJSONPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := msteamsHandler{}.NewRequest(context.Background(), hook, task) + req, reqBody, err := msteamsHandler{}.NewRequest(t.Context(), hook, task) require.NotNil(t, req) require.NotNil(t, reqBody) require.NoError(t, err) diff --git a/services/webhook/packagist_test.go b/services/webhook/packagist_test.go index 320c1c85a1..0f696f1b99 100644 --- a/services/webhook/packagist_test.go +++ b/services/webhook/packagist_test.go @@ -4,7 +4,6 @@ package webhook import ( - "context" "fmt" "testing" @@ -53,7 +52,7 @@ func TestPackagistPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := packagistHandler{}.NewRequest(context.Background(), hook, task) + req, reqBody, err := packagistHandler{}.NewRequest(t.Context(), hook, task) require.NotNil(t, req) require.NotNil(t, reqBody) require.NoError(t, err) diff --git a/services/webhook/slack_test.go b/services/webhook/slack_test.go index 155b091f9e..ecc11d541f 100644 --- a/services/webhook/slack_test.go +++ b/services/webhook/slack_test.go @@ -4,7 +4,6 @@ package webhook import ( - "context" "testing" webhook_model "code.gitea.io/gitea/models/webhook" @@ -178,7 +177,7 @@ func TestSlackJSONPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := slackHandler{}.NewRequest(context.Background(), hook, task) + req, reqBody, err := slackHandler{}.NewRequest(t.Context(), hook, task) require.NotNil(t, req) require.NotNil(t, reqBody) require.NoError(t, err) diff --git a/services/webhook/sourcehut/builds_test.go b/services/webhook/sourcehut/builds_test.go index 5b16f08c09..689c369a7f 100644 --- a/services/webhook/sourcehut/builds_test.go +++ b/services/webhook/sourcehut/builds_test.go @@ -4,7 +4,6 @@ package sourcehut import ( - "context" "strings" "testing" @@ -26,7 +25,7 @@ func gitInit(t testing.TB) { return } t.Cleanup(test.MockVariableValue(&setting.Git.HomePath, t.TempDir())) - require.NoError(t, git.InitSimple(context.Background())) + require.NoError(t, git.InitSimple(t.Context())) } func TestSourcehutBuildsPayload(t *testing.T) { @@ -372,7 +371,7 @@ func TestSourcehutJSONPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := BuildsHandler{}.NewRequest(context.Background(), hook, task) + req, reqBody, err := BuildsHandler{}.NewRequest(t.Context(), hook, task) require.NoError(t, err) require.NotNil(t, req) require.NotNil(t, reqBody) diff --git a/services/webhook/telegram_test.go b/services/webhook/telegram_test.go index 4f5663da41..85a62f7615 100644 --- a/services/webhook/telegram_test.go +++ b/services/webhook/telegram_test.go @@ -4,7 +4,6 @@ package webhook import ( - "context" "testing" webhook_model "code.gitea.io/gitea/models/webhook" @@ -194,7 +193,7 @@ func TestTelegramJSONPayload(t *testing.T) { PayloadVersion: 2, } - req, reqBody, err := telegramHandler{}.NewRequest(context.Background(), hook, task) + req, reqBody, err := telegramHandler{}.NewRequest(t.Context(), hook, task) require.NotNil(t, req) require.NotNil(t, reqBody) require.NoError(t, err) diff --git a/templates/admin/auth/edit.tmpl b/templates/admin/auth/edit.tmpl index 34d52ed224..1ca5573cae 100644 --- a/templates/admin/auth/edit.tmpl +++ b/templates/admin/auth/edit.tmpl @@ -380,51 +380,6 @@ {{end}} - - {{if .Source.IsSSPI}} - {{$cfg:=.Source.Cfg}} -
-
- - -

{{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"}}

-
- {{end}} {{if .Source.IsLDAP}}
diff --git a/templates/admin/auth/new.tmpl b/templates/admin/auth/new.tmpl index c70bd3ba43..12d3798278 100644 --- a/templates/admin/auth/new.tmpl +++ b/templates/admin/auth/new.tmpl @@ -50,9 +50,6 @@ {{template "admin/auth/source/oauth" .}} - - {{template "admin/auth/source/sspi" .}} -
diff --git a/templates/admin/auth/source/sspi.tmpl b/templates/admin/auth/source/sspi.tmpl deleted file mode 100644 index 6a3f00f9a8..0000000000 --- a/templates/admin/auth/source/sspi.tmpl +++ /dev/null @@ -1,43 +0,0 @@ -
-
-
- - -

{{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"}}

-
-
diff --git a/templates/admin/repo/unadopted.tmpl b/templates/admin/repo/unadopted.tmpl index a33cb43a2f..a95f6b5120 100644 --- a/templates/admin/repo/unadopted.tmpl +++ b/templates/admin/repo/unadopted.tmpl @@ -54,7 +54,7 @@ - {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "primary")}} + {{template "base/modal_actions_confirm"}}
diff --git a/templates/admin/user/view_details.tmpl b/templates/admin/user/view_details.tmpl index be2f32b5ec..c394b4bd3d 100644 --- a/templates/admin/user/view_details.tmpl +++ b/templates/admin/user/view_details.tmpl @@ -26,6 +26,14 @@ {{svg "octicon-x"}} {{end}}
+
+ {{ctx.Locale.Tr "admin.users.prohibit_login"}}: + {{if .User.ProhibitLogin}} + {{svg "octicon-check"}} + {{else}} + {{svg "octicon-x"}} + {{end}} +
{{ctx.Locale.Tr "admin.users.restricted"}}: {{if .User.IsRestricted}} diff --git a/templates/admin/user/view_emails.tmpl b/templates/admin/user/view_emails.tmpl index 22ce305a88..7e77206f1c 100644 --- a/templates/admin/user/view_emails.tmpl +++ b/templates/admin/user/view_emails.tmpl @@ -3,7 +3,7 @@
- {{.Email}} + {{.Email}} {{if .IsPrimary}}
{{ctx.Locale.Tr "settings.primary"}}
{{end}} diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index ba17222f9b..0c13f9e844 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -194,11 +194,13 @@ {{else}} {{if .ShowRegistrationButton}} - {{svg "octicon-person"}} {{ctx.Locale.Tr "register"}} + {{svg "octicon-person" 16 "tw-mr-1"}} + {{ctx.Locale.Tr "register"}} {{end}} - {{svg "octicon-sign-in"}} {{ctx.Locale.Tr "sign_in"}} + {{svg "octicon-sign-in" 16 "tw-mr-1"}} + {{ctx.Locale.Tr "sign_in"}} {{end}}
diff --git a/templates/base/head_script.tmpl b/templates/base/head_script.tmpl index 22e08e9c8f..d2774010b6 100644 --- a/templates/base/head_script.tmpl +++ b/templates/base/head_script.tmpl @@ -42,6 +42,7 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly. modal_confirm: {{ctx.Locale.Tr "modal.confirm"}}, modal_cancel: {{ctx.Locale.Tr "modal.cancel"}}, more_items: {{ctx.Locale.Tr "more_items"}}, + incorrect_root_url: {{ctx.Locale.Tr "incorrect_root_url" AppUrl}}, }, }; {{/* in case some pages don't render the pageData, we make sure it is an object to prevent null access */}} diff --git a/templates/base/modal_actions_confirm.tmpl b/templates/base/modal_actions_confirm.tmpl index c44320deff..8c4e346088 100644 --- a/templates/base/modal_actions_confirm.tmpl +++ b/templates/base/modal_actions_confirm.tmpl @@ -1,7 +1,6 @@ {{/* Two buttons (negative, positive): * ModalButtonTypes: "yes" (default) or "confirm" -* ModalButtonColors: "primary" (default) / "blue" / "yellow" * ModalButtonCancelText * ModalButtonOkText @@ -23,13 +22,7 @@ The ".ok.button" and ".cancel.button" selectors are also used by Fomantic Modal {{if .ModalButtonCancelText}}{{$textNegitive = .ModalButtonCancelText}}{{end}} {{if .ModalButtonOkText}}{{$textPositive = .ModalButtonOkText}}{{end}} - {{$stylePositive := "primary"}} - {{if eq .ModalButtonColors "blue"}} - {{$stylePositive = "blue"}} - {{else if eq .ModalButtonColors "yellow"}} - {{$stylePositive = "yellow"}} - {{end}} - + {{end}}
diff --git a/templates/base/paginate.tmpl b/templates/base/paginate.tmpl index 2ca72f6a34..253892c009 100644 --- a/templates/base/paginate.tmpl +++ b/templates/base/paginate.tmpl @@ -17,7 +17,7 @@ {{if eq .Num -1}} ... {{else}} - {{.Num}} + {{.Num}} {{end}} {{end}} diff --git a/templates/devtest/fomantic-modal.tmpl b/templates/devtest/fomantic-modal.tmpl index 5cd36721a7..5b94afc4f1 100644 --- a/templates/devtest/fomantic-modal.tmpl +++ b/templates/devtest/fomantic-modal.tmpl @@ -54,18 +54,6 @@ {{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
- - - - + {{else if eq .Type 38}} +
+ {{svg "octicon-list-unordered" 16}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + + {{template "shared/user/authorlink" .Poster}} + {{$createdStr}} + +
    + + + {{if and .Aggregator.PrevClosed (not .Aggregator.IsClosed)}} +
  • + {{svg "octicon-dot-fill"}} + {{if .Issue.IsPull}} + {{ctx.Locale.Tr "repo.pulls.reopened_at" "" ""}} + {{else}} + {{ctx.Locale.Tr "repo.issues.reopened_at" "" ""}} + {{end}} +
  • + {{else if and (not .Aggregator.PrevClosed) .Aggregator.IsClosed}} + {{svg "octicon-circle-slash"}} +
  • + {{if .Issue.IsPull}} + {{ctx.Locale.Tr "repo.pulls.closed_at" "" ""}} + {{else}} + {{ctx.Locale.Tr "repo.issues.closed_at" "" ""}} + {{end}} +
  • + {{end}} + + + {{if or .AddedLabels .RemovedLabels}} +
  • + {{svg "octicon-tag" 20}} + {{if and .AddedLabels (not .RemovedLabels)}} + {{ctx.Locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels $.Context ctx.Locale .AddedLabels $.RepoLink .Issue.IsPull) ""}} + {{else if and (not .AddedLabels) .RemovedLabels}} + {{ctx.Locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels $.Context ctx.Locale .RemovedLabels $.RepoLink .Issue.IsPull) ""}} + {{else}} + {{ctx.Locale.Tr "repo.issues.add_remove_labels" (RenderLabels $.Context ctx.Locale .AddedLabels $.RepoLink .Issue.IsPull) (RenderLabels $.Context ctx.Locale .RemovedLabels $.RepoLink .Issue.IsPull) ""}} + {{end}} +
  • + {{end}} + + {{if or .AddedRequestReview .RemovedRequestReview}} +
  • + {{svg "octicon-tag" 20}} + + + {{if and (eq (len .RemovedRequestReview) 1) (eq (len .AddedRequestReview) 0) (eq ((index .RemovedRequestReview 0).ID) .PosterID) (eq ((index .RemovedRequestReview 0).Type) "user")}} + {{ctx.Locale.Tr "repo.issues.review.remove_review_request_self" ""}} + {{else if and .AddedRequestReview (not .RemovedRequestReview)}} + {{ctx.Locale.TrN (len .AddedRequestReview) "repo.issues.review.add_review_request" "repo.issues.review.add_review_requests" (RenderReviewRequest .AddedRequestReview) ""}} + {{else if and (not .AddedRequestReview) .RemovedRequestReview}} + {{ctx.Locale.TrN (len .RemovedRequestReview) "repo.issues.review.remove_review_request" "repo.issues.review.remove_review_requests" (RenderReviewRequest .RemovedRequestReview) ""}} + {{else}} + {{ctx.Locale.Tr "repo.issues.review.add_remove_review_requests" (RenderReviewRequest .AddedRequestReview) (RenderReviewRequest .RemovedRequestReview) ""}} + {{end}} + + +
  • + {{end}} +
+
+
{{end}} {{end}} {{end}} diff --git a/templates/repo/issue/view_content/sidebar/projects.tmpl b/templates/repo/issue/view_content/sidebar/projects.tmpl index 91d75f3bd9..3fd58b3340 100644 --- a/templates/repo/issue/view_content/sidebar/projects.tmpl +++ b/templates/repo/issue/view_content/sidebar/projects.tmpl @@ -25,7 +25,7 @@
{{range .OpenProjects}} - {{svg .IconName 18 "tw-mr-2"}}{{.Title}} + {{svg .IconName 16 "tw-mr-2"}}{{.Title}} {{end}} {{end}} @@ -36,7 +36,7 @@
{{range .ClosedProjects}} - {{svg .IconName 18 "tw-mr-2"}}{{.Title}} + {{svg .IconName 16 "tw-mr-2"}}{{.Title}} {{end}} {{end}} @@ -47,7 +47,7 @@ diff --git a/templates/repo/settings/lfs.tmpl b/templates/repo/settings/lfs.tmpl index 069fdecb33..4928b1f5fd 100644 --- a/templates/repo/settings/lfs.tmpl +++ b/templates/repo/settings/lfs.tmpl @@ -44,7 +44,7 @@

{{$.CsrfTokenHtml}} - {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "primary")}} + {{template "base/modal_actions_confirm"}} diff --git a/templates/shared/combomarkdowneditor.tmpl b/templates/shared/combomarkdowneditor.tmpl index 0620cca65f..1ea22660f7 100644 --- a/templates/shared/combomarkdowneditor.tmpl +++ b/templates/shared/combomarkdowneditor.tmpl @@ -29,7 +29,7 @@ Template Attributes:
{{svg "octicon-quote"}} {{svg "octicon-code"}} - {{svg "octicon-link"}} +
{{svg "octicon-list-unordered"}} @@ -88,4 +88,30 @@ Template Attributes:
+ + diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index 6318d02139..53575d82b2 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -45,7 +45,7 @@ {{if .NumComments}} {{end}} @@ -145,6 +145,11 @@ + {{else}} +
+

{{ctx.Locale.Tr "repo.issues.filter_no_results"}}

+

{{ctx.Locale.Tr "repo.issues.filter_no_results_placeholder"}}

+
{{end}} {{if .IssueIndexerUnavailable}}
diff --git a/templates/shared/quota_overview.tmpl b/templates/shared/quota_overview.tmpl new file mode 100644 index 0000000000..cb8b57d724 --- /dev/null +++ b/templates/shared/quota_overview.tmpl @@ -0,0 +1,32 @@ +

+ {{ctx.Locale.Tr "settings.quota"}} +

+
+

{{if .ContextUser.IsOrganization}}{{ctx.Locale.Tr "settings.quota.applies_to_org"}}{{else}}{{ctx.Locale.Tr "settings.quota.applies_to_user"}}{{end}}:

+ {{range $group := .QuotaGroups}} +

{{$group.Name}}

+
+ {{range $rule := .Rules}} +
+ + {{if $rule.Acceptable ($.SizeUsed)}} + {{svg "octicon-check-circle-fill" 16 "text green"}} + {{$rule.Name}} + {{else}} + {{svg "octicon-alert-fill" 16 "text red"}} + + {{$rule.Name}} – {{ctx.Locale.Tr "settings.quota.rule.exceeded"}} + + {{end}} + + {{ctx.Locale.TrSize ($rule.Sum $.SizeUsed)}} / {{if eq $rule.Limit -1 -}}{{ctx.Locale.Tr "settings.quota.rule.no_limit"}}{{else}}{{ctx.Locale.TrSize $rule.Limit}}{{end}} +
+
+ {{range $idx, $subject := .Subjects}} +
+ {{end}} +
+ {{end}} +
+ {{end}} +
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 037ee48b8c..7ff9825bbb 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4159,6 +4159,93 @@ } } }, + "/packages/{owner}/{type}/{name}/-/link/{repo_name}": { + "post": { + "tags": [ + "package" + ], + "summary": "Link a package to a repository", + "operationId": "linkPackage", + "parameters": [ + { + "type": "string", + "description": "owner of the package", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "type of the package", + "name": "type", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the package", + "name": "name", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repository to link.", + "name": "repo_name", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "$ref": "#/responses/empty" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, + "/packages/{owner}/{type}/{name}/-/unlink": { + "post": { + "tags": [ + "package" + ], + "summary": "Unlink a package from a repository", + "operationId": "unlinkPackage", + "parameters": [ + { + "type": "string", + "description": "owner of the package", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "type of the package", + "name": "type", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the package", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "$ref": "#/responses/empty" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/packages/{owner}/{type}/{name}/{version}": { "get": { "produces": [ diff --git a/templates/user/auth/oauth_container.tmpl b/templates/user/auth/oauth_container.tmpl index c20273be14..7531320394 100644 --- a/templates/user/auth/oauth_container.tmpl +++ b/templates/user/auth/oauth_container.tmpl @@ -19,12 +19,6 @@ {{ctx.Locale.Tr "auth.sign_in_openid"}} {{end}} - {{if .EnableSSPI}} - - {{svg "fontawesome-windows"}} -  SSPI - - {{end}}
diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl index 8ae50bf385..e9fbb7a5b9 100644 --- a/templates/user/dashboard/feeds.tmpl +++ b/templates/user/dashboard/feeds.tmpl @@ -107,7 +107,7 @@ {{else if .GetOpType.InActions "create_pull_request"}} {{RenderIssueTitle ctx (index .GetIssueInfos 1) (.Repo.ComposeMetas ctx)}} {{else if .GetOpType.InActions "comment_issue" "approve_pull_request" "reject_pull_request" "comment_pull"}} - {{RenderIssueTitle ctx (.GetIssueTitle ctx) (.Repo.ComposeMetas ctx)}} + {{(.GetIssueTitle ctx) | RenderEmoji $.Context | RenderCodeBlock}} {{$comment := index .GetIssueInfos 1}} {{if $comment}}
{{RenderMarkdownToHtml ctx $comment}}
diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 3d046110ae..b269c63b37 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -73,7 +73,7 @@ {{range .Milestones}}
  • -

    +

    {{.Repo.FullName}} diff --git a/templates/user/settings/appearance.tmpl b/templates/user/settings/appearance.tmpl index 2aaf24adca..df4d6f3999 100644 --- a/templates/user/settings/appearance.tmpl +++ b/templates/user/settings/appearance.tmpl @@ -19,15 +19,15 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}}
    - {{range $i,$a := .AllThemes}} - {{if eq $.SignedUser.Theme $a}}{{$a}}{{end}} - {{end}} + {{- range $i,$a := .AllThemes -}} + {{if eq $.SignedUser.Theme $a}}{{call $.ThemeName $a}}{{end}} + {{- end -}}
    diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl index 2aeabc6903..a5912c9e0f 100644 --- a/templates/user/settings/applications.tmpl +++ b/templates/user/settings/applications.tmpl @@ -40,6 +40,10 @@

    +
    + + diff --git a/templates/user/settings/navbar.tmpl b/templates/user/settings/navbar.tmpl index d45d89ee9f..eadf2ee9e5 100644 --- a/templates/user/settings/navbar.tmpl +++ b/templates/user/settings/navbar.tmpl @@ -51,6 +51,11 @@ {{ctx.Locale.Tr "settings.repos"}} + {{if .EnableQuota}} + + {{ctx.Locale.Tr "settings.storage_overview"}} + + {{end}} {{ctx.Locale.Tr "settings.blocked_users"}} diff --git a/templates/user/settings/profile.tmpl b/templates/user/settings/profile.tmpl index 503a977158..3bc8800a76 100644 --- a/templates/user/settings/profile.tmpl +++ b/templates/user/settings/profile.tmpl @@ -30,38 +30,14 @@ -