diff --git a/.forgejo/workflows-composite/apt-install-from/action.yaml b/.forgejo/workflows-composite/apt-install-from/action.yaml index 615e7cb184..ab55883a11 100644 --- a/.forgejo/workflows-composite/apt-install-from/action.yaml +++ b/.forgejo/workflows-composite/apt-install-from/action.yaml @@ -13,6 +13,8 @@ runs: run: | export DEBIAN_FRONTEND=noninteractive echo "deb http://deb.debian.org/debian/ ${RELEASE} main" > "/etc/apt/sources.list.d/${RELEASE}.list" + wget -O- http://neuro.debian.net/lists/bookworm.de-fzj.libre | tee /etc/apt/sources.list.d/neurodebian.sources.list + apt-key adv --recv-keys --keyserver hkps://keyserver.ubuntu.com 0xA5D32F012649A5A9 env: RELEASE: ${{inputs.release}} - name: install packages @@ -24,6 +26,7 @@ runs: - name: remove temporary package list to prevent using it in other steps run: | rm "/etc/apt/sources.list.d/${RELEASE}.list" + rm "/etc/apt/sources.list.d/neurodebian.sources.list" apt-get update -qq env: RELEASE: ${{inputs.release}} diff --git a/.forgejo/workflows-composite/build-backend/action.yaml b/.forgejo/workflows-composite/build-backend/action.yaml index ada372b834..68a99ffaf9 100644 --- a/.forgejo/workflows-composite/build-backend/action.yaml +++ b/.forgejo/workflows-composite/build-backend/action.yaml @@ -3,7 +3,7 @@ runs: steps: - run: | su forgejo -c 'make deps-backend' - - uses: actions/cache@v4 + - uses: https://data.forgejo.org/actions/cache@v4 id: cache-backend with: path: ${{github.workspace}}/gitea diff --git a/.forgejo/workflows-composite/setup-cache-go/action.yaml b/.forgejo/workflows-composite/setup-cache-go/action.yaml index 67372d9f36..1e0425fd0e 100644 --- a/.forgejo/workflows-composite/setup-cache-go/action.yaml +++ b/.forgejo/workflows-composite/setup-cache-go/action.yaml @@ -48,7 +48,7 @@ runs: - name: "Restore Go dependencies from cache or mark for later caching" id: cache-deps - uses: actions/cache@v4 + uses: https://data.forgejo.org/actions/cache@v4 with: key: setup-cache-go-deps-${{ runner.os }}-${{ inputs.username }}-${{ steps.go-version.outputs.go_version }}-${{ hashFiles('go.sum', 'go.mod') }} restore-keys: | diff --git a/.forgejo/workflows-composite/setup-env/action.yaml b/.forgejo/workflows-composite/setup-env/action.yaml index 28216e9b8d..f19569a137 100644 --- a/.forgejo/workflows-composite/setup-env/action.yaml +++ b/.forgejo/workflows-composite/setup-env/action.yaml @@ -19,7 +19,7 @@ runs: set -ex toolchain=$(grep -oP '(?<=toolchain ).+' go.mod) version=$(go version | cut -d' ' -f3) - if [ "$toolchain" != "$version" ]; then - echo "go version mismatch: $toolchain <> $version" + if dpkg --compare-versions ${version#go} lt ${toolchain#go}; then + echo "go version too low: $toolchain >= $version" exit 1 fi diff --git a/.forgejo/workflows/build-oci-image.yml b/.forgejo/workflows/build-oci-image.yml new file mode 100644 index 0000000000..8e843b41ee --- /dev/null +++ b/.forgejo/workflows/build-oci-image.yml @@ -0,0 +1,41 @@ +on: + push: + branches: + - 'forgejo' + tags: + - '*-git-annex*' + +jobs: + build-oci-image: + runs-on: docker + strategy: + matrix: + type: ["rootful", "rootless"] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # fetch the full history so that the Forgejo version is determined properly + - name: Determine registry and username + id: determine-registry-and-username + run: | + echo "registry=${GITHUB_SERVER_URL#https://}" >> "$GITHUB_OUTPUT" + echo "username=${GITHUB_REPOSITORY%/*}" >> "$GITHUB_OUTPUT" + - name: Install Docker + run: curl -fsSL https://get.docker.com | sh + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + registry: ${{ steps.determine-registry-and-username.outputs.registry }} + username: ${{ steps.determine-registry-and-username.outputs.username }} + password: ${{ secrets.REGISTRY_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ (matrix.type == 'rootful' && 'Dockerfile') || (matrix.type == 'rootless' && 'Dockerfile.rootless') }} + push: true + tags: ${{ steps.determine-registry-and-username.outputs.registry }}/${{ github.repository }}:${{ github.ref_name }}${{ (matrix.type == 'rootful' && ' ') || (matrix.type == 'rootless' && '-rootless') }} diff --git a/.forgejo/workflows/build-release-integration.yml b/.forgejo/workflows/build-release-integration.yml index 6410915644..1af6d567dd 100644 --- a/.forgejo/workflows/build-release-integration.yml +++ b/.forgejo/workflows/build-release-integration.yml @@ -25,7 +25,7 @@ jobs: if: vars.ROLE == 'forgejo-coding' runs-on: lxc-bookworm steps: - - uses: actions/checkout@v4 + - uses: https://data.forgejo.org/actions/checkout@v4 - id: forgejo uses: https://data.forgejo.org/actions/setup-forgejo@v2.0.4 diff --git a/.forgejo/workflows/build-release.yml b/.forgejo/workflows/build-release.yml index 433b085969..0d7f94c5a6 100644 --- a/.forgejo/workflows/build-release.yml +++ b/.forgejo/workflows/build-release.yml @@ -33,7 +33,7 @@ jobs: # root is used for testing, allow it if: vars.ROLE == 'forgejo-integration' || github.repository_owner == 'root' steps: - - uses: actions/checkout@v4 + - uses: https://data.forgejo.org/actions/checkout@v4 with: fetch-depth: 0 @@ -164,7 +164,7 @@ jobs: - name: build container & release if: ${{ secrets.TOKEN != '' }} - uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.2.1 + uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.1 with: forgejo: "${{ env.GITHUB_SERVER_URL }}" owner: "${{ env.GITHUB_REPOSITORY_OWNER }}" @@ -183,7 +183,7 @@ jobs: - name: build rootless container if: ${{ secrets.TOKEN != '' }} - uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.2.1 + uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.1 with: forgejo: "${{ env.GITHUB_SERVER_URL }}" owner: "${{ env.GITHUB_REPOSITORY_OWNER }}" diff --git a/.forgejo/workflows/cascade-setup-end-to-end.yml b/.forgejo/workflows/cascade-setup-end-to-end.yml index 710cd27ba4..bcc7821f4f 100644 --- a/.forgejo/workflows/cascade-setup-end-to-end.yml +++ b/.forgejo/workflows/cascade-setup-end-to-end.yml @@ -37,11 +37,11 @@ jobs: container: image: data.forgejo.org/oci/node:20-bookworm steps: - - uses: actions/checkout@v4 + - uses: https://data.forgejo.org/actions/checkout@v4 with: fetch-depth: '0' show-progress: 'false' - - uses: https://code.forgejo.org/actions/cascading-pr@v2.2.0 + - uses: https://data.forgejo.org/actions/cascading-pr@v2.2.0 with: origin-url: ${{ env.GITHUB_SERVER_URL }} origin-repo: ${{ github.repository }} diff --git a/.forgejo/workflows/publish-release.yml b/.forgejo/workflows/publish-release.yml index cbc8455a99..93ad54de1c 100644 --- a/.forgejo/workflows/publish-release.yml +++ b/.forgejo/workflows/publish-release.yml @@ -39,10 +39,10 @@ jobs: runs-on: lxc-bookworm if: vars.DOER != '' && vars.FORGEJO != '' && vars.TO_OWNER != '' && vars.FROM_OWNER != '' && secrets.TOKEN != '' steps: - - uses: actions/checkout@v4 + - uses: https://data.forgejo.org/actions/checkout@v4 - name: copy & sign - uses: https://data.forgejo.org/forgejo/forgejo-build-publish/publish@v5.2.1 + uses: https://data.forgejo.org/forgejo/forgejo-build-publish/publish@v5.3.1 with: from-forgejo: ${{ vars.FORGEJO }} to-forgejo: ${{ vars.FORGEJO }} diff --git a/.forgejo/workflows/testing.yml b/.forgejo/workflows/testing.yml index eb3163d3ae..a93ca7879c 100644 --- a/.forgejo/workflows/testing.yml +++ b/.forgejo/workflows/testing.yml @@ -10,7 +10,6 @@ on: jobs: backend-checks: - if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' runs-on: docker container: image: 'data.forgejo.org/oci/node:20-bookworm' @@ -27,7 +26,6 @@ jobs: - run: su forgejo -c 'make --always-make -j$(nproc) lint-backend tidy-check swagger-check fmt-check swagger-validate' # ensure the "go-licenses" make target runs - uses: ./.forgejo/workflows-composite/build-backend frontend-checks: - if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' runs-on: docker container: image: 'data.forgejo.org/oci/node:20-bookworm' @@ -46,7 +44,7 @@ jobs: apt-get update -qq apt-get -q install -qq -y zstd - name: "Cache frontend build for playwright testing" - uses: actions/cache/save@v4 + uses: https://data.forgejo.org/actions/cache/save@v4 with: path: ${{github.workspace}}/public/assets key: frontend-build-${{ github.sha }} @@ -104,7 +102,7 @@ jobs: fetch-depth: 20 - uses: ./.forgejo/workflows-composite/setup-env - name: "Restore frontend build" - uses: actions/cache/restore@v4 + uses: https://data.forgejo.org/actions/cache/restore@v4 id: cache-frontend with: path: ${{github.workspace}}/public/assets @@ -176,7 +174,6 @@ jobs: TAGS: bindata TEST_REDIS_SERVER: cacher:${{ matrix.cacher.port }} test-mysql: - if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' runs-on: docker needs: [backend-checks, frontend-checks] container: @@ -199,15 +196,13 @@ jobs: - name: install dependencies & git >= 2.42 uses: ./.forgejo/workflows-composite/apt-install-from with: - packages: git git-lfs + packages: git git-annex-standalone git-lfs - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-mysql-migration test-mysql' - timeout-minutes: 120 env: USE_REPO_TEST_DIR: 1 test-pgsql: - if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' runs-on: docker needs: [backend-checks, frontend-checks] container: @@ -236,17 +231,15 @@ jobs: - name: install dependencies & git >= 2.42 uses: ./.forgejo/workflows-composite/apt-install-from with: - packages: git git-lfs + packages: git git-annex-standalone git-lfs - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-pgsql-migration test-pgsql' - timeout-minutes: 120 env: RACE_ENABLED: true USE_REPO_TEST_DIR: 1 TEST_LDAP: 1 test-sqlite: - if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' runs-on: docker needs: [backend-checks, frontend-checks] container: @@ -258,25 +251,21 @@ jobs: - name: install dependencies & git >= 2.42 uses: ./.forgejo/workflows-composite/apt-install-from with: - packages: git git-lfs + packages: git git-annex-standalone git-lfs - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-sqlite-migration test-sqlite' - timeout-minutes: 120 env: TAGS: sqlite sqlite_unlock_notify RACE_ENABLED: true TEST_TAGS: sqlite sqlite_unlock_notify USE_REPO_TEST_DIR: 1 security-check: - if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' runs-on: docker needs: - test-sqlite - test-pgsql - test-mysql - - test-remote-cacher - - test-unit container: image: 'data.forgejo.org/oci/node:20-bookworm' options: --tmpfs /tmp:exec,noatime diff --git a/.gitignore b/.gitignore index 744577248d..f040fdaf37 100644 --- a/.gitignore +++ b/.gitignore @@ -72,6 +72,7 @@ cpu.out /tests/e2e/reports /tests/e2e/test-artifacts /tests/e2e/test-snapshots +/tests/e2e/.auth /tests/*.ini /tests/**/*.git/**/*.sample /node_modules diff --git a/Dockerfile b/Dockerfile index ae21a0821e..1f33f5d57f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ -FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/xx AS xx +FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/xx AS xx -FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/golang:1.23-alpine3.20 as build-env +FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.23-alpine3.20 as build-env ARG GOPROXY ENV GOPROXY=${GOPROXY:-direct} @@ -51,7 +51,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \ /go/src/code.gitea.io/gitea/environment-to-ini RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete -FROM code.forgejo.org/oci/alpine:3.20 +FROM data.forgejo.org/oci/alpine:3.20 ARG RELEASE_VERSION LABEL maintainer="contact@forgejo.org" \ org.opencontainers.image.authors="Forgejo" \ @@ -78,6 +78,7 @@ RUN apk --no-cache add \ sqlite \ su-exec \ gnupg \ + git-annex \ && rm -rf /var/cache/apk/* RUN addgroup \ diff --git a/Dockerfile.rootless b/Dockerfile.rootless index c5d6a13f35..63fb88a7a7 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,6 +1,6 @@ -FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/xx AS xx +FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/xx AS xx -FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/golang:1.23-alpine3.20 as build-env +FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.23-alpine3.20 as build-env ARG GOPROXY ENV GOPROXY=${GOPROXY:-direct} @@ -49,7 +49,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \ /go/src/code.gitea.io/gitea/environment-to-ini RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete -FROM code.forgejo.org/oci/alpine:3.20 +FROM data.forgejo.org/oci/alpine:3.20 LABEL maintainer="contact@forgejo.org" \ org.opencontainers.image.authors="Forgejo" \ org.opencontainers.image.url="https://forgejo.org" \ @@ -71,6 +71,7 @@ RUN apk --no-cache add \ git \ curl \ gnupg \ + git-annex \ && rm -rf /var/cache/apk/* RUN addgroup \ diff --git a/Makefile b/Makefile index a9de57e523..561d674198 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ self := $(location) @tmpdir=`mktemp --tmpdir -d` ; \ echo Using temporary directory $$tmpdir for test repositories ; \ USE_REPO_TEST_DIR= $(MAKE) -f $(self) --no-print-directory REPO_TEST_DIR=$$tmpdir/ $@ ; \ - STATUS=$$? ; rm -r "$$tmpdir" ; exit $$STATUS + STATUS=$$? ; chmod -R +w "$$tmpdir" && rm -r "$$tmpdir" ; exit $$STATUS else @@ -104,7 +104,7 @@ else FORGEJO_VERSION_API ?= $(GITEA_VERSION)+${GITEA_COMPATIBILITY} else # drop the "g" prefix prepended by git describe to the commit hash - FORGEJO_VERSION ?= $(shell git describe --exclude '*-test' --tags --always | sed 's/^v//' | sed 's/\-g/-/')+${GITEA_COMPATIBILITY} + FORGEJO_VERSION ?= $(shell git describe --exclude '*-test' --tags --always | sed 's/^v//' | sed 's/\-g/-/2')+${GITEA_COMPATIBILITY} endif endif FORGEJO_VERSION_MAJOR=$(shell echo $(FORGEJO_VERSION) | sed -e 's/\..*//') diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 1d19440d59..73ad852082 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -84,6 +84,11 @@ "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", + "licenseText": "BSD 3-Clause License\n\nCopyright (c) 2018, go-fed\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, { "name": "github.com/42wim/sshsig", "path": "github.com/42wim/sshsig/LICENSE", @@ -292,7 +297,7 @@ { "name": "github.com/cyphar/filepath-securejoin", "path": "github.com/cyphar/filepath-securejoin/LICENSE", - "licenseText": "Copyright (C) 2014-2015 Docker Inc \u0026 Go Authors. All rights reserved.\nCopyright (C) 2017 SUSE LLC. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "licenseText": "Copyright (C) 2014-2015 Docker Inc \u0026 Go Authors. All rights reserved.\nCopyright (C) 2017-2024 SUSE LLC. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { "name": "github.com/davecgh/go-spew/spew", diff --git a/build/lint-locale.go b/build/lint-locale.go index c49e236938..0b5e501701 100644 --- a/build/lint-locale.go +++ b/build/lint-locale.go @@ -59,9 +59,9 @@ func initRemoveTags() { oldnew := []string{} for _, el := range []string{ "email@example.com", "correu@example.com", "epasts@domens.lv", "email@exemplo.com", "eposta@ornek.com", "email@példa.hu", "email@esempio.it", - "user", "utente", "lietotājs", "gebruiker", "usuário", "Benutzer", "Bruker", + "user", "utente", "lietotājs", "gebruiker", "usuário", "Benutzer", "Bruker", "bruger", "użytkownik", "server", "servidor", "kiszolgáló", "serveris", - "label", "etichetta", "etiķete", "rótulo", "Label", "utilizador", + "label", "etichetta", "etiķete", "rótulo", "Label", "utilizador", "etiket", "iezīme", "etykieta", } { oldnew = append(oldnew, "<"+el+">", "REPLACED-TAG") } diff --git a/cmd/serv.go b/cmd/serv.go index db67e36fa3..57804034e2 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -38,6 +38,7 @@ import ( const ( lfsAuthenticateVerb = "git-lfs-authenticate" + gitAnnexShellVerb = "git-annex-shell" ) // CmdServ represents the available serv sub-command. @@ -79,6 +80,7 @@ var ( "git-upload-archive": perm.AccessModeRead, "git-receive-pack": perm.AccessModeWrite, lfsAuthenticateVerb: perm.AccessModeNone, + gitAnnexShellVerb: perm.AccessModeNone, // annex permissions are enforced by GIT_ANNEX_SHELL_READONLY, rather than the Gitea API } alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`) ) @@ -212,6 +214,28 @@ func runServ(c *cli.Context) error { } } + if verb == gitAnnexShellVerb { + if !setting.Annex.Enabled { + return fail(ctx, "Unknown git command", "git-annex request over SSH denied, git-annex support is disabled") + } + + if len(words) < 3 { + return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd) + } + + // git-annex always puts the repo in words[2], unlike most other + // git subcommands; and it sometimes names repos like /~/, as if + // $HOME should get expanded while also being rooted. e.g.: + // git-annex-shell 'configlist' '/~/user/repo' + // git-annex-shell 'sendkey' '/user/repo 'key' + repoPath = words[2] + repoPath = strings.TrimPrefix(repoPath, "/") + repoPath = strings.TrimPrefix(repoPath, "~/") + } + + // prevent directory traversal attacks + repoPath = filepath.Clean("/" + repoPath)[1:] + rr := strings.SplitN(repoPath, "/", 2) if len(rr) != 2 { return fail(ctx, "Invalid repository path", "Invalid repository path: %v", repoPath) @@ -225,6 +249,18 @@ func runServ(c *cli.Context) error { // so that username and reponame are not affected. repoPath = strings.ToLower(strings.TrimSpace(repoPath)) + // put the sanitized repoPath back into the argument list for later + if verb == gitAnnexShellVerb { + // git-annex-shell demands an absolute path + absRepoPath, err := filepath.Abs(filepath.Join(setting.RepoRootPath, repoPath)) + if err != nil { + return fail(ctx, "Error locating repoPath", "%v", err) + } + words[2] = absRepoPath + } else { + words[1] = repoPath + } + if alphaDashDotPattern.MatchString(reponame) { return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame) } @@ -303,21 +339,45 @@ func runServ(c *cli.Context) error { return nil } - var gitcmd *exec.Cmd - gitBinPath := filepath.Dir(git.GitExecutable) // e.g. /usr/bin - gitBinVerb := filepath.Join(gitBinPath, verb) // e.g. /usr/bin/git-upload-pack - if _, err := os.Stat(gitBinVerb); err != nil { + gitBinVerb, err := exec.LookPath(verb) + if err != nil { // if the command "git-upload-pack" doesn't exist, try to split "git-upload-pack" to use the sub-command with git // ps: Windows only has "git.exe" in the bin path, so Windows always uses this way + // ps: git-annex-shell and other extensions may not necessarily be in gitBinPath, + // but '{gitBinPath}/git annex-shell' should be able to find them on $PATH. verbFields := strings.SplitN(verb, "-", 2) if len(verbFields) == 2 { // use git binary with the sub-command part: "C:\...\bin\git.exe", "upload-pack", ... - gitcmd = exec.CommandContext(ctx, git.GitExecutable, verbFields[1], repoPath) + gitBinVerb = git.GitExecutable + words = append([]string{verbFields[1]}, words...) } } - if gitcmd == nil { - // by default, use the verb (it has been checked above by allowedCommands) - gitcmd = exec.CommandContext(ctx, gitBinVerb, repoPath) + + // by default, use the verb (it has been checked above by allowedCommands) + gitcmd := exec.CommandContext(ctx, gitBinVerb, words[1:]...) + + if verb == gitAnnexShellVerb { + // This doesn't get its own isolated section like LFS does, because LFS + // is handled by internal Gitea routines, but git-annex has to be shelled out + // to like other git subcommands, so we need to build up gitcmd. + + // TODO: does this work on Windows? + gitcmd.Env = append(gitcmd.Env, + // "If set, disallows running git-shell to handle unknown commands." + // - git-annex-shell(1) + "GIT_ANNEX_SHELL_LIMITED=True", + // "If set, git-annex-shell will refuse to run commands + // that do not operate on the specified directory." + // - git-annex-shell(1) + fmt.Sprintf("GIT_ANNEX_SHELL_DIRECTORY=%s", words[2]), + ) + if results.UserMode < perm.AccessModeWrite { + // "If set, disallows any action that could modify the git-annex repository." + // - git-annex-shell(1) + // We set this when the backend API has told us that we don't have write permission to this repo. + log.Debug("Setting GIT_ANNEX_SHELL_READONLY=True") + gitcmd.Env = append(gitcmd.Env, "GIT_ANNEX_SHELL_READONLY=True") + } } process.SetSysProcAttribute(gitcmd) diff --git a/cmd/web.go b/cmd/web.go index 44babd51c5..661e6d158e 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -9,6 +9,7 @@ import ( "net" "net/http" "os" + "os/exec" "path/filepath" "strconv" "strings" @@ -247,6 +248,12 @@ func runWeb(ctx *cli.Context) error { createPIDFile(ctx.String("pid")) } + if setting.Annex.Enabled { + if _, err := exec.LookPath("git-annex"); err != nil { + log.Fatal("You have enabled git-annex support but git-annex is not installed. Please make sure that Forgejo's PATH contains the git-annex executable.") + } + } + if !setting.InstallLock { if err := serveInstall(ctx); err != nil { return err @@ -311,6 +318,10 @@ func listen(m http.Handler, handleRedirector bool) error { log.Info("LFS server enabled") } + if setting.Annex.Enabled { + log.Info("git-annex enabled") + } + var err error switch setting.Protocol { case setting.HTTP: diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index ee8ad66668..3c723fa4c7 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2678,6 +2678,17 @@ LEVEL = Info ;; Limit the number of concurrent upload/download operations within a batch ;BATCH_OPERATION_CONCURRENCY = 8 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;[annex] +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Whether git-annex is enabled; defaults to false +;ENABLED = false +;; Whether to disable p2phttp support; default is the same as repository.DISABLE_HTTP_GIT +;DISABLE_P2PHTTP = false + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; settings for packages, will override storage setting diff --git a/go.mod b/go.mod index b054802289..19bec3f81f 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,10 @@ module code.gitea.io/gitea go 1.23 -toolchain go1.23.4 +toolchain go1.23.5 require ( - code.forgejo.org/f3/gof3/v3 v3.7.0 + code.forgejo.org/f3/gof3/v3 v3.10.2 code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 code.forgejo.org/forgejo/reply v1.0.2 code.forgejo.org/go-chi/binding v1.0.0 @@ -19,10 +19,10 @@ require ( gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 - github.com/ProtonMail/go-crypto v1.0.0 + github.com/ProtonMail/go-crypto v1.1.3 github.com/PuerkitoBio/goquery v1.10.0 github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 - github.com/alecthomas/chroma/v2 v2.14.0 + 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.4 @@ -44,7 +44,7 @@ require ( github.com/go-co-op/gocron v1.37.0 github.com/go-enry/go-enry/v2 v2.9.1 github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e - github.com/go-git/go-git/v5 v5.11.0 + github.com/go-git/go-git/v5 v5.13.1 github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-openapi/spec v0.20.14 github.com/go-sql-driver/mysql v1.8.1 @@ -89,7 +89,7 @@ require ( github.com/robfig/cron/v3 v3.0.1 github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 github.com/sassoftware/go-rpmutils v0.4.0 - github.com/sergi/go-diff v1.3.1 + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 github.com/stretchr/testify v1.10.0 github.com/syndtr/goleveldb v1.0.0 @@ -131,6 +131,7 @@ require ( dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect + github.com/42wim/httpsig v1.2.2 // indirect github.com/DataDog/zstd v1.5.5 // indirect github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.2 // indirect @@ -168,11 +169,11 @@ require ( github.com/cloudflare/circl v1.3.8 // indirect github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/cyphar/filepath-securejoin v0.3.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidmz/go-pageant v1.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dlclark/regexp2 v1.11.0 // indirect + 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 @@ -184,7 +185,7 @@ require ( github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-enry/go-oniguruma v1.2.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-git/go-billy/v5 v5.6.1 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -246,13 +247,14 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skeema/knownhosts v1.2.1 // indirect + github.com/skeema/knownhosts v1.3.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/zeebo/blake3 v0.2.4 // indirect + gitlab.com/gitlab-org/api/client-go v0.116.0 // indirect go.etcd.io/bbolt v1.3.9 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.31.0 // indirect diff --git a/go.sum b/go.sum index 4629eba1df..0bdc471be2 100644 --- a/go.sum +++ b/go.sum @@ -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.7.0 h1:ZfuCP8CGm8ZJbWmL+V0pUu3E0X4FCAA7GfRDy/y5/K4= -code.forgejo.org/f3/gof3/v3 v3.7.0/go.mod h1:oNhOeqD4DZYjVcNjQXIOdDX9b/1tqxi9ITLS8H9/Csw= +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/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.22.0 h1:NbUf0+vQ48+ddwe4zVkINqnxKYl/to+NUvW7iisPA60= @@ -651,6 +651,8 @@ gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 h1:IFT+hup2xejHq 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= +github.com/42wim/httpsig v1.2.2/go.mod h1:P/UYo7ytNBFwc+dg35IubuAUIs8zj5zzFIgUCEl55WY= github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 h1:r3qt8PCHnfjOv9PN3H+XXKmDA1dfFMIN1AislhlA/ps= github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121/go.mod h1:Ock8XgA7pvULhIaHGAk/cDnRfNrF9Jey81nPcc403iU= github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U= @@ -674,8 +676,8 @@ 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.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= -github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= +github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/PuerkitoBio/goquery v1.10.0 h1:6fiXdLuUvYs2OJSvNRqlNPoBm6YABE226xrbavY5Wv4= github.com/PuerkitoBio/goquery v1.10.0/go.mod h1:TjZZl68Q3eGHNBA8CWaxAN7rOU1EbDz3CWuolcO5Yu4= github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM= @@ -686,11 +688,11 @@ github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= -github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= -github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= +github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= -github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= -github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= +github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc= +github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= @@ -768,7 +770,6 @@ 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.4 h1:QFYO8IGvRnp7tGgiQb8g9uFU8kY9wOzxsFFx17+yy6Q= github.com/buildkite/terminal-to-html/v3 v3.16.4/go.mod h1:r/J7cC9c3EzBzP3/wDz0RJLPwv5PUAMp+KF2w+ntMc0= -github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/caddyserver/certmagic v0.21.4 h1:e7VobB8rffHv8ZZpSiZtEwnLDHUwLVYLWzWSa1FfKI0= github.com/caddyserver/certmagic v0.21.4/go.mod h1:swUXjQ1T9ZtMv95qj7/InJvWLXURU85r+CfG0T+ZbDE= github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= @@ -796,7 +797,6 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI= github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -817,8 +817,8 @@ github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1Ig 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= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= +github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -837,8 +837,8 @@ github.com/djherbis/nio/v3 v3.0.1/go.mod h1:Ng4h80pbZFMla1yKzm61cF0tqqilXZYrogmW github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= -github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= +github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4= @@ -849,8 +849,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/editorconfig/editorconfig-core-go/v2 v2.6.2 h1:dKG8sc7n321deIVRcQtwlMNoBEra7j0qQ8RwxO8RN0w= github.com/editorconfig/editorconfig-core-go/v2 v2.6.2/go.mod h1:7dvD3GCm7eBw53xZ/lsiq72LqobdMg3ITbMBxnmJmqY= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ= +github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= github.com/emersion/go-imap v1.2.1 h1:+s9ZjMEjOB8NzZMVTM3cCenz2JrQIGGo5j1df19WjTA= github.com/emersion/go-imap v1.2.1/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY= github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4= @@ -929,12 +929,12 @@ github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2H github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA= +github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M= +github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -1300,8 +1300,8 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +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= @@ -1373,8 +1373,8 @@ github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jN github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= -github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= -github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= @@ -1382,8 +1382,8 @@ github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= -github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= +github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= @@ -1449,6 +1449,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.116.0 h1:Dy534gtZPMrnm3fAcmQRMadrcoUyFO4FQ4rXlSAdHAw= +gitlab.com/gitlab-org/api/client-go v0.116.0/go.mod h1:B29OfnZklmaoiR7uHANh9jTyfWEgmXvZLVEnosw2Dx0= 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= @@ -1501,8 +1503,6 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= @@ -1522,6 +1522,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= diff --git a/models/actions/runner.go b/models/actions/runner.go index a679d7d989..b24950d014 100644 --- a/models/actions/runner.go +++ b/models/actions/runner.go @@ -282,27 +282,22 @@ func UpdateRunner(ctx context.Context, r *ActionRunner, cols ...string) error { } // DeleteRunner deletes a runner by given ID. -func DeleteRunner(ctx context.Context, id int64) error { - runner, err := GetRunnerByID(ctx, id) - if err != nil { - return err - } - +func DeleteRunner(ctx context.Context, r *ActionRunner) error { // Replace the UUID, which was either based on the secret's first 16 bytes or an UUIDv4, // with a sequence of 8 0xff bytes followed by the little-endian version of the record's // identifier. This will prevent the deleted record's identifier from colliding with any // new record. b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, uint64(id)) - runner.UUID = fmt.Sprintf("ffffffff-ffff-ffff-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x", + binary.LittleEndian.PutUint64(b, uint64(r.ID)) + r.UUID = fmt.Sprintf("ffffffff-ffff-ffff-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]) - err = UpdateRunner(ctx, runner, "UUID") + err := UpdateRunner(ctx, r, "UUID") if err != nil { return err } - _, err = db.DeleteByID[ActionRunner](ctx, id) + _, err = db.DeleteByID[ActionRunner](ctx, r.ID) return err } diff --git a/models/actions/runner_test.go b/models/actions/runner_test.go index 26ef4c44c6..2c8d430f94 100644 --- a/models/actions/runner_test.go +++ b/models/actions/runner_test.go @@ -34,7 +34,7 @@ func TestDeleteRunner(t *testing.T) { require.NoError(t, unittest.PrepareTestDatabase()) before := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID}) - err := DeleteRunner(db.DefaultContext, recordID) + err := DeleteRunner(db.DefaultContext, &ActionRunner{ID: recordID}) require.NoError(t, err) var after ActionRunner diff --git a/models/actions/variable.go b/models/actions/variable.go index d0f917d923..39cea95c4b 100644 --- a/models/actions/variable.go +++ b/models/actions/variable.go @@ -86,7 +86,7 @@ func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*ActionVariab } func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error) { - count, err := db.GetEngine(ctx).ID(variable.ID).Cols("name", "data"). + count, err := db.GetEngine(ctx).ID(variable.ID).Where("owner_id = ? AND repo_id = ?", variable.OwnerID, variable.RepoID).Cols("name", "data"). Update(&ActionVariable{ Name: variable.Name, Data: variable.Data, @@ -94,11 +94,9 @@ func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error) return count != 0, err } -func DeleteVariable(ctx context.Context, id int64) error { - if _, err := db.DeleteByID[ActionVariable](ctx, id); err != nil { - return err - } - return nil +func DeleteVariable(ctx context.Context, variableID, ownerID, repoID int64) (bool, error) { + count, err := db.GetEngine(ctx).Table("action_variable").Where("id = ? AND owner_id = ? AND repo_id = ?", variableID, ownerID, repoID).Delete() + return count != 0, err } func GetVariablesOfRun(ctx context.Context, run *ActionRun) (map[string]string, error) { diff --git a/models/auth/webauthn.go b/models/auth/webauthn.go index aa13cf6cb1..b230e1665a 100644 --- a/models/auth/webauthn.go +++ b/models/auth/webauthn.go @@ -52,10 +52,10 @@ type WebAuthnCredential struct { AAGUID []byte SignCount uint32 `xorm:"BIGINT"` CloneWarning bool - BackupEligible bool `XORM:"NOT NULL DEFAULT false"` - BackupState bool `XORM:"NOT NULL DEFAULT false"` + BackupEligible bool `xorm:"NOT NULL DEFAULT false"` + BackupState bool `xorm:"NOT NULL DEFAULT false"` // If legacy is set to true, backup_eligible and backup_state isn't set. - Legacy bool `XORM:"NOT NULL DEFAULT true"` + Legacy bool `xorm:"NOT NULL DEFAULT true"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` } diff --git a/models/fixtures/PrivateIssueProjects/project.yml b/models/fixtures/PrivateIssueProjects/project.yml new file mode 100644 index 0000000000..cf63e4e413 --- /dev/null +++ b/models/fixtures/PrivateIssueProjects/project.yml @@ -0,0 +1,23 @@ +- + id: 1001 + title: Org project that contains private issues + owner_id: 3 + repo_id: 0 + is_closed: false + creator_id: 2 + board_type: 1 + type: 3 + created_unix: 1738000000 + updated_unix: 1738000000 + +- + id: 1002 + title: User project that contains private issues + owner_id: 2 + repo_id: 0 + is_closed: false + creator_id: 2 + board_type: 1 + type: 1 + created_unix: 1738000000 + updated_unix: 1738000000 diff --git a/models/fixtures/PrivateIssueProjects/project_board.yml b/models/fixtures/PrivateIssueProjects/project_board.yml new file mode 100644 index 0000000000..3f1fe1e705 --- /dev/null +++ b/models/fixtures/PrivateIssueProjects/project_board.yml @@ -0,0 +1,17 @@ +- + id: 1001 + project_id: 1001 + title: Triage + creator_id: 2 + default: true + created_unix: 1738000000 + updated_unix: 1738000000 + +- + id: 1002 + project_id: 1002 + title: Triage + creator_id: 2 + default: true + created_unix: 1738000000 + updated_unix: 1738000000 diff --git a/models/fixtures/PrivateIssueProjects/project_issue.yml b/models/fixtures/PrivateIssueProjects/project_issue.yml new file mode 100644 index 0000000000..222b2e5f71 --- /dev/null +++ b/models/fixtures/PrivateIssueProjects/project_issue.yml @@ -0,0 +1,11 @@ +- + id: 1001 + issue_id: 6 + project_id: 1001 + project_board_id: 1001 + +- + id: 1002 + issue_id: 7 + project_id: 1002 + project_board_id: 1002 diff --git a/models/fixtures/label.yml b/models/fixtures/label.yml index 2242b90dcd..acfac74968 100644 --- a/models/fixtures/label.yml +++ b/models/fixtures/label.yml @@ -96,3 +96,14 @@ num_issues: 0 num_closed_issues: 0 archived_unix: 0 + +- + id: 10 + repo_id: 3 + org_id: 0 + name: repo3label1 + color: '#112233' + exclusive: false + num_issues: 0 + num_closed_issues: 0 + archived_unix: 0 diff --git a/models/fixtures/team_unit.yml b/models/fixtures/team_unit.yml index de0e8d738b..e8f8d0e422 100644 --- a/models/fixtures/team_unit.yml +++ b/models/fixtures/team_unit.yml @@ -1,42 +1,49 @@ - id: 1 team_id: 1 + org_id: 3 type: 1 access_mode: 4 - id: 2 team_id: 1 + org_id: 3 type: 2 access_mode: 4 - id: 3 team_id: 1 + org_id: 3 type: 3 access_mode: 4 - id: 4 team_id: 1 + org_id: 3 type: 4 access_mode: 4 - id: 5 team_id: 1 + org_id: 3 type: 5 access_mode: 4 - id: 6 team_id: 1 + org_id: 3 type: 6 access_mode: 4 - id: 7 team_id: 1 + org_id: 3 type: 7 access_mode: 4 diff --git a/models/issues/issue.go b/models/issues/issue.go index 17391ffe6c..fbbc4828a2 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -416,20 +416,6 @@ func (issue *Issue) SummaryCardURL() string { return fmt.Sprintf("%s/summary-card", issue.HTMLURL()) } -func (issue *Issue) SummaryCardSize() (int, int) { - return 1200, 600 -} - -func (issue *Issue) SummaryCardWidth() int { - width, _ := issue.SummaryCardSize() - return width -} - -func (issue *Issue) SummaryCardHeight() int { - _, height := issue.SummaryCardSize() - return height -} - // Link returns the issue's relative URL. func (issue *Issue) Link() string { var path string diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index 835ea1db52..f606b713cf 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -7,8 +7,10 @@ import ( "context" "code.gitea.io/gitea/models/db" + org_model "code.gitea.io/gitea/models/organization" project_model "code.gitea.io/gitea/models/project" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/util" ) @@ -48,22 +50,29 @@ func (issue *Issue) ProjectColumnID(ctx context.Context) int64 { } // LoadIssuesFromColumn load issues assigned to this column -func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column) (IssueList, error) { - issueList, err := Issues(ctx, &IssuesOptions{ +func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column, doer *user_model.User, org *org_model.Organization, isClosed optional.Option[bool]) (IssueList, error) { + issueOpts := &IssuesOptions{ ProjectColumnID: b.ID, ProjectID: b.ProjectID, SortType: "project-column-sorting", - }) + IsClosed: isClosed, + } + if doer != nil { + issueOpts.User = doer + issueOpts.Org = org + } else { + issueOpts.AllPublic = true + } + + issueList, err := Issues(ctx, issueOpts) if err != nil { return nil, err } if b.Default { - issues, err := Issues(ctx, &IssuesOptions{ - ProjectColumnID: db.NoConditionID, - ProjectID: b.ProjectID, - SortType: "project-column-sorting", - }) + issueOpts.ProjectColumnID = db.NoConditionID + + issues, err := Issues(ctx, issueOpts) if err != nil { return nil, err } @@ -78,10 +87,10 @@ func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column) (IssueLi } // LoadIssuesFromColumnList load issues assigned to the columns -func LoadIssuesFromColumnList(ctx context.Context, bs project_model.ColumnList) (map[int64]IssueList, error) { +func LoadIssuesFromColumnList(ctx context.Context, bs project_model.ColumnList, doer *user_model.User, org *org_model.Organization, isClosed optional.Option[bool]) (map[int64]IssueList, error) { issuesMap := make(map[int64]IssueList, len(bs)) for i := range bs { - il, err := LoadIssuesFromColumn(ctx, bs[i]) + il, err := LoadIssuesFromColumn(ctx, bs[i], doer, org, isClosed) if err != nil { return nil, err } @@ -160,3 +169,36 @@ func IssueAssignOrRemoveProject(ctx context.Context, issue *Issue, doer *user_mo }) }) } + +// NumIssuesInProjects returns the amount of issues assigned to one of the project +// in the list which the doer can access. +func NumIssuesInProjects(ctx context.Context, pl []*project_model.Project, doer *user_model.User, org *org_model.Organization, isClosed optional.Option[bool]) (map[int64]int, error) { + numMap := make(map[int64]int, len(pl)) + for _, p := range pl { + num, err := NumIssuesInProject(ctx, p, doer, org, isClosed) + if err != nil { + return nil, err + } + numMap[p.ID] = num + } + + return numMap, nil +} + +// NumIssuesInProject returns the amount of issues assigned to the project which +// the doer can access. +func NumIssuesInProject(ctx context.Context, p *project_model.Project, doer *user_model.User, org *org_model.Organization, isClosed optional.Option[bool]) (int, error) { + numIssuesInProject := int(0) + bs, err := p.GetColumns(ctx) + if err != nil { + return 0, err + } + im, err := LoadIssuesFromColumnList(ctx, bs, doer, org, isClosed) + if err != nil { + return 0, err + } + for _, il := range im { + numIssuesInProject += len(il) + } + return numIssuesInProject, nil +} diff --git a/models/issues/issue_project_test.go b/models/issues/issue_project_test.go new file mode 100644 index 0000000000..6ebc803722 --- /dev/null +++ b/models/issues/issue_project_test.go @@ -0,0 +1,100 @@ +// Copyright 2025 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-or-later + +package issues_test + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/organization" + "code.gitea.io/gitea/models/project" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPrivateIssueProjects(t *testing.T) { + defer tests.AddFixtures("models/fixtures/PrivateIssueProjects/")() + require.NoError(t, unittest.PrepareTestDatabase()) + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + t.Run("Organization project", func(t *testing.T) { + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) + orgProject := unittest.AssertExistsAndLoadBean(t, &project.Project{ID: 1001, OwnerID: org.ID}) + column := unittest.AssertExistsAndLoadBean(t, &project.Column{ID: 1001, ProjectID: orgProject.ID}) + + t.Run("Authenticated user", func(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) + + issuesNum, err := issues.NumIssuesInProject(db.DefaultContext, orgProject, user2, org, optional.None[bool]()) + require.NoError(t, err) + assert.EqualValues(t, 1, issuesNum) + + issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, orgProject, user2, org, optional.Some(true)) + require.NoError(t, err) + assert.EqualValues(t, 0, issuesNum) + + issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, orgProject, user2, org, optional.Some(false)) + require.NoError(t, err) + assert.EqualValues(t, 1, 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) + + issuesNum, err := issues.NumIssuesInProject(db.DefaultContext, orgProject, nil, org, optional.None[bool]()) + require.NoError(t, err) + assert.EqualValues(t, 0, issuesNum) + }) + }) + + t.Run("User project", func(t *testing.T) { + userProject := unittest.AssertExistsAndLoadBean(t, &project.Project{ID: 1002, OwnerID: user2.ID}) + column := unittest.AssertExistsAndLoadBean(t, &project.Column{ID: 1002, ProjectID: userProject.ID}) + + t.Run("Authenticated user", func(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.EqualValues(t, 7, issueList[0].ID) + + issuesNum, err := issues.NumIssuesInProject(db.DefaultContext, userProject, user2, nil, optional.None[bool]()) + require.NoError(t, err) + assert.EqualValues(t, 1, issuesNum) + + issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, userProject, user2, nil, optional.Some(true)) + require.NoError(t, err) + assert.EqualValues(t, 0, issuesNum) + + issuesNum, err = issues.NumIssuesInProject(db.DefaultContext, userProject, user2, nil, optional.Some(false)) + require.NoError(t, err) + assert.EqualValues(t, 1, 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) + + issuesNum, err := issues.NumIssuesInProject(db.DefaultContext, userProject, nil, nil, optional.None[bool]()) + require.NoError(t, err) + assert.EqualValues(t, 0, issuesNum) + }) + }) +} diff --git a/models/issues/label.go b/models/issues/label.go index 804a118e7a..259c87459e 100644 --- a/models/issues/label.go +++ b/models/issues/label.go @@ -353,6 +353,17 @@ func GetLabelIDsInRepoByNames(ctx context.Context, repoID int64, labelNames []st Find(&labelIDs) } +// GetLabelIDsInOrgByNames returns a list of labelIDs by names in a given org. +func GetLabelIDsInOrgByNames(ctx context.Context, orgID int64, labelNames []string) ([]int64, error) { + labelIDs := make([]int64, 0, len(labelNames)) + return labelIDs, db.GetEngine(ctx).Table("label"). + Where("org_id = ?", orgID). + In("name", labelNames). + Asc("name"). + Cols("id"). + Find(&labelIDs) +} + // BuildLabelNamesIssueIDsCondition returns a builder where get issue ids match label names func BuildLabelNamesIssueIDsCondition(labelNames []string) *builder.Builder { return builder.Select("issue_label.issue_id"). diff --git a/models/migrations/v1_23/v303.go b/models/migrations/v1_23/v303.go index c1e74c596a..2fb37ac843 100644 --- a/models/migrations/v1_23/v303.go +++ b/models/migrations/v1_23/v303.go @@ -1,5 +1,5 @@ -// Copyright 2024 The Forgejo Authors. -// SPDX-License-Identifier: MIT +// Copyright 2025 The Forgejo Authors. +// SPDX-License-Identifier: GPL-3.0-or-later package v1_23 //nolint @@ -7,26 +7,53 @@ import ( "code.gitea.io/gitea/models/migrations/base" "xorm.io/xorm" + "xorm.io/xorm/schemas" ) func GiteaLastDrop(x *xorm.Engine) error { + tables, err := x.DBMetas() + if err != nil { + return err + } + sess := x.NewSession() defer sess.Close() - if err := base.DropTableColumns(sess, "badge", "slug"); err != nil { - return err - } - if err := base.DropTableColumns(sess, "oauth2_application", "skip_secondary_authorization"); err != nil { - return err - } - if err := base.DropTableColumns(sess, "repository", "default_wiki_branch"); err != nil { - return err - } - // the migration v297.go that adds everyone_access_mode exists in Gitea >= v1.22 and the column must be dropped - // but it does not exist in Forgejo and a failure to drop the column can be ignored - base.DropTableColumns(sess, "repo_unit", "everyone_access_mode") - if err := base.DropTableColumns(sess, "protected_branch", "can_force_push", "enable_force_push_allowlist", "force_push_allowlist_user_i_ds", "force_push_allowlist_team_i_ds", "force_push_allowlist_deploy_keys"); err != nil { - return err + for _, drop := range []struct { + table string + column string + }{ + {"badge", "slug"}, + {"oauth2_application", "skip_secondary_authorization"}, + {"repository", "default_wiki_branch"}, + {"repo_unit", "everyone_access_mode"}, + {"protected_branch", "can_force_push"}, + {"protected_branch", "enable_force_push_allowlist"}, + {"protected_branch", "force_push_allowlist_user_i_ds"}, + {"protected_branch", "force_push_allowlist_team_i_ds"}, + {"protected_branch", "force_push_allowlist_deploy_keys"}, + } { + var table *schemas.Table + found := false + + for _, table = range tables { + if table.Name == drop.table { + found = true + break + } + } + + if !found { + continue + } + + if table.GetColumn(drop.column) == nil { + continue + } + + if err := base.DropTableColumns(sess, drop.table, drop.column); err != nil { + return err + } } return sess.Commit() diff --git a/models/migrations/v1_23/v303_test.go b/models/migrations/v1_23/v303_test.go new file mode 100644 index 0000000000..752eacee0c --- /dev/null +++ b/models/migrations/v1_23/v303_test.go @@ -0,0 +1,41 @@ +// Copyright 2025 The Forgejo Authors. +// SPDX-License-Identifier: GPL-3.0-or-later + +package v1_23 //nolint + +import ( + "testing" + + migration_tests "code.gitea.io/gitea/models/migrations/test" + + "github.com/stretchr/testify/require" + "xorm.io/xorm/schemas" +) + +func Test_GiteaLastDrop(t *testing.T) { + type Badge struct { + ID int64 `xorm:"pk autoincr"` + Slug string + } + + x, deferable := migration_tests.PrepareTestEnv(t, 0, new(Badge)) + defer deferable() + if x == nil || t.Failed() { + return + } + + getColumn := func() *schemas.Column { + tables, err := x.DBMetas() + require.NoError(t, err) + require.Len(t, tables, 1) + table := tables[0] + require.Equal(t, "badge", table.Name) + return table.GetColumn("slug") + } + + require.NotNil(t, getColumn(), "slug column exists") + require.NoError(t, GiteaLastDrop(x)) + require.Nil(t, getColumn(), "slug column was deleted") + // idempotent + require.NoError(t, GiteaLastDrop(x)) +} diff --git a/models/project/column.go b/models/project/column.go index 222f448599..f6d6614004 100644 --- a/models/project/column.go +++ b/models/project/column.go @@ -57,20 +57,6 @@ func (Column) TableName() string { return "project_board" // TODO: the legacy table name should be project_column } -// NumIssues return counter of all issues assigned to the column -func (c *Column) NumIssues(ctx context.Context) int { - total, err := db.GetEngine(ctx).Table("project_issue"). - Where("project_id=?", c.ProjectID). - And("project_board_id=?", c.ID). - GroupBy("issue_id"). - Cols("issue_id"). - Count() - if err != nil { - return 0 - } - return int(total) -} - func (c *Column) GetIssues(ctx context.Context) ([]*ProjectIssue, error) { issues := make([]*ProjectIssue, 0, 5) if err := db.GetEngine(ctx).Where("project_id=?", c.ProjectID). diff --git a/models/project/issue.go b/models/project/issue.go index 3361b533b9..984f47ee7c 100644 --- a/models/project/issue.go +++ b/models/project/issue.go @@ -34,20 +34,6 @@ func deleteProjectIssuesByProjectID(ctx context.Context, projectID int64) error return err } -// NumIssues return counter of all issues assigned to a project -func (p *Project) NumIssues(ctx context.Context) int { - c, err := db.GetEngine(ctx).Table("project_issue"). - Where("project_id=?", p.ID). - GroupBy("issue_id"). - Cols("issue_id"). - Count() - if err != nil { - log.Error("NumIssues: %v", err) - return 0 - } - return int(c) -} - // NumClosedIssues return counter of closed issues assigned to a project func (p *Project) NumClosedIssues(ctx context.Context) int { c, err := db.GetEngine(ctx).Table("project_issue"). diff --git a/models/repo/release.go b/models/repo/release.go index 38e38c6572..eb18f8aa02 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -97,13 +97,11 @@ func init() { // LoadAttributes load repo and publisher attributes for a release func (r *Release) LoadAttributes(ctx context.Context) error { - var err error - if r.Repo == nil { - r.Repo, err = GetRepositoryByID(ctx, r.RepoID) - if err != nil { - return err - } + err := r.LoadRepo(ctx) + if err != nil { + return err } + if r.Publisher == nil { r.Publisher, err = user_model.GetUserByID(ctx, r.PublisherID) if err != nil { @@ -123,6 +121,18 @@ func (r *Release) LoadAttributes(ctx context.Context) error { return GetReleaseAttachments(ctx, r) } +// LoadRepo load repo attribute for release +func (r *Release) LoadRepo(ctx context.Context) error { + if r.Repo != nil { + return nil + } + + var err error + r.Repo, err = GetRepositoryByID(ctx, r.RepoID) + + return err +} + // LoadArchiveDownloadCount loads the download count for the source archives func (r *Release) LoadArchiveDownloadCount(ctx context.Context) error { var err error @@ -130,6 +140,25 @@ func (r *Release) LoadArchiveDownloadCount(ctx context.Context) error { return err } +// GetTotalDownloadCount returns the summary of all dowload count of files attached to the release +func (r *Release) GetTotalDownloadCount(ctx context.Context) (int64, error) { + var archiveCount int64 + if !r.HideArchiveLinks { + _, err := db.GetEngine(ctx).SQL("SELECT SUM(count) FROM repo_archive_download_count WHERE release_id = ?", r.ID).Get(&archiveCount) + if err != nil { + return 0, err + } + } + + var attachmentCount int64 + _, err := db.GetEngine(ctx).SQL("SELECT SUM(download_count) FROM attachment WHERE release_id = ?", r.ID).Get(&attachmentCount) + if err != nil { + return 0, err + } + + return archiveCount + attachmentCount, nil +} + // APIURL the api url for a release. release must have attributes loaded func (r *Release) APIURL() string { return r.Repo.APIURL() + "/releases/" + strconv.FormatInt(r.ID, 10) @@ -160,6 +189,20 @@ func (r *Release) Link() string { return r.Repo.Link() + "/releases/tag/" + util.PathEscapeSegments(r.TagName) } +// SummaryCardURL returns the absolute URL to an image providing a summary of the release +func (r *Release) SummaryCardURL() string { + return fmt.Sprintf("%s/releases/summary-card/%s", r.Repo.HTMLURL(), util.PathEscapeSegments(r.TagName)) +} + +// DisplayName retruns the name of the release +func (r *Release) DisplayName() string { + if r.IsTag && r.Title == "" { + return r.TagName + } + + return r.Title +} + // IsReleaseExist returns true if release with given tag name already exists. func IsReleaseExist(ctx context.Context, repoID int64, tagName string) (bool, error) { if len(tagName) == 0 { diff --git a/models/repo/release_test.go b/models/repo/release_test.go index 4e61a2805d..7680f2cc9d 100644 --- a/models/repo/release_test.go +++ b/models/repo/release_test.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -25,3 +26,26 @@ func TestMigrate_InsertReleases(t *testing.T) { err := InsertReleases(db.DefaultContext, r) require.NoError(t, err) } + +func TestReleaseLoadRepo(t *testing.T) { + require.NoError(t, unittest.PrepareTestDatabase()) + + release := unittest.AssertExistsAndLoadBean(t, &Release{ID: 1}) + assert.Nil(t, release.Repo) + + require.NoError(t, release.LoadRepo(db.DefaultContext)) + + assert.EqualValues(t, 1, release.Repo.ID) +} + +func TestReleaseDisplayName(t *testing.T) { + release := Release{TagName: "TagName"} + + assert.Empty(t, release.DisplayName()) + + release.IsTag = true + assert.Equal(t, "TagName", release.DisplayName()) + + release.Title = "Title" + assert.Equal(t, "Title", release.DisplayName()) +} diff --git a/models/repo/repo.go b/models/repo/repo.go index cd6be48b90..bdf0de2f85 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -327,6 +327,11 @@ func (repo *Repository) HTMLURL() string { return setting.AppURL + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) } +// SummaryCardURL returns the absolute URL to an image providing a summary of the repo +func (repo *Repository) SummaryCardURL() string { + return fmt.Sprintf("%s/-/summary-card", repo.HTMLURL()) +} + // CommitLink make link to by commit full ID // note: won't check whether it's an right id func (repo *Repository) CommitLink(commitID string) (result string) { diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go index 781a75730a..0f95f5ab6b 100644 --- a/models/repo/user_repo.go +++ b/models/repo/user_repo.go @@ -166,9 +166,9 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64) // If isShowFullName is set to true, also include full name prefix search func GetIssuePostersWithSearch(ctx context.Context, repo *Repository, isPull bool, search string, isShowFullName bool) ([]*user_model.User, error) { users := make([]*user_model.User, 0, 30) - var prefixCond builder.Cond = builder.Like{"name", search + "%"} + prefixCond := db.BuildCaseInsensitiveLike("name", search+"%") if isShowFullName { - prefixCond = prefixCond.Or(builder.Like{"full_name", "%" + search + "%"}) + prefixCond = db.BuildCaseInsensitiveLike("full_name", "%"+search+"%") } cond := builder.In("`user`.id", diff --git a/models/user/search.go b/models/user/search.go index cb90ca850e..143f9d39c9 100644 --- a/models/user/search.go +++ b/models/user/search.go @@ -126,17 +126,15 @@ func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Sess return e.Where(cond) } - // 2fa filter uses LEFT JOIN to check whether a user has a 2fa record - // While using LEFT JOIN, sometimes the performance might not be good, but it won't be a problem now, such SQL is seldom executed. - // There are some possible methods to refactor this SQL in future when we really need to optimize the performance (but not now): - // (1) add a column in user table (2) add a setting value in user_setting table (3) use search engines (bleve/elasticsearch) + // Check if the user has two factor enabled, which is TOTP or Webauthn. if opts.IsTwoFactorEnabled.Value() { - cond = cond.And(builder.Expr("two_factor.uid IS NOT NULL")) + cond = cond.And(builder.Expr("two_factor.uid IS NOT NULL OR webauthn_credential.user_id IS NOT NULL")) } else { - cond = cond.And(builder.Expr("two_factor.uid IS NULL")) + cond = cond.And(builder.Expr("two_factor.uid IS NULL AND webauthn_credential.user_id IS NULL")) } return e.Join("LEFT OUTER", "two_factor", "two_factor.uid = `user`.id"). + Join("LEFT OUTER", "webauthn_credential", "webauthn_credential.user_id = `user`.id"). Where(cond) } diff --git a/models/user/user_test.go b/models/user/user_test.go index 1c734fa926..bc23a5da48 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -222,7 +222,7 @@ func TestSearchUsers(t *testing.T) { []int64{1041, 37}) testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: optional.Some(true)}, - []int64{24}) + []int64{24, 32}) } func TestEmailNotificationPreferences(t *testing.T) { diff --git a/modules/annex/annex.go b/modules/annex/annex.go new file mode 100644 index 0000000000..67e53f566c --- /dev/null +++ b/modules/annex/annex.go @@ -0,0 +1,256 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +// Unlike modules/lfs, which operates mainly on git.Blobs, this operates on git.TreeEntrys. +// The motivation for this is that TreeEntrys have an easy pointer to the on-disk repo path, +// while blobs do not (in fact, if building with TAGS=gogit, blobs might exist only in a mock +// filesystem, living only in process RAM). We must have the on-disk path to do anything +// useful with git-annex because all of its interesting data is on-disk under .git/annex/. + +package annex + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "os" + "path" + "path/filepath" + "strings" + "sync" + "time" + + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/typesniffer" + + "gopkg.in/ini.v1" //nolint:depguard // This import is forbidden in favor of using the setting module, but we need ini parsing for something other than Forgejo settings +) + +// ErrBlobIsNotAnnexed occurs if a blob does not contain a valid annex key +var ErrBlobIsNotAnnexed = errors.New("not a git-annex pointer") + +func PrivateInit(ctx context.Context, repoPath string) error { + if _, _, err := git.NewCommand(ctx, "config", "annex.private", "true").RunStdString(&git.RunOpts{Dir: repoPath}); err != nil { + return err + } + if _, _, err := git.NewCommand(ctx, "annex", "init").RunStdString(&git.RunOpts{Dir: repoPath}); err != nil { + return err + } + return nil +} + +func LookupKey(blob *git.Blob) (string, error) { + stdout, _, err := git.NewCommand(git.DefaultContext, "annex", "lookupkey", "--ref").AddDynamicArguments(blob.ID.String()).RunStdString(&git.RunOpts{Dir: blob.Repo().Path}) + if err != nil { + return "", ErrBlobIsNotAnnexed + } + key := strings.TrimSpace(stdout) + return key, nil +} + +// LookupKeyBatch runs git annex lookupkey --batch --ref +func LookupKeyBatch(ctx context.Context, shasToBatchReader *io.PipeReader, lookupKeyBatchWriter *io.PipeWriter, wg *sync.WaitGroup, repoPath string) { + defer wg.Done() + defer shasToBatchReader.Close() + defer lookupKeyBatchWriter.Close() + + stderr := new(bytes.Buffer) + var errbuf strings.Builder + if err := git.NewCommand(ctx, "annex", "lookupkey", "--batch", "--ref").Run(&git.RunOpts{ + Dir: repoPath, + Stdout: lookupKeyBatchWriter, + Stdin: shasToBatchReader, + Stderr: stderr, + }); err != nil { + _ = lookupKeyBatchWriter.CloseWithError(fmt.Errorf("git annex lookupkey --batch --ref [%s]: %w - %s", repoPath, err, errbuf.String())) + } +} + +// CopyFromToBatch runs git -c annex.hardlink=true annex copy --batch-keys --from --to +func CopyFromToBatch(ctx context.Context, from, to string, keysToCopyReader *io.PipeReader, wg *sync.WaitGroup, repoPath string) { + defer wg.Done() + defer keysToCopyReader.Close() + + stdout := new(bytes.Buffer) + stderr := new(bytes.Buffer) + var errbuf strings.Builder + if err := git.NewCommand(ctx, "-c", "annex.hardlink=true", "annex", "copy", "--batch-keys", "--from").AddDynamicArguments(from).AddArguments("--to").AddDynamicArguments(to).Run(&git.RunOpts{ + Dir: repoPath, + Stdout: stdout, + Stdin: keysToCopyReader, + Stderr: stderr, + }); err != nil { + _ = keysToCopyReader.CloseWithError(fmt.Errorf("git annex copy --batch-keys --from --to [%s]: %w - %s", repoPath, err, errbuf.String())) + } +} + +func ContentLocationFromKey(repoPath, key string) (string, error) { + contentLocation, _, err := git.NewCommandContextNoGlobals(git.DefaultContext, "annex", "contentlocation").AddDynamicArguments(key).RunStdString(&git.RunOpts{Dir: repoPath}) + if err != nil { + return "", fmt.Errorf("in %s: %s does not seem to be a valid annexed file: %w", repoPath, key, err) + } + contentLocation = strings.TrimSpace(contentLocation) + contentLocation = path.Clean("/" + contentLocation)[1:] // prevent directory traversals + contentLocation = path.Join(repoPath, contentLocation) + + return contentLocation, nil +} + +// return the absolute path of the content pointed to by the annex pointer stored in the git object +// errors if the content is not found in this repo +func ContentLocation(blob *git.Blob) (string, error) { + key, err := LookupKey(blob) + if err != nil { + return "", err + } + return ContentLocationFromKey(blob.Repo().Path, key) +} + +// returns a stream open to the annex content +func Content(blob *git.Blob) (*os.File, error) { + contentLocation, err := ContentLocation(blob) + if err != nil { + return nil, err + } + + return os.Open(contentLocation) +} + +// whether the object appears to be a valid annex pointer +// does *not* verify if the content is actually in this repo; +// for that, use ContentLocation() +func IsAnnexed(blob *git.Blob) (bool, error) { + if !setting.Annex.Enabled { + return false, nil + } + + // LookupKey is written to only return well-formed keys + // so the test is just to see if it errors + _, err := LookupKey(blob) + if err != nil { + if errors.Is(err, ErrBlobIsNotAnnexed) { + return false, nil + } + return false, err + } + return true, nil +} + +// PathIsAnnexRepo determines if repoPath is a git-annex enabled repository +func PathIsAnnexRepo(repoPath string) bool { + _, _, err := git.NewCommand(git.DefaultContext, "config", "annex.uuid").RunStdString(&git.RunOpts{Dir: repoPath}) + return err == nil +} + +// IsAnnexRepo determines if repo is a git-annex enabled repository +func IsAnnexRepo(repo *git.Repository) bool { + _, _, err := git.NewCommand(repo.Ctx, "config", "annex.uuid").RunStdString(&git.RunOpts{Dir: repo.Path}) + return err == nil +} + +var ( + uuid2repoPathCache = make(map[string]string) + repoPath2uuidCache = make(map[string]string) +) + +func Init() error { + if !setting.Annex.Enabled { + return nil + } + if !setting.Annex.DisableP2PHTTP { + log.Info("Populating the git-annex UUID cache with existing repositories") + start := time.Now() + if err := updateUUID2RepoPathCache(); err != nil { + return err + } + log.Info("Populating the git-annex UUID cache took %v", time.Since(start)) + } + return nil +} + +func updateUUID2RepoPathCache() error { + configFiles, err := filepath.Glob(filepath.Join(setting.RepoRootPath, "*", "*", "config")) + if err != nil { + return err + } + for _, configFile := range configFiles { + repoPath := strings.TrimSuffix(configFile, "/config") + _, ok := repoPath2uuidCache[repoPath] + if ok { + continue + } + config, err := ini.Load(configFile) + if err != nil { + continue + } + repoUUID := config.Section("annex").Key("uuid").Value() + if repoUUID != "" { + uuid2repoPathCache[repoUUID] = repoPath + repoPath2uuidCache[repoPath] = repoUUID + } + } + return nil +} + +func repoPathFromUUIDCache(uuid string) (string, error) { + if repoPath, ok := uuid2repoPathCache[uuid]; ok { + return repoPath, nil + } + // If the cache didn't contain an entry for the UUID then update the cache and try again + if err := updateUUID2RepoPathCache(); err != nil { + return "", err + } + if repoPath, ok := uuid2repoPathCache[uuid]; ok { + return repoPath, nil + } + return "", fmt.Errorf("no repository known for UUID '%s'", uuid) +} + +func checkValidity(uuid, repoPath string) (bool, error) { + stdout, _, err := git.NewCommand(git.DefaultContext, "config", "annex.uuid").RunStdString(&git.RunOpts{Dir: repoPath}) + if err != nil { + return false, err + } + repoUUID := strings.TrimSpace(stdout) + return uuid == repoUUID, nil +} + +func removeCachedEntries(uuid, repoPath string) { + delete(uuid2repoPathCache, uuid) + delete(repoPath2uuidCache, repoPath) +} + +func UUID2RepoPath(uuid string) (string, error) { + // Get the current cache entry for the UUID + repoPath, err := repoPathFromUUIDCache(uuid) + if err != nil { + return "", err + } + // Check if it is still up-to-date + valid, err := checkValidity(uuid, repoPath) + if err != nil { + return "", err + } + if !valid { + // If it isn't, remove the cache entry and try again + removeCachedEntries(uuid, repoPath) + return UUID2RepoPath(uuid) + } + // Otherwise just return the cached entry + return repoPath, nil +} + +// GuessContentType guesses the content type of the annexed blob. +func GuessContentType(blob *git.Blob) (typesniffer.SniffedType, error) { + r, err := Content(blob) + if err != nil { + return typesniffer.SniffedType{}, err + } + defer r.Close() + + return typesniffer.DetectContentTypeFromReader(r) +} diff --git a/modules/base/tool.go b/modules/base/tool.go index 02f1db59d3..a885546fde 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -16,6 +16,7 @@ import ( "strings" "unicode/utf8" + "code.gitea.io/gitea/modules/annex" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" @@ -101,6 +102,12 @@ func Int64sToStrings(ints []int64) []string { // EntryIcon returns the octicon class for displaying files/directories func EntryIcon(entry *git.TreeEntry) string { + isAnnexed, _ := annex.IsAnnexed(entry.Blob()) + if isAnnexed { + // Show git-annex files as binary files to differentiate them from non-annexed files + // TODO: find a more suitable icon, maybe something related to git-annex + return "file-binary" + } switch { case entry.IsLink(): te, _, err := entry.FollowLink() diff --git a/modules/card/card.go b/modules/card/card.go index bb160d7ea3..370d241073 100644 --- a/modules/card/card.go +++ b/modules/card/card.go @@ -5,6 +5,7 @@ package card import ( "bytes" + "fmt" "image" "image/color" "io" @@ -35,12 +36,19 @@ type Card struct { Img *image.RGBA Font *truetype.Font Margin int + Width int + Height int } var fontCache = sync.OnceValues(func() (*truetype.Font, error) { return truetype.Parse(goregular.TTF) }) +// DefaultSize returns the default size for a card +func DefaultSize() (int, int) { + return 1200, 600 +} + // NewCard creates a new card with the given dimensions in pixels func NewCard(width, height int) (*Card, error) { img := image.NewRGBA(image.Rect(0, 0, width, height)) @@ -55,6 +63,8 @@ func NewCard(width, height int) (*Card, error) { Img: img, Font: font, Margin: 0, + Width: width, + Height: height, }, nil } @@ -67,14 +77,14 @@ func (c *Card) Split(vertical bool, percentage int) (*Card, *Card) { mid := (bounds.Dx() * percentage / 100) + bounds.Min.X subleft := c.Img.SubImage(image.Rect(bounds.Min.X, bounds.Min.Y, mid, bounds.Max.Y)).(*image.RGBA) subright := c.Img.SubImage(image.Rect(mid, bounds.Min.Y, bounds.Max.X, bounds.Max.Y)).(*image.RGBA) - return &Card{Img: subleft, Font: c.Font}, - &Card{Img: subright, Font: c.Font} + return &Card{Img: subleft, Font: c.Font, Width: subleft.Bounds().Dx(), Height: subleft.Bounds().Dy()}, + &Card{Img: subright, Font: c.Font, Width: subright.Bounds().Dx(), Height: subright.Bounds().Dy()} } mid := (bounds.Dy() * percentage / 100) + bounds.Min.Y subtop := c.Img.SubImage(image.Rect(bounds.Min.X, bounds.Min.Y, bounds.Max.X, mid)).(*image.RGBA) subbottom := c.Img.SubImage(image.Rect(bounds.Min.X, mid, bounds.Max.X, bounds.Max.Y)).(*image.RGBA) - return &Card{Img: subtop, Font: c.Font}, - &Card{Img: subbottom, Font: c.Font} + return &Card{Img: subtop, Font: c.Font, Width: subtop.Bounds().Dx(), Height: subtop.Bounds().Dy()}, + &Card{Img: subbottom, Font: c.Font, Width: subbottom.Bounds().Dx(), Height: subbottom.Bounds().Dy()} } // SetMargin sets the margins for the card @@ -244,9 +254,14 @@ func (c *Card) fetchExternalImage(url string) (image.Image, bool) { }, } + // Go expects a absolute URL, so we must change a relative to an absolute one + if !strings.Contains(url, "://") { + url = fmt.Sprintf("%s%s", setting.AppURL, strings.TrimPrefix(url, "/")) + } + resp, err := client.Get(url) if err != nil { - log.Warn("error when fetching external image from %s: %w", url, err) + log.Warn("error when fetching external image from %s: %v", url, err) return nil, false } defer resp.Body.Close() @@ -321,3 +336,8 @@ func (c *Card) DrawExternalImage(url string) { } c.DrawImage(image) } + +// DrawRect draws a rect with the given color +func (c *Card) DrawRect(startX, startY, endX, endY int, color color.Color) { + draw.Draw(c.Img, image.Rect(startX, startY, endX, endY), &image.Uniform{color}, image.Point{}, draw.Src) +} diff --git a/modules/git/blob.go b/modules/git/blob.go index 2f02693428..bbfab7d005 100644 --- a/modules/git/blob.go +++ b/modules/git/blob.go @@ -126,6 +126,10 @@ func (b *blobReader) Close() error { return nil } +func (b *Blob) Repo() *Repository { + return b.repo +} + // Name returns name of the tree entry this blob object was created from (or empty string) func (b *Blob) Name() string { return b.name diff --git a/modules/git/command.go b/modules/git/command.go index a3d43aaec6..d3e6b7b8bc 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -457,12 +457,13 @@ func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunS } // AllowLFSFiltersArgs return globalCommandArgs with lfs filter, it should only be used for tests +// It also re-enables git-credential(1), which is used to test git-annex's HTTP support func AllowLFSFiltersArgs() TrustedCmdArgs { // Now here we should explicitly allow lfs filters to run filteredLFSGlobalArgs := make(TrustedCmdArgs, len(globalCommandArgs)) j := 0 for _, arg := range globalCommandArgs { - if strings.Contains(string(arg), "lfs") { + if strings.Contains(string(arg), "lfs") || strings.Contains(string(arg), "credential") { j-- } else { filteredLFSGlobalArgs[j] = arg diff --git a/modules/git/pipeline/catfile.go b/modules/git/pipeline/catfile.go index 4677218150..f803d2e5be 100644 --- a/modules/git/pipeline/catfile.go +++ b/modules/git/pipeline/catfile.go @@ -106,3 +106,36 @@ func BlobsLessThan1024FromCatFileBatchCheck(catFileCheckReader *io.PipeReader, s } } } + +// BlobsLessThanOrEqual32KiBFromCatFileBatchCheck reads a pipeline from cat-file --batch-check and returns the blobs <=32KiB in size +func BlobsLessThanOrEqual32KiBFromCatFileBatchCheck(catFileCheckReader *io.PipeReader, shasToBatchWriter *io.PipeWriter, wg *sync.WaitGroup) { + defer wg.Done() + defer catFileCheckReader.Close() + scanner := bufio.NewScanner(catFileCheckReader) + defer func() { + _ = shasToBatchWriter.CloseWithError(scanner.Err()) + }() + for scanner.Scan() { + line := scanner.Text() + if len(line) == 0 { + continue + } + fields := strings.Split(line, " ") + if len(fields) < 3 || fields[1] != "blob" { + continue + } + size, _ := strconv.Atoi(fields[2]) + if size > 32*1024 { + continue + } + toWrite := []byte(fields[0] + "\n") + for len(toWrite) > 0 { + n, err := shasToBatchWriter.Write(toWrite) + if err != nil { + _ = catFileCheckReader.CloseWithError(err) + break + } + toWrite = toWrite[n:] + } + } +} diff --git a/modules/markup/external/external.go b/modules/markup/external/external.go index 122517ed11..b9760772a1 100644 --- a/modules/markup/external/external.go +++ b/modules/markup/external/external.go @@ -12,6 +12,7 @@ import ( "runtime" "strings" + "code.gitea.io/gitea/modules/annex" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" @@ -86,8 +87,22 @@ func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io. commands = strings.Fields(command) args = commands[1:] ) - - if p.IsInputFile { + isAnnexed, _ := annex.IsAnnexed(ctx.Blob) + // if a renderer wants to read a file, and we have annexed content, we can + // provide the annex key file location directly to the renderer. git-annex + // takes care of having that location be read-only, so no critical + // protection layer is needed. Moreover, the file readily exists, and + // expensive temporary files can be avoided, also allowing an operator + // to raise MAX_DISPLAY_FILE_SIZE without much negative impact. + if p.IsInputFile && isAnnexed { + // look for annexed content, will be empty, if there is none + annexContentLocation, _ := annex.ContentLocation(ctx.Blob) + // we call the renderer, even if there is no annex content present. + // showing the pointer file content is not much use, and a topical + // renderer might be able to produce something useful from the + // filename alone (present in ENV) + args = append(args, annexContentLocation) + } else if p.IsInputFile { // write to temp file f, err := os.CreateTemp("", "gitea_input") if err != nil { @@ -130,6 +145,12 @@ func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io. os.Environ(), "GITEA_PREFIX_SRC="+ctx.Links.SrcLink(), "GITEA_PREFIX_RAW="+ctx.Links.RawLink(), + // also communicate the relative path of the to-be-rendered item. + // this enables the renderer to make use of the original file name + // and path, e.g., to make rendering or dtype-detection decisions + // that go beyond the originally matched extension. Even if the + // content is directly streamed to STDIN + "GITEA_RELATIVE_PATH="+ctx.RelativePath, ) if !p.IsInputFile { cmd.Stdin = input diff --git a/modules/markup/file_preview.go b/modules/markup/file_preview.go index 49a5f1e8ba..2171f6097b 100644 --- a/modules/markup/file_preview.go +++ b/modules/markup/file_preview.go @@ -8,6 +8,7 @@ import ( "bytes" "html/template" "io" + "net/url" "regexp" "slices" "strconv" @@ -77,6 +78,16 @@ func newFilePreview(ctx *RenderContext, node *html.Node, locale translation.Loca commitSha := node.Data[m[4]:m[5]] filePath := node.Data[m[6]:m[7]] + urlFullSource := urlFull + if strings.HasSuffix(filePath, "?display=source") { + filePath = strings.TrimSuffix(filePath, "?display=source") + } else if Type(filePath) != "" { + urlFullSource = node.Data[m[0]:m[6]] + filePath + "?display=source#" + node.Data[m[8]:m[1]] + } + filePath, err := url.QueryUnescape(filePath) + if err != nil { + return nil + } hash := node.Data[m[8]:m[9]] preview.start = m[0] @@ -113,7 +124,7 @@ func newFilePreview(ctx *RenderContext, node *html.Node, locale translation.Loca titleBuffer.WriteString(" – ") } - err = html.Render(titleBuffer, createLink(urlFull, filePath, "muted")) + err = html.Render(titleBuffer, createLink(urlFullSource, filePath, "muted")) if err != nil { log.Error("failed to render filepathLink: %v", err) } diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 50ea70905c..05ba321548 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -1026,4 +1026,138 @@ func TestRender_FilePreview(t *testing.T) { localMetas, ) }) + + commitFileURL := util.URLJoin(markup.TestRepoURL, "src", "commit", "c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be", "path", "to", "file.md") + + t.Run("rendered file with ?display=source", func(t *testing.T) { + testRender( + commitFileURL+"?display=source"+"#L1-L2", + `

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.md`+ + `
`+ + ``+ + `Lines 1 to 2 in c991312`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
# A`+"\n"+`
B`+"\n"+`
`+ + `
`+ + `
`+ + `

`, + localMetas, + ) + }) + + t.Run("rendered file without ?display=source", func(t *testing.T) { + testRender( + commitFileURL+"#L1-L2", + `

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.md`+ + `
`+ + ``+ + `Lines 1 to 2 in c991312`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
# A`+"\n"+`
B`+"\n"+`
`+ + `
`+ + `
`+ + `

`, + localMetas, + ) + }) + + commitFileURL = util.URLJoin(markup.TestRepoURL, "src", "commit", "190d9492934af498c3f669d6a2431dc5459e5b20", "path", "to", "file.go") + + t.Run("normal file with ?display=source", func(t *testing.T) { + testRender( + commitFileURL+"?display=source"+"#L2-L3", + `

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.go`+ + `
`+ + ``+ + `Lines 2 to 3 in 190d949`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
B`+"\n"+`
C`+"\n"+`
`+ + `
`+ + `
`+ + `

`, + localMetas, + ) + }) + + commitFileURL = util.URLJoin(markup.TestRepoURL, "src", "commit", "eeb243c3395e1921c5d90e73bd739827251fc99d", "path", "to", "file%20%23.txt") + + t.Run("file with strange characters in name", func(t *testing.T) { + testRender( + commitFileURL+"#L1", + `

`+ + `
`+ + `
`+ + `
`+ + `path/to/file #.txt`+ + `
`+ + ``+ + `Line 1 in eeb243c`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
A`+"\n"+`
`+ + `
`+ + `
`+ + `

`, + localMetas, + ) + }) } diff --git a/modules/markup/orgmode/orgmode_test.go b/modules/markup/orgmode/orgmode_test.go index f41d86a8a8..58fede7eb8 100644 --- a/modules/markup/orgmode/orgmode_test.go +++ b/modules/markup/orgmode/orgmode_test.go @@ -152,8 +152,8 @@ func HelloWorld() { } #+end_src `, `
-
// HelloWorld prints "Hello World"
-func HelloWorld() {
+
// HelloWorld prints "Hello World"
+func HelloWorld() {
 	fmt.Println("Hello World")
 }
`) diff --git a/modules/markup/renderer.go b/modules/markup/renderer.go index 2137302f43..c00bd2b56e 100644 --- a/modules/markup/renderer.go +++ b/modules/markup/renderer.go @@ -67,14 +67,18 @@ type Header struct { // RenderContext represents a render context type RenderContext struct { - Ctx context.Context - RelativePath string // relative path from tree root of the branch - Type string - IsWiki bool - Links Links - Metas map[string]string - DefaultLink string - GitRepo *git.Repository + Ctx context.Context + RelativePath string // relative path from tree root of the branch + Type string + IsWiki bool + Links Links + Metas map[string]string + DefaultLink string + GitRepo *git.Repository + // reporting the target blob that is to-be-rendered enables + // deeper inspection in the handler for external renderer + // (i.e., more targeted handling of annexed files) + Blob *git.Blob ShaExistCache map[string]bool cancelFn func() SidebarTocNode ast.Node diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/0b/b53b56d70d253ce75c257d3cd6334a41ef2b6c b/modules/markup/tests/repo/repo1_filepreview/objects/0b/b53b56d70d253ce75c257d3cd6334a41ef2b6c new file mode 100644 index 0000000000..1ab268b76c Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/0b/b53b56d70d253ce75c257d3cd6334a41ef2b6c differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/18/9739e1c2a6cdb8ee094ba1ef8a2e40cf65b2ec b/modules/markup/tests/repo/repo1_filepreview/objects/18/9739e1c2a6cdb8ee094ba1ef8a2e40cf65b2ec new file mode 100644 index 0000000000..c8b99f906b Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/18/9739e1c2a6cdb8ee094ba1ef8a2e40cf65b2ec differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/2a/4032b49cff56d6d4921133e087d9dc0341a2c5 b/modules/markup/tests/repo/repo1_filepreview/objects/2a/4032b49cff56d6d4921133e087d9dc0341a2c5 new file mode 100644 index 0000000000..f799e8a988 Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/2a/4032b49cff56d6d4921133e087d9dc0341a2c5 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/2d/2f8eaa17b17359ee1c73222065575d50d9a157 b/modules/markup/tests/repo/repo1_filepreview/objects/2d/2f8eaa17b17359ee1c73222065575d50d9a157 new file mode 100644 index 0000000000..7f4c451d00 Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/2d/2f8eaa17b17359ee1c73222065575d50d9a157 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/2f/b9577a8e940a0a84a789cdd4a45d0f172e3fdd b/modules/markup/tests/repo/repo1_filepreview/objects/2f/b9577a8e940a0a84a789cdd4a45d0f172e3fdd new file mode 100644 index 0000000000..fc97712911 Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/2f/b9577a8e940a0a84a789cdd4a45d0f172e3fdd differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/2f/f8eb63aad050c3f20e9cb27090ab7378267ab2 b/modules/markup/tests/repo/repo1_filepreview/objects/2f/f8eb63aad050c3f20e9cb27090ab7378267ab2 new file mode 100644 index 0000000000..e230df1343 Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/2f/f8eb63aad050c3f20e9cb27090ab7378267ab2 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/35/75ed7948fe86ab56b0a76f796f7995222bec65 b/modules/markup/tests/repo/repo1_filepreview/objects/35/75ed7948fe86ab56b0a76f796f7995222bec65 new file mode 100644 index 0000000000..1493caa3df Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/35/75ed7948fe86ab56b0a76f796f7995222bec65 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/3c/95f14e5a0ab2c5ba9ee9a47ddc261af4968043 b/modules/markup/tests/repo/repo1_filepreview/objects/3c/95f14e5a0ab2c5ba9ee9a47ddc261af4968043 new file mode 100644 index 0000000000..3e9c0c0d8b Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/3c/95f14e5a0ab2c5ba9ee9a47ddc261af4968043 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/3e/2a4f1b9a15ffa15ea7ffdc06acd302442b3eca b/modules/markup/tests/repo/repo1_filepreview/objects/3e/2a4f1b9a15ffa15ea7ffdc06acd302442b3eca new file mode 100644 index 0000000000..78189a52f6 --- /dev/null +++ b/modules/markup/tests/repo/repo1_filepreview/objects/3e/2a4f1b9a15ffa15ea7ffdc06acd302442b3eca @@ -0,0 +1 @@ +xAN0EYGB;a U=D9=&r}7ҌB^yY8:A X}RXks";uF9x EdВ%~**Z3\v9Й>n8fxk=[9K%L>{7s;av4hXOHԓՆ`K \ No newline at end of file diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/72/1f0ce13d83f93d431b849a554a62948b85f573 b/modules/markup/tests/repo/repo1_filepreview/objects/72/1f0ce13d83f93d431b849a554a62948b85f573 new file mode 100644 index 0000000000..d781d4d248 --- /dev/null +++ b/modules/markup/tests/repo/repo1_filepreview/objects/72/1f0ce13d83f93d431b849a554a62948b85f573 @@ -0,0 +1 @@ +xK1@]$JazJR@w+s۲"@VL&J3%f-GDq2>FjBOEݹ:g\1ꦒkEM6D,Ÿ\Ǹ:\6Olmȩ;ϭ|!GE6ZzYβ mwٛi.x-o"L \ No newline at end of file diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/72/e0a44ea5761c9055995db18019e459576b3b27 b/modules/markup/tests/repo/repo1_filepreview/objects/72/e0a44ea5761c9055995db18019e459576b3b27 new file mode 100644 index 0000000000..7b926dc0d8 Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/72/e0a44ea5761c9055995db18019e459576b3b27 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/72/e1c77b65c7baa0e848557089148833fb54705e b/modules/markup/tests/repo/repo1_filepreview/objects/72/e1c77b65c7baa0e848557089148833fb54705e new file mode 100644 index 0000000000..0bbca73af2 Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/72/e1c77b65c7baa0e848557089148833fb54705e differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/8a/3b1881b5c4e7dc2be7ee1c0f37f93ffbb5ff77 b/modules/markup/tests/repo/repo1_filepreview/objects/8a/3b1881b5c4e7dc2be7ee1c0f37f93ffbb5ff77 new file mode 100644 index 0000000000..0ea93376dc Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/8a/3b1881b5c4e7dc2be7ee1c0f37f93ffbb5ff77 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/8b/ccd5176c25898b57da2551e076f769054e0d8e b/modules/markup/tests/repo/repo1_filepreview/objects/8b/ccd5176c25898b57da2551e076f769054e0d8e new file mode 100644 index 0000000000..394a7bb50d Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/8b/ccd5176c25898b57da2551e076f769054e0d8e differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/95/31b649823095acf5d79ab9e4f8b8d86046352f b/modules/markup/tests/repo/repo1_filepreview/objects/95/31b649823095acf5d79ab9e4f8b8d86046352f new file mode 100644 index 0000000000..ab36311f6f Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/95/31b649823095acf5d79ab9e4f8b8d86046352f differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/ac/769ab4baa91060a4c2f828f53e6c3cc2f708f8 b/modules/markup/tests/repo/repo1_filepreview/objects/ac/769ab4baa91060a4c2f828f53e6c3cc2f708f8 new file mode 100644 index 0000000000..59afaebf4a Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/ac/769ab4baa91060a4c2f828f53e6c3cc2f708f8 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/c5/3110b1957cefc56c4b2d879476ddbe905980bf b/modules/markup/tests/repo/repo1_filepreview/objects/c5/3110b1957cefc56c4b2d879476ddbe905980bf new file mode 100644 index 0000000000..3de089bf6a Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/c5/3110b1957cefc56c4b2d879476ddbe905980bf differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/c9/8762531dd068cd818300a5f5c7dca5da79b510 b/modules/markup/tests/repo/repo1_filepreview/objects/c9/8762531dd068cd818300a5f5c7dca5da79b510 new file mode 100644 index 0000000000..af5b784773 Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/c9/8762531dd068cd818300a5f5c7dca5da79b510 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/c9/913120ed2c1e27c1d7752ecdb7a504dc7cf6be b/modules/markup/tests/repo/repo1_filepreview/objects/c9/913120ed2c1e27c1d7752ecdb7a504dc7cf6be new file mode 100644 index 0000000000..9fc2b7c312 Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/c9/913120ed2c1e27c1d7752ecdb7a504dc7cf6be differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/e7/99b34ea867a0364d0df33f382562db9ff39084 b/modules/markup/tests/repo/repo1_filepreview/objects/e7/99b34ea867a0364d0df33f382562db9ff39084 new file mode 100644 index 0000000000..ef73ed1791 Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/e7/99b34ea867a0364d0df33f382562db9ff39084 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/ee/b243c3395e1921c5d90e73bd739827251fc99d b/modules/markup/tests/repo/repo1_filepreview/objects/ee/b243c3395e1921c5d90e73bd739827251fc99d new file mode 100644 index 0000000000..5515b07d4a Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/ee/b243c3395e1921c5d90e73bd739827251fc99d differ diff --git a/modules/markup/tests/repo/repo1_filepreview/objects/f7/0f10e4db19068f79bc43844b49f3eece45c4e8 b/modules/markup/tests/repo/repo1_filepreview/objects/f7/0f10e4db19068f79bc43844b49f3eece45c4e8 new file mode 100644 index 0000000000..2e15b4fb0a Binary files /dev/null and b/modules/markup/tests/repo/repo1_filepreview/objects/f7/0f10e4db19068f79bc43844b49f3eece45c4e8 differ diff --git a/modules/markup/tests/repo/repo1_filepreview/refs/heads/master b/modules/markup/tests/repo/repo1_filepreview/refs/heads/master index df25bf45f0..709cffca17 100644 --- a/modules/markup/tests/repo/repo1_filepreview/refs/heads/master +++ b/modules/markup/tests/repo/repo1_filepreview/refs/heads/master @@ -1 +1 @@ -4c1aaf56bcb9f39dcf65f3f250726850aed13cd6 +eeb243c3395e1921c5d90e73bd739827251fc99d diff --git a/modules/private/serv.go b/modules/private/serv.go index 480a446954..6c7c753cf0 100644 --- a/modules/private/serv.go +++ b/modules/private/serv.go @@ -40,6 +40,7 @@ type ServCommandResults struct { UserName string UserEmail string UserID int64 + UserMode perm.AccessMode OwnerName string RepoName string RepoID int64 diff --git a/modules/references/references.go b/modules/references/references.go index c61d06d5dc..3b4bcb3706 100644 --- a/modules/references/references.go +++ b/modules/references/references.go @@ -32,7 +32,7 @@ var ( // issueNumericPattern matches string that references to a numeric issue, e.g. #1287 issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`) // issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234 - issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\')`) + issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\'|,)`) // crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository // e.g. org/repo#12345 crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`) diff --git a/modules/references/references_test.go b/modules/references/references_test.go index ffa7f993e3..d5f7c4b4c5 100644 --- a/modules/references/references_test.go +++ b/modules/references/references_test.go @@ -466,6 +466,7 @@ func TestRegExp_issueAlphanumericPattern(t *testing.T) { "ABC-123:", "\"ABC-123\"", "'ABC-123'", + "ABC-123, unknown PR", } falseTestCases := []string{ "RC-08", diff --git a/modules/secret/secret.go b/modules/secret/secret.go index e70ae1839c..e3557b91b9 100644 --- a/modules/secret/secret.go +++ b/modules/secret/secret.go @@ -47,7 +47,7 @@ func AesDecrypt(key, text []byte) ([]byte, error) { cfb.XORKeyStream(text, text) data, err := base64.StdEncoding.DecodeString(string(text)) if err != nil { - return nil, fmt.Errorf("AesDecrypt invalid decrypted base64 string: %w", err) + return nil, fmt.Errorf("AesDecrypt invalid decrypted base64 string: %w - it can be caused by a change of the [security].SECRET_KEY setting or a database corruption - `forgejo doctor check --run check-db-consistency --fix` will get rid of orphaned rows found in the `two_factor` table and may fix this problem if they are the one with the invalid content", err) } return data, nil } diff --git a/modules/setting/annex.go b/modules/setting/annex.go new file mode 100644 index 0000000000..35e9e55c0e --- /dev/null +++ b/modules/setting/annex.go @@ -0,0 +1,25 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "code.gitea.io/gitea/modules/log" +) + +// Annex represents the configuration for git-annex +var Annex = struct { + Enabled bool `ini:"ENABLED"` + DisableP2PHTTP bool `ini:"DISABLE_P2PHTTP"` +}{} + +func loadAnnexFrom(rootCfg ConfigProvider) { + sec := rootCfg.Section("annex") + if err := sec.MapTo(&Annex); err != nil { + log.Fatal("Failed to map Annex settings: %v", err) + } + if !sec.HasKey("DISABLE_P2PHTTP") { + // If DisableP2PHTTP is not explicitly set then use DisableHTTPGit as its default + Annex.DisableP2PHTTP = Repository.DisableHTTPGit + } +} diff --git a/modules/setting/service.go b/modules/setting/service.go index 5a6cc254e0..74ed5cd3c9 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -138,6 +138,11 @@ func CompileEmailGlobList(sec ConfigSection, keys ...string) (globs []glob.Glob) return globs } +// LoadServiceSetting loads the service settings +func LoadServiceSetting() { + loadServiceFrom(CfgProvider) +} + func loadServiceFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("service") Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index c9d30836ac..9710fb23d8 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -153,6 +153,7 @@ func loadCommonSettingsFrom(cfg ConfigProvider) error { loadCamoFrom(cfg) loadI18nFrom(cfg) loadGitFrom(cfg) + loadAnnexFrom(cfg) loadMirrorFrom(cfg) loadMarkupFrom(cfg) loadQuotaFrom(cfg) diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 55de85646c..023ba60fa9 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -103,6 +103,10 @@ func NewFuncMap() template.FuncMap { "AppVer": func() string { return setting.AppVer }, + "AppVerNoMetadata": func() string { + version, _, _ := strings.Cut(setting.AppVer, "+") + return version + }, "AppDomain": func() string { // documented in mail-templates.md return setting.Domain }, diff --git a/modules/util/remove.go b/modules/util/remove.go index d1e38faf5f..39556e5e0b 100644 --- a/modules/util/remove.go +++ b/modules/util/remove.go @@ -4,7 +4,9 @@ package util import ( + "io/fs" "os" + "path/filepath" "runtime" "syscall" "time" @@ -41,10 +43,48 @@ func Remove(name string) error { return err } -// RemoveAll removes the named file or (empty) directory with at most 5 attempts. +// MakeWritable recursively makes the named directory writable. +func MakeWritable(name string) error { + return filepath.WalkDir(name, func(path string, d fs.DirEntry, err error) error { + // NB: this is called WalkDir but it works on a single file too + if err == nil { + info, err := d.Info() + if err != nil { + return err + } + + // Don't try chmod'ing symlinks (will fail with broken symlinks) + if info.Mode()&os.ModeSymlink != os.ModeSymlink { + // 0200 == u+w, in octal unix permission notation + err = os.Chmod(path, info.Mode()|0o200) + if err != nil { + return err + } + } + } + return nil + }) +} + +// RemoveAll removes the named file or directory with at most 5 attempts. func RemoveAll(name string) error { var err error + for i := 0; i < 5; i++ { + // Do chmod -R +w to help ensure the removal succeeds. + // In particular, in the git-annex case, this handles + // https://git-annex.branchable.com/internals/lockdown/ : + // + // > (The only bad consequence of this is that rm -rf .git + // > doesn't work unless you first run chmod -R +w .git) + + err = MakeWritable(name) + if err != nil { + // try again + <-time.After(100 * time.Millisecond) + continue + } + err = os.RemoveAll(name) if err == nil { break diff --git a/options/locale/locale_bg.ini b/options/locale/locale_bg.ini index 924ce710e0..133ffd248e 100644 --- a/options/locale/locale_bg.ini +++ b/options/locale/locale_bg.ini @@ -111,6 +111,7 @@ new_migrate.link = Нова миграция new_org.link = Нова организация copy_generic = Копиране в клипборда copy_error = Неуспешно копиране +copy_path = Копиране на пътя [settings] ui = Тема @@ -159,7 +160,7 @@ comment_type_group_milestone = Етап manage_emails = Управление на адресите на ел. поща permission_read = Четене update_password = Обновяване на паролата -biography_placeholder = Разкажете ни малко за себе си! (Можете да използвате Markdown) +biography_placeholder = Разкажете на другите малко за себе си! (Можете да използвате Маркдаун) orgs = Организации continue = Продължаване blocked_users = Блокирани потребители @@ -224,7 +225,7 @@ key_signature_gpg_placeholder = Започва с „-----BEGIN PGP SIGNATURE--- key_signature_ssh_placeholder = Започва с „-----BEGIN SSH SIGNATURE-----“ saved_successfully = Настройките бяха запазени успешно. no_activity = Няма скорошна дейност -theme_desc = Това ще бъде вашата тема по подразбиране в целия сайт. +theme_desc = Тази тема ще се използва за уеб интерфейса, когато сте влезли. keep_activity_private = Скриване на дейността от профилната страница lookup_avatar_by_mail = Търсене на профилна снимка по адреса на ел. поща password_incorrect = Текущата парола е неправилна. @@ -235,7 +236,7 @@ twofa_disabled = Двуфакторното удостоверяване е из orgs_none = Не сте участник в никакви организации. repos_none = Не притежавате никакви хранилища. blocked_users_none = Няма блокирани потребители. -profile_desc = Контролирайте как вашият профил се показва на другите потребители. Вашият основен адрес на ел. поща ще се използва за известия, възстановяване на паролата и уеб базирани Git операции. +profile_desc = Вашият профил permission_write = Четене и писане twofa_disable = Изключване на двуфакторното удостоверяване twofa_enroll = Включване на двуфакторно удостоверяване @@ -252,6 +253,9 @@ gpg_token_code = echo "%s" | gpg -a --default-key %s --detach-sig language.title = Език по подразбиране language.localization_project = Помогнете ни да преведем Forgejo на вашия език! Научете повече. language.description = Този език ще бъде запазен във вашия акаунт и ще се използва като език по подразбиране, след като влезете. +pronouns_custom = Персонализирани +visibility.limited_tooltip = Видимо само за влезли потребители +pronouns_custom_label = Персонализирани местоимения [packages] container.labels.value = Стойност @@ -280,6 +284,9 @@ dependencies = Зависимости published_by_in = Публикуван %[1]s от %[3]s в %[5]s published_by = Публикуван %[1]s от %[3]s generic.download = Изтеглете пакета от командния ред: +container.details.type = Тип образ +alpine.repository = За хранилището +container.images.title = Образи [tool] hours = %d часа @@ -397,7 +404,7 @@ issues.keyword_search_unavailable = В момента търсенето по к repo_desc_helper = Въведете кратко описание (опционално) mirror_address = Клониране от URL owner_helper = Някои организации може да не се показват в падащото меню поради ограничение за максимален брой хранилища. -new_repo_helper = Хранилището съдържа всички файлове на проекта, включително хронологията на ревизиите. Вече хоствате хранилище другаде? Мигрирайте хранилище. +new_repo_helper = Хранилището съдържа всички файлове на проекта, включително хронологията на ревизиите. Вече хоствате хранилище другаде? Мигрирайте хранилище. repo_name_helper = Добрите имена на хранилища използват кратки, запомнящи се и уникални ключови думи. migrated_from = Мигрирано от %[2]s visibility_description = Само притежателят или участниците в организацията, ако имат права, ще могат да го видят. @@ -424,14 +431,14 @@ settings.add_webhook = Добавяне на уеб-кука template.webhooks = Уеб-куки issues.label_templates.info = Все още няма етикети. Създайте етикет с „Нов етикет“ или използвайте предварително зададен набор от етикети: labels = Етикети -license_helper_desc = Лицензът определя какво могат и какво не могат да правят другите с вашия код. Не сте сигурни кой е подходящ за вашия проект? Вижте Избиране на лиценз. +license_helper_desc = Лицензът определя какво могат и какво не могат да правят другите с вашия код. Не сте сигурни кой е подходящ за вашия проект? Вижте Избиране на лиценз. issues.choose.blank = По подразбиране settings.hooks = Уеб-куки issue_labels = Етикети issue_labels_helper = Изберете набор от етикети readme_helper_desc = Това е мястото, където можете да напишете пълно описание на вашия проект. repo_gitignore_helper = Изберете .gitignore шаблони -auto_init = Да се инициализира хранилище (Добавя .gitignore, License и README) +auto_init = Да се инициализира хранилище template.issue_labels = Етикети за задачите migrate_items_labels = Етикети issues.label_templates.title = Зареждане на предв. зададен набор от етикети @@ -815,7 +822,7 @@ diff.browse_source = Разглеждане на изходния код file_view_rendered = Преглед на визуализация issues.lock_with_reason = заключи като %s и ограничи обсъждането до сътрудници %s milestones.new_subheader = Етапите ви помагат да управлявате задачите и да проследявате напредъка им. -release.edit = редактиране +release.edit = Редактиране activity.published_release_label = Издание activity.navbar.contributors = Допринесли pulls.recently_pushed_new_branches = Изтласкахте в клона %[1]s %[2]s @@ -939,7 +946,7 @@ pulls.approve_count_1 = %d одобрение pulls.can_auto_merge_desc = Тази заявка за сливане може да бъде слята автоматично. pulls.num_conflicting_files_1 = %d конфликтен файл activity.git_stats_commit_n = %d подавания -settings.event_issues = Модификация +settings.event_issues = Изменение branch.delete_head = Изтриване branch.delete = Изтриване на клона „%s“ branch.delete_html = Изтриване на клона @@ -1113,7 +1120,7 @@ pulls.reject_count_1 = %d поискана промяна issues.review.show_resolved = Показване на решено issues.review.hide_resolved = Скриване на решено issues.review.resolve_conversation = Решаване на обсъждането -diff.comment.markdown_info = Поддържа се стилизиране с markdown. +diff.comment.markdown_info = Поддържа се стилизиране с Маркдаун. diff.file_suppressed = Разликите не са показани, защото са твърде много pulls.reject_count_n = %d поискани промени settings.pulls.default_allow_edits_from_maintainers = Позволяване на редакции от поддържащите по подразбиране @@ -1195,6 +1202,95 @@ issues.all_title = Общо issues.new.assign_to_me = Възлагане на мен ext_wiki = Външно уики ext_issues = Външни задачи +readme_helper = Изберете шаблон за файл README +settings.event_pull_request_review_desc = Заявка за сливане е одобрена, отхвърлена или са добавени рецензионни коментари. +settings.event_pull_request_review = Рецензии +issues.filter_sort.relevance = Съответствие +settings.confirm_wiki_branch_rename = Преименуване на клона на уикито +settings.webhook.request = Заявка +settings.webhook.response = Отговор +settings.event_create = Създаване +settings.event_push_only = Събития при изтласкване +settings.event_delete = Изтриване +settings.event_header_repository = Събития за хранилището +settings.event_fork_desc = Хранилище е разклонено. +settings.event_fork = Разклоняване +settings.event_wiki_desc = Уики страница е създадена, преименувана, редактирана или изтрита. +settings.event_issue_milestone = Етапи +settings.event_pull_request_milestone_desc = Етап е добавен, премахнат или изменен. +settings.event_pull_request_label_desc = Етикети на заявка за сливане са добавени или премахнати. +settings.event_pull_request_merge = Сливане на заявка за сливане +settings.archive.tagsettings_unavailable = Настройките за маркери не са налични в архивирани хранилища. +settings.event_desc = Задействане при: +settings.event_create_desc = Клон или маркер е създаден. +generate_from = Генериране от +settings.event_push_desc = Git изтласкване към хранилище. +settings.event_package = Пакет +settings.event_pull_request_label = Етикети +settings.event_pull_request_assign_desc = Заявка за сливане е възложена или отвъзложена. +settings.event_choose = Персонализирани събития… +settings.event_header_issue = Събития при задачи +fork_no_valid_owners = Това хранилище не може да бъде разклонено, защото няма валидни притежатели. +settings.unarchive.text = Разархивирането на хранилище ще възстанови способността му да получава подавания и изтласквания, както и нови задачи и заявки за сливане. +settings.archive.branchsettings_unavailable = Настройките за клонове не са налични в архивирани хранилища. +settings.event_send_everything = Всички събития +settings.event_pull_request_approvals = Одобрения на заявка за сливане +release.invalid_external_url = Невалиден външен URL адрес: "%s" +settings.event_delete_desc = Клон или маркер е изтрит. +settings.discord_icon_url = URL адрес на иконка +settings.discord_icon_url.exceeds_max_length = URL адресът на иконката трябва да е по-малък или равен на 2048 знака +settings.event_push = Изтласкване +settings.event_repository_desc = Хранилище е създадено или изтрито. +settings.slack_icon_url = URL адрес на иконка +settings.event_issue_comment = Коментари +settings.event_pull_request_desc = Заявка за сливане е отворена, затворена, отворена наново или редактирана. +settings.event_issue_comment_desc = Коментар на задача е създаден, редактиран или изтрит. +settings.event_release_desc = Издание е публикувано, обновено или изтрито в хранилище. +settings.event_pull_request_review_request = Искания за рецензия +settings.event_pull_request_enforcement = Принудително изпълнение +diff.git-notes.remove-header = Премахване на бележката +diff.git-notes.add = Добавяне на бележка +settings.event_pull_request_assign = Възлагане +new_advanced_expand = Щракнете за разгъване +new_advanced = Разширени настройки +new_from_template = Използване на шаблон +new_from_template_description = Можете да изберете съществуващо шаблонно хранилище в тази инстанция и да приложите неговите настройки. +settings.event_pull_request_comment = Коментари +repo_gitignore_helper_desc = Изберете кои файлове да не се проследяват от списък с шаблони за обичайните езици. Типичните артефакти, генерирани от инструментите за изграждане, са включени в .gitignore по подразбиране. +object_format_helper = Формат на обектите на хранилището. Не може да се променя по-късно. SHA1 е най-съвместим. +issues.num_reviews_one = %d рецензия +settings.event_pull_request = Изменение +settings.event_issue_label = Етикети +settings.event_issue_assign = Възлагане +settings.event_header_pull_request = Събития при заявка за сливане +settings.event_issue_milestone_desc = Етап е добавен, премахнат или изменен. +settings.event_issue_label_desc = Етикети на задача са добавени или премахнати. +settings.event_issues_desc = Задача е отворена, затворена, отворена наново или редактирана. +settings.webhook.headers = Заглавки +settings.webhook.body = Тяло +settings.event_pull_request_sync = Синхронизирано +settings.event_pull_request_sync_desc = Клонът е обновен автоматично с целевия клон. +settings.event_package_desc = Пакет е създаден или изтрит в хранилище. +template_description = Шаблонните хранилища позволяват на потребителите да генерират нови хранилища със същата структура на директориите, файлове и опционални настройки. +auto_init_description = Поставете началото на Git историята с README и по избор добавете файлове License и .gitignore. +pulls.sign_in_require = Влезте, за да създадете нова заявка за сливане. +issues.num_reviews_few = %d рецензии +diff.git-notes.remove-body = Тази бележка ще бъде премахната. +issues.review.add_remove_review_requests = поиска рецензии от %[1]s и премахна заявки за рецензия за %[2]s %[3]s +form.name_pattern_not_allowed = Шаблонът "%s" не е разрешен в име на хранилище. +settings.wiki_rename_branch_main_notices_2 = Това ще преименува перманентно вътрешния клон на уикито на хранилището %s. Съществуващите изтегляния ще трябва да бъдат обновени. +settings.event_pull_request_milestone = Етапи +settings.event_pull_request_comment_desc = Заявка за сливане е създадена, редактирана или изтрита. +settings.event_issue_assign_desc = Задача е възложена или отвъзложена. +settings.event_pull_request_review_request_desc = Рецензия на заявка за сливане е поискана или е премахната. +generate_repo = Генериране на хранилище +default_branch_helper = Стандартният клон е основния клон за заявки за сливане и подавания на код. + +issues.reaction.add = Добавяне на реакция +issues.reaction.alt_few = %[1]s реагира с %[2]s. +issues.reaction.alt_many = %[1]s и още %[2]d реагираха с %[3]s. +issues.reaction.alt_remove = Премахване на реакция %[1]s от коментара. +issues.reaction.alt_add = Добавяне на реакция %[1]s към коментара. [modal] confirm = Потвърждаване @@ -1218,6 +1314,12 @@ buttons.italic.tooltip = Добавяне на курсив текст buttons.link.tooltip = Добавяне на връзка buttons.disable_monospace_font = Изключване на равноширокия шрифт buttons.ref.tooltip = Препратка към задача или заявка за сливане +table_modal.label.columns = Колони +table_modal.label.rows = Редове +table_modal.placeholder.content = Съдържание +table_modal.placeholder.header = Заглавка +buttons.new_table.tooltip = Добавяне на таблица +table_modal.header = Добавяне на таблица [org] teams.write_access = Писане @@ -1249,7 +1351,7 @@ settings.visibility.public = Публична settings.visibility.limited_shortname = Ограничена settings.visibility.private_shortname = Частна settings.permission = Разрешения -settings.visibility.limited = Ограничена (видима само за удостоверени потребители) +settings.visibility.limited = Ограничена (видима само за влезли потребители) settings.visibility.private = Частна (видима само за участниците в организацията) org_name_helper = Имената на организациите е добре да са кратки и запомнящи се. org_full_name_holder = Пълно име на организацията @@ -1330,6 +1432,9 @@ err_empty_admin_email = Администраторският адрес на е password_algorithm = Алгоритъм за хеш. на паролите default_keep_email_private = Скриване на адресите на ел. поща по подразбиране invalid_password_algorithm = Невалиден алгоритъм за хеш. на паролите +err_admin_name_is_reserved = Потребителското име на администратора е невалидно, потребителското име е резервирано +err_admin_name_pattern_not_allowed = Потребителското име на администратора е невалидно, потребителското име съответства с резервиран шаблон +err_admin_name_is_invalid = Потребителското име на администратора е невалидно [filter] string.asc = А - Я @@ -1361,6 +1466,14 @@ activate_account.text_1 = Здравейте, %[1]s, благодарим activate_email.text = Моля, щракнете върху следната връзка, за да потвърдите своя адрес на ел. поща в рамките на %s: activate_email = Потвърдете своя адрес на ел. поща activate_account.text_2 = Моля, щракнете върху следната връзка, за да активирате своя акаунт в рамките на %s: +issue_assigned.issue = @%[1]s ви възложи задача %[2]s в хранилище %[3]s. +issue.action.push_n = @%[1]s изтласка %[3]d подавания към %[2]s +issue.action.push_1 = @%[1]s изтласка %[3]d подаване към %[2]s +repo.transfer.subject_to_you = %s иска да прехвърли хранилище "%s" към вас +issue.action.merge = @%[1]s сля #%[2]d в %[3]s. +issue_assigned.pull = @%[1]s ви възложи заявката за сливане %[2]s в хранилище %[3]s. +issue.action.ready_for_review = @%[1]s отбеляза тази заявка за сливане като готова за рецензиране. +repo.transfer.subject_to = %s иска да прехвърли хранилище "%s" към %s [user] joined_on = Присъединени на %s @@ -1392,6 +1505,9 @@ followers.title.one = Последовател following.title.one = Следван following.title.few = Следвани public_activity.visibility_hint.self_public = Вашата дейност е видима за всички, с изключение на взаимодействията в частни пространства. Конфигуриране. +form.name_pattern_not_allowed = Шаблонът "%s" не е разрешен в потребителско име. +form.name_reserved = Потребителското име "%s" е резервирано. +public_activity.visibility_hint.self_private_profile = Вашата дейност е видима само за вас и администраторите на инстанцията, тъй като вашият профил е частен. Конфигуриране. [home] filter = Други филтри @@ -1661,6 +1777,7 @@ variables.creation = Добавяне на променлива variables.deletion.failed = Неуспешно премахване на променлива. runners.task_list.repository = Хранилище runners.description = Описание +runs.no_workflows.help_no_write_access = За да научите повече за Forgejo Actions, вижте документацията. [heatmap] less = По-малко diff --git a/options/locale/locale_ca.ini b/options/locale/locale_ca.ini index ec8ae32668..dda88b1b46 100644 --- a/options/locale/locale_ca.ini +++ b/options/locale/locale_ca.ini @@ -1,10 +1,10 @@ [common] -home = inici +home = Inici dashboard = Panell de control explore = Explorar help = Ajuda logo = Logo -sign_in = Entrar +sign_in = Iniciar sessió sign_in_with_provider = Entra amb %s sign_in_or = o sign_out = Sortir @@ -15,7 +15,7 @@ page = Pàgina template = Plantilla language = Idioma notifications = Notificacions -active_stopwatch = Registre de Temps Actiu +active_stopwatch = Registre de temps actiu create_new = Crear… user_profile_and_more = Perfil i Configuració… signed_in_as = Entrat com @@ -140,6 +140,14 @@ filter.not_archived = No arxivats filter.not_fork = No és fork filter.is_fork = Són forks +new_repo.title = Nou repositori +new_migrate.title = Nova migració +new_org.title = Nova organització +new_repo.link = Nou repositori +new_migrate.link = Nova migració +new_org.link = Nova organització +copy_path = Copiar ruta + [search] milestone_kind = Cerca fites... fuzzy = Difusa @@ -167,6 +175,9 @@ exact = Exacte exact_tooltip = Inclou només resultats que són exactament el terme de cerca issue_kind = Cerca problemes... +regexp = Expressió regular +regexp_tooltip = Interpreta el terme de cerca com una expressió regular + [heatmap] number_of_contributions_in_the_last_12_months = %s contribucions en els últims 12 mesos contributions_zero = Cap contribució @@ -337,6 +348,72 @@ manual_activation_only = Contacti amb l'administrador de lloc per a completar l' remember_me = Recordar aquest dispositiu create_new_account = Registrar compte +forgot_password_title = Contrasenya oblidada +forgot_password = Contrasenya oblidada? +hint_login = Ja tens compte? Entra ara! +hint_register = Necessites un compte? Registra't ara. +sign_up_button = Registra't ara. +sign_up_successful = S'ha creat el compte correctament. Benvingut! +confirmation_mail_sent_prompt = S'ha enviat un correu electrònic de confirmació a %s. Per tal de completar el registre, reviseu la safata d'entrada i seguiu l'enllaç que se us ha enviat en els següents %s. Si l'adreça de correu és incorrecta, podreu accedir al compte i demanar d'enviar un altre correu de confirmació a una altra adreça. +must_change_password = Actualitza la contrasenya +allow_password_change = Requereix a l'usuari canviar la contrasenya (recomanat) +reset_password_mail_sent_prompt = S'ha enviat un correu electrònic de confirmació a %s. Per tal de completar el procés de recuperació del compte, reviseu la safata d'entrada i seguiu l'enllaç que se us ha enviat en els següents %s. +active_your_account = Activeu el compte +account_activated = El compte s'ha activat +prohibit_login = El compte està en suspensió +prohibit_login_desc = S'ha suspès la interacció del vostre compte amb la instància. Contacteu amb l'administrador per a recuperar-ne l'accés. +resent_limit_prompt = Fa poc que heu sol·licitat un correu electrònic d'activació. Si us plau, espereu 3 minuts i torneu a intentar-ho. +has_unconfirmed_mail = Hola %s, la vostra adreça de correu no s'ha confirmat (%s). Si no heu rebut un correu de confirmació o necessiteu que l'enviem de nou, feu clic al botó següent. +change_unconfirmed_email_summary = Canvieu l'adreça de correu on s'envia el correu d'activació. +change_unconfirmed_email = Si heu proporcionat una direcció de correu incorrecta durant el registre, la podeu canviar aquí baix i se us enviarà una confirmació a l'adreça nova. +change_unconfirmed_email_error = No s'ha pogut canviar l'adreça de correu: %v +resend_mail = Feu clic aquí per tornar a enviar el correu electrònic d'activació +send_reset_mail = Enviar correu electrònic de recuperació del compte +reset_password = Recuperació del compte +invalid_code = El codi de confirmació no és vàlid o ha caducat. +invalid_code_forgot_password = El codi de confirmació és invàlid o ha caducat. Feu click aquí per a iniciar una sessió nova. +invalid_password = La contrasenya no coincideix amb la que es va utilitzar per a crear el compte. +reset_password_helper = Recuperar compte +reset_password_wrong_user = Heu iniciat sessió com a %s, però l'enllaç de recuperació pertany a %s +password_too_short = La longitud de la contrasenya no pot ser inferior a %d caràcters. +non_local_account = Els usuaris no locals no poden actualitzar la seva contrasenya mitjançant l'interfície web de Forgejo +verify = Verificar +unauthorized_credentials = Les credencials són incorrectes o han caducat. Torneu a executar l'ordre o visiteu %s per a més informació +scratch_code = Codi de recuperació +use_scratch_code = Utilitzar un codi de recuperació +use_onetime_code = Utilitzar un codi d'un sol ús +twofa_scratch_used = Ja heu utilitzat el vostre codi de recuperació. Se us ha redirigit a la pàgina de configuració de l'autenticació de doble factor per tal d'eliminar el dispositiu o generar un codi de recuperació nou. +twofa_passcode_incorrect = El codi d'accés és incorrecte. Si heu perdut el dispositiu, useu el codi de recuperació per a entrar. +twofa_scratch_token_incorrect = El codi de recuperació és incorrecte. +login_userpass = Entra +oauth_signup_tab = Registrar compte nou +oauth_signup_title = Completar compte nou +oauth_signup_submit = Completar compte +oauth_signin_tab = Vincular a un compte existent +oauth_signin_title = Entreu per a autoritzar el compte vinculat +oauth_signin_submit = Vincular compte +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. +oauth.signin.error.access_denied = S'ha denegat la sol·licitud d'autorització. +oauth.signin.error.temporarily_unavailable = Ha fallat l'autorització perquè el servidor d'autenticació no està disponible temporalment. Intenteu-ho de nou més tard. +openid_connect_submit = Connectar +openid_connect_title = Entreu a un compte existent +openid_register_title = Crear un compte nou +openid_signin_desc = Introduïu la URI OpenID. Per exemple: alice.openid.example.org o https://openid.example.org/alice. +disable_forgot_password_mail = La recuperació de comptes està deshabilitada perquè no hi ha configuració de correu electrònic. Si us plau, contacteu 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. +email_domain_blacklisted = No podeu registrar-vos amb el correu electrònic. +authorize_application = Autoritzar aplicació +authorize_redirect_notice = Sereu redirigits a %s si autoritzeu aquesta aplicació. +authorize_application_created_by = Aquesta aplicació l'ha creat %s. +authorize_application_description = Si li concediu l'accés podrà accedir i escriure a tota la informació del vostre compte, inclòs repositoris privats i organitzacions. +authorize_title = Autoritzeu "%s" a accedir al vostre compte? +authorization_failed = Ha fallat l'autorització +authorization_failed_desc = Ha fallat l'autorització perquè s'ha detectat una sol·licitud invàlida. Si us plau, contacteu amb el responsable de l'aplicació que heu intentat autoritzar. +password_pwned = La contrasenya que heu introduït es troba en una llista de contrasenyes robades exposades en dades filtrades públicament. Si us plau, intenteu-ho de nou amb una contrasenya diferent i considereu modificar aquesta contrasenya a tot arreu on la utilitzeu. +password_pwned_err = No s'ha pogut completar la sol·licitud a HaveIBeenPwned +last_admin = No podeu eliminar l'últim usuari administrador. Com a mínim n'hi ha d'haver un. +back_to_sign_in = Torneu a entrar + [editor] buttons.indent.tooltip = Aniua els elements un nivell buttons.unindent.tooltip = Desaniuna els elements un nivell @@ -355,6 +432,13 @@ buttons.list.ordered.tooltip = Afegir una llista enumerada buttons.list.task.tooltip = Afegir una llista de tasques buttons.mention.tooltip = Mencionar un usuari o equip +buttons.new_table.tooltip = Afegir taula +table_modal.header = Afegir taula +table_modal.placeholder.header = Capçalera +table_modal.placeholder.content = Contingut +table_modal.label.rows = Files +table_modal.label.columns = Columnes + [home] my_orgs = Organitzacions show_more_repos = Mostra més repositoris… @@ -381,4 +465,15 @@ filter = Altres filtres footer.software = Sobre aquest software footer.links = Enllaços navbar = Barra de navegació -footer = Peu de pàgina \ No newline at end of file +footer = Peu de pàgina + +[mail] +view_it_on = Veure a %s +reply = o responeu directament a aquest correu +link_not_working_do_paste = No funciona l'enllaç? Proveu a copiar-lo i enganxar-lo al navegador web. +hi_user_x = Hola %s, +activate_account = Si us plau, activeu el compte +activate_account.text_1 = Hola %[1]s, gràcies per registrar-te a %[2]s! +admin.new_user.user_info = Informació d'usuari +admin.new_user.text = Si us plau, cliqueu aui per administrar aquest usuari des del panell d'administració. +register_notify = Benvinguts a %s \ No newline at end of file diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index bd983164b2..1894aeb81c 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -4,7 +4,7 @@ dashboard=Přehled explore=Procházet help=Nápověda logo=Logo -sign_in=Přihlášení +sign_in=Přihlásit se sign_in_with_provider = Přihlásit se přes %s sign_in_or=nebo sign_out=Odhlásit se @@ -517,8 +517,8 @@ issue_assigned.issue=@%[1]s vás přiřadil/a k problému %[2]s v repozitáři % issue.x_mentioned_you=@%s vás zmínil/a: issue.action.force_push=%[1]s vynutil/a nahrání %[2]s z %[3]s do %[4]s. -issue.action.push_1=@%[1]s nahrál/a %[3]d commit do %[2]s -issue.action.push_n=@%[1]s nahrál/a %[3]d commity do %[2]s +issue.action.push_1=Uživatel @%[1]s nahrál %[3]d revizi do %[2]s +issue.action.push_n=Uživatel @%[1]s nahrál %[3]d revizí do %[2]s issue.action.close=@%[1]s uzavřel/a #%[2]d. issue.action.reopen=@%[1]s znovu otevřel/a #%[2]d. issue.action.merge=@%[1]s sloučil/a #%[2]d do %[3]s. @@ -590,9 +590,9 @@ AuthName=Název ověření AdminEmail=E-mailová adresa správce NewBranchName=Název nové větve -CommitSummary=Shrnutí commity -CommitMessage=Zpráva commitu -CommitChoice=Výběr commitu +CommitSummary=Shrnutí revize +CommitMessage=Zpráva revize +CommitChoice=Výběr revize TreeName=Cesta k souboru Content=Obsah @@ -681,6 +681,8 @@ To = Název větve Biography = Životopis AccessToken = Přístupový token +email_domain_is_not_allowed = Doména uživatelské e-mailové adresy %s je v rozporu se seznamem EMAIL_DOMAIN_ALLOWLIST nebo EMAIL_DOMAIN_BLOCKLIST. Ujistěte se, že je vaše adresa správně nastavena. + [user] change_avatar=Změnit váš avatar… joined_on=Přidal/a se %s @@ -747,7 +749,7 @@ webauthn=Dvoufázové ověření (bezpečnostní klíče) public_profile=Veřejný profil biography_placeholder=Řekněte ostatním něco o sobě! (Je podporován Markdown) location_placeholder=Sdílejte svou přibližnou polohu s ostatními -profile_desc=Nastavte, jak bude váš profil zobrazen ostatním uživatelům. Vaše hlavní e-mailová adresa bude použita pro oznámení, obnovení hesla a operace Git. +profile_desc=O vás password_username_disabled=Externí uživatelé nemohou měnit svoje uživatelské jméno. Kontaktujte prosím svého administrátora pro více detailů. full_name=Celé jméno website=Web @@ -767,7 +769,7 @@ language=Jazyk ui=Motiv vzhledu hidden_comment_types=Skryté typy komentářů hidden_comment_types_description=Zde zkontrolované typy komentářů nebudou zobrazeny na stránkách problémů. Zaškrtnutí „Štítek“ například odstraní všechny komentáře „ přidal/odstranil pour vérifier la signature de l'index : alpine.registry.info=Choisissez $branch et $repository dans la liste ci-dessous. alpine.install=Pour installer le paquet, exécutez la commande suivante : -alpine.repository=Informations sur le Dépôt +alpine.repository=Informations sur le dépôt alpine.repository.branches=Branches alpine.repository.repositories=Dépôts alpine.repository.architectures=Architectures @@ -3682,7 +3711,7 @@ conda.install=Pour installer le paquet en utilisant Conda, exécutez la commande container.details.type=Type d'image container.details.platform=Plateforme container.pull=Tirez l'image depuis un terminal : -container.digest=Empreinte : +container.digest=Empreinte container.multi_arch=SE / Arch container.layers=Calques d'image container.labels=Labels @@ -3693,7 +3722,7 @@ cran.install=Pour installer le paquet, exécutez la commande suivante : debian.registry=Configurez ce registre à partir d'un terminal : debian.registry.info=Choisissez $distribution et $component dans la liste ci-dessous. debian.install=Pour installer le paquet, exécutez la commande suivante : -debian.repository=Infos sur le Dépôt +debian.repository=Infos sur le dépôt debian.repository.distributions=Distributions debian.repository.components=Composants debian.repository.architectures=Architectures @@ -3797,6 +3826,7 @@ arch.version.conflicts = Conflits arch.version.replaces = Remplace arch.version.backup = Sauvegarde arch.version.makedepends = Faire des dépendances +container.images.title = Images [secrets] secrets=Secrets @@ -3945,7 +3975,7 @@ keyword_search_unavailable = La recherche par mot-clé n'est pas disponible actu fuzzy_tooltip = Inclure les résultats proches des termes recherchés match = Correspondance match_tooltip = Uniquement inclure les résultats correspondant exactement aux termes recherchés -repo_kind = Chercher dans les dépôt... +repo_kind = Chercher dans les dépôts... user_kind = Chercher les utilisateurs... org_kind = Chercher les organisations... team_kind = Chercher les équipes... diff --git a/options/locale/locale_he.ini b/options/locale/locale_he.ini new file mode 100644 index 0000000000..61845d49f3 --- /dev/null +++ b/options/locale/locale_he.ini @@ -0,0 +1,239 @@ +[common] +home = בית +dashboard = מבט על +help = עזרה +logo = לוגו +sign_in = כניסה +sign_in_with_provider = כניסה דרך %s +sign_in_or = או +sign_out = יציאה מהחשבון +sign_up = הרשמה +link_account = חיבור חשבון +register = הרשמה +version = גרסה +powered_by = רץ על %s +page = דף +template = תבנית +language = שפה +notifications = הודעות +active_stopwatch = סטופר +create_new = חדש… +user_profile_and_more = פרופיל והגדרות… +signed_in_as = שלום +enable_javascript = אתר זה משתמש בJavaScript. +toc = תוכן הענינים +licenses = רישיונות +return_to_forgejo = חזרה לפורג'ו +more_items = עוד אפשרויות +username = שם משתמש +email = כתובת אימייל +password = סיסמה +access_token = קוד גישה +captcha = CAPTCHA +twofa = אימות דו־שלבי +twofa_scratch = קוד אימות דו־שלבי +passcode = קוד כניסה +webauthn_insert_key = יש להכניס את מפתח אבטחך +webauthn_sign_in = יש ללחוץ על הכפתור שעל מפתח האבטחה. אם אין כפתור, אפשר להוציא את המפתח ולחבר אותו שוב. +webauthn_press_button = נא ללחוץ על הכפתור שעל מפתח האבטחה… +webauthn_error = קריאת מפתח האבטחה נכשלה. +webauthn_unsupported_browser = הדפדפן שלך לא תומך בWebAuthn. +webauthn_error_unknown = שגיאה לא ידועה, אפשר לנסות שוב. +webauthn_error_insecure = הפרוטוקול WebAuthn לא תומך בחיבורים לא מאובטחים, למעט דרך "localhost" או "127.0.0.1" +webauthn_error_unable_to_process = שרת זה נכשל בעיבוד בקשתך. +webauthn_error_duplicated = מפתח האבטחה לא יכול לשמש לבקשה זו. נא לוודא שהמפתח לא רשום. +webauthn_error_empty = שם המפתח הוא שדה חובה. +webauthn_error_timeout = קריאת מפתחך לקחה יותר מדי זמן. אפשר לטעון מחדש את הדף ולנסות שוב. +repository = קרפיף +organization = ארגון +mirror = מראה +new_mirror = מראה חדשה +new_fork = מזלוג חדש של קרפיף זה +new_project = פרויקט חדש +new_project_column = עמודה חדשה +admin_panel = לוח ניהול מערכת +settings = הגדרות +your_profile = פרופיל +your_starred = כיכבת +your_settings = הגדרות +new_repo.title = קרפיף חדש +new_migrate.title = יבוא קרפיף +new_org.title = ארגון חדש +new_repo.link = קרפיף חדש +new_migrate.link = יבוא קרפיף +new_org.link = ארגון חדש +all = הכל +sources = מקורות +mirrors = מראות +collaborative = שיתופי +forks = מזלוגים +activities = פעילויות +pull_requests = בקשות מיזוג +issues = סוגיות +milestones = מטרות +ok = אישור +cancel = ביטול +retry = לנסות שוב +rerun = הרצה חוזרת +save = שמירה +add = הוספה +add_all = הוספת הכל +remove = הסרה +remove_all = הסרת הכל +remove_label_str = הסרת "%s" +edit = עריכה +test = בדיקה +enabled = מופעל +disabled = כבוי +locked = נעול +copy = העתקה +copy_generic = העתקה לCtrl + C +copy_url = העתקת קישור +copy_hash = העתקת קוד גיבוב +copy_path = העתקת מיקום קובץ +copy_content = העתקת תוכן +copy_branch = העתקת שם ענף +copy_success = הועתק! +copy_error = העתקה נכשלה +copy_type_unsupported = אי אפשר להעתיק קבצים מסוג זה +write = כתיבה +preview = תצוגה מקדימה +loading = נטען… +error = שגיאה +error404 = דף זה לא קיים או שאין לך אילו גישה. +go_back = אחורה +invalid_data = הבנת הקלט נכשלה: %v +never = אף פעם +unknown = לא ידוע +rss_feed = פיד RSS +pin = הצמדה +unpin = ביטול הצמדה +archived = ארכיון +concept_system_global = גלובלי +concept_user_individual = אישי +concept_code_repository = קרפיף +concept_user_organization = ארגון +show_timestamps = הצגת זמנים +show_log_seconds = הצגת שניות +show_full_screen = מסך מלא +download_logs = הורדת לוגים +confirm_delete_selected = למחוק את כל הפריטים המסומנים? +name = שם +value = ערך +filter = מסנן +filter.clear = ניקוי מסננים +filter.is_archived = בארכיון +filter.not_archived = מחוץ לארכיון +filter.is_fork = רק מזלוגים +filter.not_fork = להוציא מזלוגים +filter.is_mirror = רק מראות +filter.not_mirror = להוציא מראות +filter.is_template = רק תבניות +filter.not_template = להוציא תבניות +filter.public = ציבורי +filter.private = פרטי + +[search] +search = חיפוש... +type_tooltip = סוג חיפוש +fuzzy = מקורב +fuzzy_tooltip = תוצאות יתאימו לתוכן תיבת החיפוש בקירוב; מומלץ כנגד שגיאות כתיב +union = מילות מפתח +union_tooltip = תוצאות יכללו לפחות מילת מפתח אחת; אפשר להפריד מילות מפתח עם רווחים +exact = מדויק +exact_tooltip = תוצאות יתאימו במדויק לתוכן תיבת החיפוש +regexp = רג'קס +repo_kind = חיפוש קרפיפים... +user_kind = חיפוש אנשים... +org_kind = חיפוש ארגונים... +team_kind = חיפוש צוותים... +code_kind = חיפוש קוד... +code_search_unavailable = חיפוש קוד לא זמין. נא לדווח למנהלי המערכת. +package_kind = חיפוש חבילות... +project_kind = חיפוש פרוייקטים... +branch_kind = חיפוש ענפים... +commit_kind = חיפוש קומיטים... +runner_kind = חיפוש מריצים... +no_results = לא נמצאו תוצאות. +issue_kind = חיפוש סוגיות... +keyword_search_unavailable = חיפוש מילות מפתח לא זמין. נא לדווח למנהלי המערכת. + +[aria] +navbar = סרגל הניווט +footer.software = על תוכנה זו +footer.links = קישורים + +[heatmap] +number_of_contributions_in_the_last_12_months = % תרומות ב־12 החודשים האחרונים +contributions_zero = אפס תרומות +contributions_format = {contributions} ב{day} ל{month} {year} +contributions_one = תרומה +contributions_few = תרומות +less = פחות +more = יותר + +[editor] +buttons.heading.tooltip = הוספת כותרת +buttons.bold.tooltip = הדגשת טקסט +buttons.italic.tooltip = הטיית טקסט +buttons.quote.tooltip = ציטוט +buttons.code.tooltip = הוספת קוד +buttons.link.tooltip = הוספת קישור +buttons.list.unordered.tooltip = הוספת רשימה לא ממוספרת +buttons.list.ordered.tooltip = הוספת רשימה ממוספרת +buttons.list.task.tooltip = הוספת רשימת משימות +buttons.mention.tooltip = תיוג אדם או צוות +buttons.ref.tooltip = ריפרור לסוגיה או בקשת מיזוג +buttons.switch_to_legacy.tooltip = מעבר לעורך הישן +buttons.enable_monospace_font = הפעלת גופן קבוע־רוחב +buttons.disable_monospace_font = כיבוי גופן קבוע־רוחב +buttons.new_table.tooltip = הוספת טבלה +table_modal.header = הוספת טבלה +table_modal.placeholder.header = כותרת +table_modal.placeholder.content = תוכן +table_modal.label.rows = שורות +table_modal.label.columns = עמודות + +[filter] +string.asc = סדר אלפבתי עולה +string.desc = סדר אלפבתי יורד + +[error] +occurred = קרתה שגיאה +not_found = המטרה לא נמצאה. +network_error = שגיאת אינטרנט +server_internal = שגיאת שרת פנימית + +[startpage] +install = קל להתקנה +lightweight = קל +license = קוד פתוח + +[install] +install = התקנה +title = הגדרה ראשונית +db_title = הגדרות מסד מידע +db_type = סוג מסד מידע +user = שם משתמש +password = סיסמה +db_name = שם מסד המידע +db_schema = סכימה +db_schema_helper = תוכן ריק משמע ערך ברירת המחדל ("public") של מסד המידע. +ssl_mode = SSL +err_empty_admin_password = סיסמה של מנהל מערכת לא יכולה להיות ריקה. +err_empty_admin_email = כתובת אימייל של מנהל מערכת היא חובה. +general_title = הגדרות כלליות +app_name = שם שרת זה + +[mail] +issue_assigned.pull = @%[1]s שייך אותך לבקשת המיזוג %[2]s בקרפיף %[3]s. +issue_assigned.issue = @%[1]s שייך אותך לסוגיה %[2]s בקרפיף %[3]s. +repo.transfer.subject_to = %s רוצה להעביר את הקרפיף "%s" ל־%s +repo.transfer.subject_to_you = %s רוצה להעביר את הקרפיף "%s" אליך +repo.collaborator.added.text = הוספת בתור פועל לקרפיף: + +[form] +RepoName = שם קרפיף +repo_name_been_taken = כבר יש קרפיף בשם זה. +repository_force_private = פרטיות כפויה מופעלת: קרפיפים פרטיים לא יכולים להעשות ציבוריים. +repository_files_already_exist = כבר יש קבצים בקרפיף זה. יש לדבר עם מנהל המערכת כדי לתקן את הבעיה. diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 57555b90a2..ef94d2de0c 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -787,6 +787,7 @@ file_too_large=Ez a fájl túl nagy ahhoz, hogy megjelenítsük. video_not_supported_in_browser=A böngésző nem támogatja a HTML5 video tag-et. audio_not_supported_in_browser=A böngésző nem támogatja a HTML5 audio tag-et. stored_lfs=Git LFS-el eltárolva +stored_annex=Git Annex-el eltárolva symbolic_link=Szimbolikus hivatkozás commit_graph=Commit gráf commit_graph.hide_pr_refs=Pull request-ek elrejtése @@ -799,6 +800,7 @@ editor.upload_file=Fájl feltöltése editor.edit_file=Fájl szerkesztése editor.preview_changes=Változások előnézete editor.cannot_edit_lfs_files=LFS fájlok nem szerkeszthetőek a webes felületen. +editor.cannot_edit_annex_files=Annex fájlok nem szerkeszthetőek a webes felületen. editor.cannot_edit_non_text_files=Bináris fájlok nem szerkeszthetőek a webes felületen. editor.edit_this_file=Fájl szerkesztése editor.this_file_locked=Zárolt állomány diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 1e0044e4ce..8cf3457aae 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -596,6 +596,7 @@ file_permalink=Permalink file_too_large=Berkas terlalu besar untuk ditampilkan. stored_lfs=Tersimpan dengan GIT LFS +stored_annex=Tersimpan dengan GIT Annex commit_graph=Grafik Komit blame=Salahkan normal_view=Pandangan Normal @@ -607,6 +608,7 @@ editor.upload_file=Unggah Berkas editor.edit_file=Sunting Berkas editor.preview_changes=Tinjau Perubahan editor.cannot_edit_lfs_files=Berkas LFS tidak dapat disunting dalam antarmuka web. +editor.cannot_edit_annex_files=Berkas Annex tidak dapat disunting dalam antarmuka web. editor.cannot_edit_non_text_files=Berkas biner tidak dapat disunting dalam antarmuka web. editor.edit_this_file=Sunting Berkas editor.this_file_locked=Berkas terkunci diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index 3a6e844de2..b3cf17fccc 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -680,6 +680,7 @@ file_view_rendered=Skoða Unnið file_copy_permalink=Afrita Varanlega Slóð stored_lfs=Geymt með Git LFS +stored_annex=Geymt með Git Annex commit_graph.hide_pr_refs=Fela Sameiningarbeiðnir commit_graph.monochrome=Einlitað commit_graph.color=Litað diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index fa5853c92e..4bfc6762b8 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -220,7 +220,7 @@ platform=Multipiattaforma lightweight=Leggero lightweight_desc=Forgejo ha requisiti minimi bassi e può funzionare su un economico Raspberry Pi. Risparmia l'energia della tua macchina! license=Open Source -license_desc=Ottieni Forgejo! Partecipa per contribuire a rendere questo progetto ancora migliore. Non aver paura di diventare un collaboratore! +license_desc=Ottieni Forgejo! Partecipa per contribuire a rendere questo progetto ancora più bello. Non aver paura di diventare collaborante! install_desc = Semplicemente avvia l'eseguibile per la tua piattaforma, distribuiscilo con Docker, oppure scarica il pacchetto. [install] @@ -511,11 +511,11 @@ issue.action.push_n=@%[1]s ha immesso %[3]d commit presso %[2]s issue.action.close=@%[1]s chiuso #%[2]d. issue.action.reopen=@%[1]s riaperto #%[2]d. issue.action.merge=@%[1]s unito #%[2]d in %[3]s. -issue.action.approve=@%[1]s ha approvato questa pull request. -issue.action.reject=@%[1]s ha richiesto modifiche su questa pull request. -issue.action.review=@%[1]s ha commentato questa pull request. -issue.action.review_dismissed=@%[1]s ha respinto l'ultima recensione da %[2]s per questa pull request. -issue.action.ready_for_review=@%[1]s ha contrassegnato questa pull request pronta per la revisione. +issue.action.approve=@%[1]s ha approvato questa richiesta di modifica. +issue.action.reject=@%[1]s ha richiesto modifiche su questa richiesta. +issue.action.review=@%[1]s ha commentato questa richiesta di modifica. +issue.action.review_dismissed=@%[1]s ha respinto l'ultima revisione di %[2]s per questa richiesta di modifica. +issue.action.ready_for_review=@%[1]s ha contrassegnato questa richiesta di modifica come pronta per la revisione. issue.action.new=@%[1]s creato #%[2]d. issue.in_tree_path=In %s: @@ -532,8 +532,8 @@ repo.transfer.subject_to_you=%s ti vorrebbe trasferire il repositorio "%s" repo.transfer.to_you=tu repo.transfer.body=Per accettare o respingerla visita %s o semplicemente ignorarla. -repo.collaborator.added.subject=%s ti ha aggiunto a %s come collaboratorə -repo.collaborator.added.text=Sei statə aggiuntə come collaboratorə al repositorio: +repo.collaborator.added.subject=%s ti ha aggiunto a %s come collaborante +repo.collaborator.added.text=Sei statə aggiuntə come collaborante al repositorio: reply = o rispondi direttamente a questa email admin.new_user.subject = Il nuovo utente %s si è appena registrato admin.new_user.user_info = Informazioni utente @@ -690,7 +690,7 @@ joined_on = Membro dal %s block_user = Blocca utente block_user.detail_1 = Questo utente non ti seguirà più. block_user.detail_2 = Quest'utente non potrà interagire né con i tuoi repositori, né con le segnalazioni che hai aperto, né con i tuoi commenti. -block_user.detail_3 = Non sarete in grado di aggiungervi come collaboratorɜ del repositorio. +block_user.detail_3 = Non sarete in grado di aggiungervi come collaboranti del repositorio. code = Codice block = Blocca unblock = Sblocca @@ -762,7 +762,7 @@ comment_type_group_lock=Stato blocco comment_type_group_review_request=Richiesta di revisione comment_type_group_pull_request_push=Commit aggiunti comment_type_group_project=Progetto -comment_type_group_issue_ref=Riferimento del problema +comment_type_group_issue_ref=Riferimento alla segnalazione saved_successfully=Le impostazioni sono state salvate correttamente. privacy=Privacy keep_activity_private_popup=La tua attività sarà visibile solo a te e agli amministratori dell'istanza @@ -1029,7 +1029,7 @@ oauth2_application_locked = Forgejo preregistra alcune applicazioni OAuth2 all'a hooks.desc = Aggiungi richiami HTTP che saranno innescati per tutti i progetti che possiedi. repos_none = Non possiedi alcun progetto. blocked_users_none = Non ci sono utenti bloccati. -keep_email_private_popup = Questo nasconderà il tuo indirizzo e-mail nel tuo profilo, nelle pull request e quando modifichi un file usando l'interfaccia web. I commit inoltrati non saranno modificati. Usa %s nei commit per associarli al tuo profilo. +keep_email_private_popup = Questo nasconderà il tuo indirizzo e-mail nel tuo profilo, nelle richieste di modifica e quando modifichi un file usando l'interfaccia web. I commit inoltrati non saranno modificati. Usa %s nei commit per associarli al tuo profilo. verify_gpg_key_success = La chiave GPG "%s" è stata verificata. added_on = Aggiunto su %s additional_repo_units_hint = Suggerisci l'attivazione di unità aggiuntive nel repositorio @@ -1189,7 +1189,7 @@ migrate.migrating_failed_no_addr=Migrazione non riuscita. migrate.github.description=Migrare i dati da github.com o da server GitHub Enterprise. migrate.git.description=Migra un repositorio solo da qualsiasi servizio Git. migrate.gitlab.description=Migrare i dati da gitlab.com o da altre istanze di GitLab. -migrate.gitea.description=Migrare i dati da gitea.com o altre istanze di Gitea/Forgejo. +migrate.gitea.description=Migrare i dati da gitea.com o altre istanze di Gitea. migrate.gogs.description=Migrare i dati da notabug.org o da altre istanze Gogs. migrate.onedev.description=Migrare i dati da code.onedev.io o da altre istanze OneDev. migrate.codebase.description=Migrare i dati da codebasehq.com. @@ -1267,6 +1267,7 @@ view_git_blame=Visualizza git incolpa video_not_supported_in_browser=Il tuo browser non supporta le etichette "video" di HTML5. audio_not_supported_in_browser=Il tuo browser non supporta le etichette "audio" di HTML5. stored_lfs=Memorizzati con Git LFS +stored_annex=Memorizzati con Git Annex symbolic_link=Link Simbolico commit_graph=Grafico dei commit commit_graph.select=Seleziona rami @@ -1285,6 +1286,7 @@ editor.upload_file=Carica file editor.edit_file=Modifica file editor.preview_changes=Anteprima modifiche editor.cannot_edit_lfs_files=I file LFS non possono essere modificati nell'interfaccia web. +editor.cannot_edit_annex_files=I file Annex non possono essere modificati nell'interfaccia web. editor.cannot_edit_non_text_files=I file binari non possono essere modificati tramite interfaccia web. editor.edit_this_file=Modifica file editor.this_file_locked=Il file è bloccato @@ -1338,8 +1340,8 @@ commits.date=Data commits.older=Più vecchio commits.newer=Più recente commits.signed_by=Firmato da -commits.signed_by_untrusted_user=Firmato da un utente non attendibile -commits.signed_by_untrusted_user_unmatched=Firmato da un utente non attendibile che non corrisponde al committer +commits.signed_by_untrusted_user=Firmato da un*utente non attendibile +commits.signed_by_untrusted_user_unmatched=Firmato da un*utente non attendibile che non corrisponde al committente commits.gpg_key_id=ID chiave GPG commits.ssh_key_fingerprint=Impronta chiave SSH @@ -1411,7 +1413,7 @@ issues.new.no_reviewers=Nessun revisore issues.choose.get_started=Cominciare issues.choose.open_external_link=Apri issues.choose.blank=Default -issues.choose.blank_about=Crea un problema dal modello predefinito. +issues.choose.blank_about=Crea una segnalazione dal modello predefinito. issues.no_ref=Nessun ramo/etichetta specificati issues.create=Crea segnalazione issues.new_label=Nuova etichetta @@ -1482,8 +1484,8 @@ issues.action_milestone_no_select=Nessuna pietra miliare issues.action_assignee=Assegnatario issues.action_assignee_no_select=Nessun assegnatario issues.opened_by=aperta %[1]s da %[3]s -pulls.merged_by=di %[3]s è stato fuso %[1]s -pulls.merged_by_fake=di %[2]s è stato fuso %[1]s +pulls.merged_by=di %[3]s è stata fusa %[1]s +pulls.merged_by_fake=di %[2]s è stata fusa %[1]s issues.closed_by=di %[3]s è stato chiuso %[1]s issues.opened_by_fake=aperta %[1]s da %[2]s issues.closed_by_fake=di %[2]s è stato chiuso %[1]s @@ -1511,7 +1513,7 @@ issues.ref_issue_from=`ha fatto riferimento a questa segnalazion issues.ref_pull_from=`ha fatto riferimento a questa richiesta di modifica %[4]s %[2]s` issues.ref_closing_from=`ha fatto riferimento a questa segnalazione da una richiesta di modifica %[4]s che la chiuderà, %[2]s` issues.ref_reopening_from=`ha fatto riferimento a questa segnalazione da una richiesta di modifica %[4]s che la riaprirà, %[2]s` -issues.ref_closed_from=`chiuso questo problema %[4]s %[2]s` +issues.ref_closed_from=`chiuso questa segnalazione %[4]s %[2]s` issues.ref_reopened_from=`ha riaperto questa segnalazione %[4]s %[2]s` issues.ref_from=`da %[1]s` issues.author=Autore @@ -1549,32 +1551,32 @@ issues.subscribe=Iscriviti issues.unsubscribe=Annulla iscrizione issues.lock=Blocca conversazione issues.unlock=Sblocca conversazione -issues.lock.unknown_reason=Impossibile bloccare un problema con un motivo sconosciuto. +issues.lock.unknown_reason=Impossibile bloccare una segnalazione senza un motivo. issues.lock_duplicate=Un issue non può essere bloccato due volte. -issues.unlock_error=Impossibile sbloccare un problema che non è bloccato. -issues.lock_with_reason=ha bloccato come %s e limitato la conversazione ai collaboratori %s -issues.lock_no_reason=ha bloccato e limitato la conversazione ai collaboratori %s +issues.unlock_error=Impossibile sbloccare una segnalazione che non è bloccata. +issues.lock_with_reason=ha bloccato come %s e limitato la conversazione allɜ collaboranti %s +issues.lock_no_reason=ha bloccato e limitato la conversazione allɜ collaboranti %s issues.unlock_comment=ha sbloccato questa conversazione %s issues.lock_confirm=Blocca issues.unlock_confirm=Sblocca issues.lock.notice_1=- Altri utenti non possono aggiungere nuovi commenti a questa segnalazione. -issues.lock.notice_2=- Tu e altri collaboratori con accesso a questo repository potete ancora lasciare commenti che altri possono vedere. -issues.lock.notice_3=- Puoi sempre sbloccare questo problema in futuro. -issues.unlock.notice_1=- Tutti potranno commentare nuovamente questo problema. -issues.unlock.notice_2=- Puoi sempre chiudere nuovamente questo problema in futuro. +issues.lock.notice_2=- Tu e altrɜ collaboranti con accesso a questo repositorio potete ancora lasciare commenti visibili da altre persone. +issues.lock.notice_3=- Puoi sempre sbloccare questa segnalazione in futuro. +issues.unlock.notice_1=- Tuttɜ potranno commentare nuovamente questa segnalazione. +issues.unlock.notice_2=- Puoi sempre chiudere nuovamente questa segnalazione in futuro. issues.lock.reason=Motivo per il blocco issues.lock.title=Blocca la conversazione su questa issue. issues.unlock.title=Sblocca la conversazione su questa issue. -issues.comment_on_locked=Non puoi commentare un problema bloccato. +issues.comment_on_locked=Non puoi commentare una segnalazione bloccata. issues.delete=Elimina -issues.delete.title=Eliminare questo problema? -issues.delete.text=Vuoi davvero eliminare questo problema? (Questo rimuoverà permanentemente tutti i contenuti. Considera invece di chiuderlo, se vuoi tenerlo archiviato) +issues.delete.title=Eliminare la segnalazione? +issues.delete.text=Vuoi davvero eliminare la segnalazione? (Questo rimuoverà permanentemente tutti i contenuti. Considera invece di chiuderla, se vuoi tenerla archiviata) issues.tracker=Cronografo issues.start_tracking_short=Avvia timer issues.start_tracking=Avvia cronografo issues.start_tracking_history=ha iniziato a lavorare %s -issues.tracker_auto_close=Il timer verrà interrotto automaticamente una volta che il problema verrá chiuso -issues.tracking_already_started=`Hai già avviato il monitoraggio del tempo su un altro problema!` +issues.tracker_auto_close=Il timer verrà fermato automaticamente quando questa segnalazione verrà chiusa +issues.tracking_already_started=`Hai già avviato il monitoraggio del tempo su un'altra segnalazione!` issues.stop_tracking=Ferma timer issues.stop_tracking_history=`ha smesso di funzionare %s` issues.cancel_tracking=Scarta @@ -1620,7 +1622,7 @@ issues.dependency.pr_closing_blockedby=Questa richiesta di modifica non può ess issues.dependency.issue_closing_blockedby=Questa segnalazione non può essere chiusa per via delle seguenti segnalazioni issues.dependency.issue_close_blocks=Questa segnalazione impedisce la chiusura delle seguenti segnalazioni issues.dependency.pr_close_blocks=Questa richiesta di modifica impedisce la chiusura delle seguenti segnalazioni -issues.dependency.issue_close_blocked=Devi chiudere tutte le anomalie che bloiccano questo problema prima di chiudelo. +issues.dependency.issue_close_blocked=Vanno chiuse tutte le segnalazioni che bloccano quest'ultima, prima di poterla chiudere. issues.dependency.pr_close_blocked=Chiudere tutte le anomalie che bloccano la richiesta di pull prima di effettaure il merge. issues.dependency.blocks_short=Blocchi issues.dependency.blocked_by_short=Dipende da @@ -1628,8 +1630,8 @@ issues.dependency.remove_header=Rimuovi Dipendenza issues.dependency.issue_remove_text=Questo rimuoverà la dipendenza da questa issue. Continuare? issues.dependency.pr_remove_text=Questo rimuoverà la dipendenza da questa pull request. Continuare? issues.dependency.setting=Abilita le dipendenze per segnalazioni e richieste di modifica -issues.dependency.add_error_same_issue=Non si può fare dipendere un problema da se stesso. -issues.dependency.add_error_dep_issue_not_exist=Il problema dipendente non esiste. +issues.dependency.add_error_same_issue=Non si può fare dipendere una segnalazione da se stessa. +issues.dependency.add_error_dep_issue_not_exist=La segnalazione dalla quale dipende non esiste. issues.dependency.add_error_dep_not_exist=La dipendenza non esiste. issues.dependency.add_error_dep_exists=La dipendenza esiste già. issues.dependency.add_error_cannot_create_circular=Non puoi creare una dipendenza con due segnalazioni che si bloccano a vicenda. @@ -1782,7 +1784,7 @@ pulls.auto_merge_newly_scheduled_comment=`ha programmato questa pull request per pulls.auto_merge_canceled_schedule_comment=`cancella l'auto-merging di questa pull request quando tutti i testi sono superati %[1]s` pulls.delete.title=Eliminare questa pull request? -pulls.delete.text=Vuoi davvero eliminare questo problema? (Questo rimuoverà permanentemente tutti i contenuti. Considera invece di chiuderlo, se vuoi tenerlo archiviato) +pulls.delete.text=Vuoi davvero eliminare questa richiesta di modifica? (Ciò rimuoverà permanentemente tutti i contenuti. Considera invece di chiuderla, se vuoi tenerla archiviata) @@ -1816,8 +1818,8 @@ ext_wiki.desc=Collegamento a una wiki esterna. wiki=Wiki wiki.welcome=Benvenuti nella Wiki. -wiki.welcome_desc=La wiki ti permette di scrivere e condividere documentazione con i collaboratori. -wiki.desc=Scrivi e condividi documentazione con i collaboratori. +wiki.welcome_desc=La wiki ti permette di scrivere e condividere documentazione con lɜ collaboranti. +wiki.desc=Scrivi e condividi documentazione con lɜ collaboranti. wiki.create_first_page=Crea la prima pagina wiki.page=Pagina wiki.filter_page=Filtra pagina @@ -1915,7 +1917,7 @@ search.code_search_unavailable=Attualmente la ricerca di codice non è disponibi settings=Impostazioni settings.desc=Impostazioni ti permette di gestire le impostazioni del repository settings.options=Repository -settings.collaboration=Collaboratori +settings.collaboration=Collaboranti settings.collaboration.admin=Amministratore settings.collaboration.write=Scrittura settings.collaboration.read=Lettura @@ -2009,14 +2011,14 @@ settings.signing_settings=Impostazioni verifica firma settings.trust_model=Modello di fiducia per la firma settings.trust_model.default=Modello di fiducia predefinito settings.trust_model.default.desc=Usa il modello di trust del repository predefinito per questa installazione. -settings.trust_model.collaborator=Collaboratore -settings.trust_model.collaborator.long=Collaboratore: Firme di fiducia da parte dei collaboratori -settings.trust_model.collaborator.desc=Le firme valide da parte dei collaboratori di questo repository saranno contrassegnate con "trusted" (sia che corrispondano al committer o meno). Altrimenti, le firme valide saranno contrassegnate con "untrusted" se la firma corrisponde al committer e "unmatched" se non. +settings.trust_model.collaborator=Collaborante +settings.trust_model.collaborator.long=Collaborante: firme di fiducia da parte dellɜ collaboranti +settings.trust_model.collaborator.desc=Le firme valide da parte dellɜ collaboranti di questo repositorio saranno contrassegnate con "fidate" (sia che corrispondano a chi ha fatto il commit o meno). Altrimenti saranno contrassegnate con "non fidate" se la firma corrisponde a chi ha fatto il commit e "senza riscontro" se non. settings.trust_model.committer=Autorə settings.trust_model.committer.long=Committer: firme affidabili che corrispondono ai committer (questo corrisponde a GitHub e costringerà i commit firmati di Forgejo ad avere Forgejo come committer) -settings.trust_model.collaboratorcommitter=Collaboratore+Committer -settings.trust_model.collaboratorcommitter.long=Collaboratore+Committer: Firme di fiducia da parte dei collaboratori che corrispondono al committer -settings.trust_model.collaboratorcommitter.desc=Le firme valide da parte dei collaboratori di questa repository saranno contrassegnate "fidate" se corrispondono al committer. Altrimenti le firme saranno contrassegnate con "untrusted" se la firma corrisponde al committer non corrisponde. Questo costringerà Forgejo a essere contrassegnato come committer su impegni firmati con l'effettivo committer contrassegnato come Co-Authored-By: e Co-Committed-By: nel commit. La chiave Forgejo predefinita deve corrispondere a un utente nel database. +settings.trust_model.collaboratorcommitter=Collaborante+Committente +settings.trust_model.collaboratorcommitter.long=Collaborante+Committente: firme di fiducia da parte dellɜ collaboranti che corrispondono allə committente +settings.trust_model.collaboratorcommitter.desc=Le firme valide da parte dellɜ collaboranti di questo repositorio saranno contrassegnate "fidate" se corrispondono a chi fa il commit. Altrimenti saranno contrassegnate con "non fidate" se la firma corrisponde a chi fa il commit, e "senza riscontro" se non corrisponde. Questo costringerà Forgejo a essere contrassegnato come committente sui commit firmati, con l'effettivə committente contrassegnatə come Co-Authored-By: e Co-Committed-By: nel commit. La chiave Forgejo predefinita deve corrispondere a un*utente nella base dati. settings.wiki_delete=Elimina dati wiki settings.wiki_delete_desc=L'eliminazione dei dati della wiki del repository è permanente e non può essere annullata. settings.wiki_delete_notices_1=-Questa operazione eliminerà permanentemente e disabiliterà la wiki repository per %s. @@ -2025,21 +2027,21 @@ settings.wiki_deletion_success=I dati della repository wiki sono stati eliminati settings.delete=Elimina questo progetto settings.delete_desc=L'eliminazione di un repository è un'operazione permanente e non può essere annullata. settings.delete_notices_1=-Questa operazione NON PUÒ essere annullata. -settings.delete_notices_2=-Questa operazione eliminerà definitivamente il repository %s inclusi codice, issue, commenti, dati wiki e impostazioni collaboratore. +settings.delete_notices_2=-Questa operazione eliminerà definitivamente il repositorio %s, inclusi codice, segnalazioni commenti, dati della wiki e impostazioni collaboranti. settings.delete_notices_fork_1=-I fork di questo repository diventeranno indipendenti dopo la cancellazione. settings.deletion_success=Il repository è stato eliminato. settings.update_settings_success=Le impostazioni del repository sono state aggiornate. settings.confirm_delete=Elimina progetto -settings.add_collaborator=Aggiungi collaboratore -settings.add_collaborator_success=Il collaboratore è stato aggiunto. -settings.add_collaborator_inactive_user=Non posso aggiungere un utente inattivo come collaboratore. -settings.add_collaborator_duplicate=Il collaboratore è già stato aggiunto a questo repository. +settings.add_collaborator=Aggiungi collaborante +settings.add_collaborator_success=Lə collaborante è statə aggiuntə. +settings.add_collaborator_inactive_user=Non posso aggiungere un*utente inattivə come collaborante. +settings.add_collaborator_duplicate=Lə collaborante è già statə aggiuntə a questo repositorio. settings.delete_collaborator=Rimuovi -settings.collaborator_deletion=Rimuovi collaboratore -settings.collaborator_deletion_desc=Rimuovere un collaboratore revocherà l'accesso a questo repository. Continuare? -settings.remove_collaborator_success=Il collaboratore è stato rimosso. +settings.collaborator_deletion=Rimuovi collaborante +settings.collaborator_deletion_desc=Rimuovere unə collaborante ne revocherà l'accesso a questo repositorio. Continuare? +settings.remove_collaborator_success=Lə collaborante è statə rimossə. settings.search_user_placeholder=Ricerca utente… -settings.org_not_allowed_to_be_collaborator=Le organizzazioni non possono essere aggiunte come un collaboratore. +settings.org_not_allowed_to_be_collaborator=Le organizzazioni non possono essere aggiunte come collaborante. settings.change_team_access_not_allowed=La modifica dell'accesso al team per il repository è stato limitato al solo proprietario dell'organizzazione settings.team_not_in_organization=Il team non è nella stessa organizzazione del repository settings.teams=Gruppi @@ -2409,7 +2411,7 @@ actions = Azioni commit.operations = Operazioni issues.action_check = Seleziona/Deseleziona issues.close = Chiudi segnalazione -issues.role.collaborator = Collaboratore +issues.role.collaborator = Collaborante desc.sha256 = SHA256 editor.add = Aggiungi %s editor.update = Aggiorna %s @@ -2452,7 +2454,7 @@ settings.units.overview = Panoramica all_branches = Tutti i rami projects.column.assigned_to = Assegnato a pulls.cmd_instruction_hint = `Visualizza istruzioni per la riga di comando.` -settings.add_collaborator_blocked_them = Non si può aggiungere il collaboratore perché ha bloccato il proprietario del progetto. +settings.add_collaborator_blocked_them = Non si può aggiungere lə collaborante perché ha bloccato lə proprietariə del progetto. branch.protected_deletion_failed = Il ramo "%s" è protetto. Non può essere eliminato. branch.default_deletion_failed = Il ramo "%s" è il ramo predefinito. Non può essere eliminato. branch.tag_collision = Il ramo "%s" non può essere creato perché esiste già un'etichetta con lo stesso nome nel repositorio. @@ -2566,7 +2568,7 @@ settings.wiki_branch_rename_success = Il nome del ramo della wiki della repo è settings.wiki_branch_rename_failure = Impossibile normalizzare il nome del ramo della wiki della repo. settings.confirm_wiki_branch_rename = Rinomina il ramo della wiki settings.wiki_rename_branch_main_notices_2 = Ciò rinominerà permanentemente il ramo interno della wiki della repo di %s. Passaggi esistenti dovranno essere aggiornati. -settings.add_collaborator_blocked_our = Non si può aggiungere il collaboratore perché il proprietario del progetto lo ha bloccato. +settings.add_collaborator_blocked_our = Non si può aggiungere lə collaborante perché lə proprietariə del progetto l'ha bloccatə. settings.webhook.replay.description_disabled = Per riprodurre questo richiamo HTTP, attivalo. settings.event_wiki_desc = Pagina wiki creata, rinominata, modificata o rimossa. settings.event_pull_request_review_request = Richiesta di modifica revisionata @@ -2609,7 +2611,7 @@ invisible_runes_description = `Questo file contiene caratteri Unicode invisibili issues.filter_type.reviewed_by_you = Revisionati da te projects.edit_success = Il progetto "%s" è stato aggiornato. issues.keyword_search_unavailable = La ricerca per parola chiave non è attualmente disponibile. Contatta l'amministratore del sito. -issues.role.collaborator_helper = Questo utente è stato invitato a collaborare sul progetto. +issues.role.collaborator_helper = Quest*utente è statə invitatə a collaborare al progetto. pulls.commit_ref_at = `ha fatto riferimento a questa richiesta di modifica da un commit %[2]s` settings.thread_id = ID della discussione release.title = Titolo del rilascio @@ -2661,7 +2663,7 @@ settings.branches.add_new_rule = Aggiungi una nuova regola settings.actions_desc = Abilita azioni del progetto settings.new_owner_blocked_doer = Il nuovo proprietario ti ha bloccato. settings.update_settings_no_unit = Ili progetto dovrebbe consentire almeno qualche tipo di interazione. -settings.add_collaborator_owner = Non si può aggiungere un proprietario come collaboratore. +settings.add_collaborator_owner = Non si può aggiungere unə proprietariə come collaborante. branch.delete_desc = L'eliminazione di un ramo è definitiva. Nonostante il ramo eliminato potrebbe continuare ad esistere per un breve periodo di tempo prima di essere realmente eliminato, l'eliminazione NON PUÒ essere annullata in molti casi. Continuare? editor.invalid_commit_mail = Email invalida per creare un commit. editor.branch_does_not_exist = Non esiste nessun ramo "%s" nel repositorio. @@ -2780,9 +2782,9 @@ settings.matrix.access_token_helper = È consigliata l'impostazione di un accoun issues.author.tooltip.issue = Questo utente è l'autore di questa segnalazione. form.string_too_long = La stringa data è più lunga di %d caratteri. project = Progetti -issues.edit.already_changed = Impossibile salvare le modifiche al problema. Sembra che il contenuto sia già stato modificato da un altro utente. Aggiornare la pagina e provare a modificare nuovamente per evitare di sovrascrivere le modifiche +issues.edit.already_changed = Impossibile salvare le modifiche alla segnalazione. Sembra che il contenuto sia già stato modificato da un*altrə utente. Aggiornare la pagina e provare a modificare nuovamente per evitare di sovrascrivere le modifiche subscribe.pull.guest.tooltip = Accedi per iscriverti a questa richiesta di modifica. -subscribe.issue.guest.tooltip = Accedere per sottoscrivere questo problema. +subscribe.issue.guest.tooltip = Accedere per seguire questa segnalazione. n_release_one = rilascio %s n_release_few = rilasci %s issues.author.tooltip.pr = Quest'utente è l'autorə di questa richiesta di modifica. @@ -2889,7 +2891,7 @@ teams.read_access_helper=I membri possono visualizzare e clonare i repository de teams.write_access=Scrittura teams.write_access_helper=I membri possono leggere e pushare sui repository del team. teams.admin_access=Accesso amministratore -teams.admin_access_helper=I membri possono pullare e pushare sulle repository del team e anche aggiungere collaboratori. +teams.admin_access_helper=I membri possono prelevare e immettere sui repositori del team e aggiungere collaboranti. teams.no_desc=Questo team non ha alcuna descrizione teams.settings=Impostazioni teams.owners_permission_desc=I proprietari hanno pieno accesso a tutti i repository e hanno diritti di amministratore nell'organizzazione. @@ -2902,7 +2904,7 @@ teams.delete_team_desc=Eliminare un team revocherà l'accesso al repository da p teams.delete_team_success=Il team è stato eliminato. teams.read_permission_desc=Questo team concede l'accesso di lettura: i membri possono visualizzare e clonare i repository del team. teams.write_permission_desc=Questo team concede l'accesso di Scrittura: i membri possono leggere da e pushare sui repository del team. -teams.admin_permission_desc=Questo team concede l'accesso di Amministratore: i membri possono leggere da, pushare su e aggiungere collaboratori ai repository del team. +teams.admin_permission_desc=Questo team concede l'accesso di Amministrante: i membri possono leggere da, immettere in e aggiungere collaboranti ai repositori del team. teams.create_repo_permission_desc=Inoltre, questo team concede il permesso di Creare repository: i membri possono creare nuove repository nell'organizzazione. teams.repositories=Progetti della squadra teams.search_repo_placeholder=Ricerca repository… @@ -3221,7 +3223,7 @@ auths.tip.google_plus=Ottieni le credenziali del client OAuth2 dalla console API auths.tip.openid_connect=Utilizza l'OpenID Connect Discovery URL (/.well-known/openid-configuration) per specificare gli endpoint auths.tip.twitter=Vai su %s, crea una applicazione e assicurati che l'opzione "Allow this application to be used to Sign In with Twitter" sia abilitata auths.tip.discord=Registra una nuova applicazione su %s -auths.tip.yandex=`Crea una nuova applicazione su %s. Seleziona i seguenti permessi da "Yandex. assport API": "Access to email address", "Access to user avatar" e "Access to username, name and surname, gender"` +auths.tip.yandex=`Crea una nuova applicazione su %s. Seleziona i seguenti permessi da "Yandex.Passport API": "Access to email address", "Access to user avatar" e "Access to username, name and surname, gender"` auths.tip.mastodon=Inserisci un URL di istanza personalizzato per l'istanza mastodon con cui vuoi autenticarti (o usa quella predefinita) auths.edit=Modifica fonte di autenticazione auths.activated=Questa fonte di autenticazione è attiva @@ -3463,7 +3465,7 @@ auths.tips.gmail_settings = Impostazioni Gmail: config.test_mail_failed = Impossibile inviare email di prova a "%s": %v users.details = Dettagli dell'utente monitor.queue.review_add = Revisiona / aggiungi lavoratori -self_check.no_problem_found = Nessun problema trovato. +self_check.no_problem_found = Non c'è ancora nessuna segnalazione. self_check.database_inconsistent_collation_columns = La base di dati sta usando la collazione %s ma queste colonne usano una collazione diversa. Potrebbe causare problemi imprevisti. monitor.queue.settings.remove_all_items = Rimuovi tutto monitor.queue.settings.desc = Le piscine crescono dinamicamente in risposta al blocco dei lavoratori in coda. @@ -3483,11 +3485,13 @@ config.app_slogan = Slogan dell'istanza auths.default_domain_name = Nome di dominio predefinito utilizzato per l'indirizzo e-mail +users.restricted.description = Permetti di interagire solo con i repositori e le organizzazioni in cui l'utente è aggiuntə come collaborante. Ciò evita l'accesso ai repositori pubblici di quest'istanza. + [action] create_repo=ha creato il repository %s rename_repo=repository rinominato da %[1]s a [3]s create_issue=`ha aperto la segnalazione %[3]s#%[2]s` -close_issue=`ha chiuso il problema %[3]s#%[2]s` +close_issue=`ha chiuso la segnalazione %[3]s#%[2]s` reopen_issue=`ha riaperto la segnalazione %[3]s#%[2]s` create_pull_request=`ha creato la pull request %[3]s#%[2]s` close_pull_request=`ha chiuso la pull request %[3]s#%[2]s` diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index b0fc38d911..2a4f075994 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1217,7 +1217,7 @@ migrate.migrating_failed_no_addr=移行に失敗しました。 migrate.github.description=github.com やその他の GitHub エンタープライズサーバーからデータを移行します。 migrate.git.description=Git サービスからリポジトリのみを移行します。 migrate.gitlab.description=gitlab.com やその他の GitLab インスタンスからデータを移行します。 -migrate.gitea.description=gitea.com やその他の Gitea/Forgejo インスタンスからデータを移行します。 +migrate.gitea.description=gitea.com やその他の Gitea インスタンスからデータを移行します。 migrate.gogs.description=notabug.org やその他の Gogs インスタンスからデータを移行します。 migrate.onedev.description=code.onedev.io やその他の OneDev インスタンスからデータを移行します。 migrate.codebase.description=codebasehq.com からデータを移行します。 @@ -1305,6 +1305,7 @@ view_git_blame=Git Blameを表示 video_not_supported_in_browser=このブラウザはHTML5のvideoタグをサポートしていません。 audio_not_supported_in_browser=このブラウザーはHTML5のaudioタグをサポートしていません。 stored_lfs=Git LFSで保管されています +stored_annex=Git Annexで保管されています symbolic_link=シンボリック リンク executable_file=実行ファイル commit_graph=コミットグラフ @@ -1328,6 +1329,7 @@ editor.upload_file=ファイルをアップロード editor.edit_file=ファイルを編集 editor.preview_changes=変更をプレビュー editor.cannot_edit_lfs_files=LFSのファイルはWebインターフェースで編集できません。 +editor.cannot_edit_annex_files=AnnexのファイルはWebインターフェースで編集できません。 editor.cannot_edit_non_text_files=バイナリファイルはWebインターフェースで編集できません。 editor.edit_this_file=ファイルを編集 editor.this_file_locked=ファイルはロックされています diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index 6eb9dd634e..0573982812 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -128,7 +128,7 @@ copy_success = 복사되었습니다! copy_error = 복사 실패 copy_type_unsupported = 이 파일 형식은 복사할 수 없습니다 error = 오류 -error404 = 도달하려는 페이지가 존재하지 않거나 볼 수 있도록 인증되지 않았습니다. +error404 = 도달하려는 페이지가 존재하지 않거나 볼 수 있는 권한이 없습니다. go_back = 돌아가기 invalid_data = 유효하지 않는 데이터: %v unknown = 알 수 없음 @@ -160,6 +160,16 @@ view = 보기 never = 안함 test = 테스트 +new_repo.title = 새 저장소 +new_org.title = 새 조직 +new_repo.link = 새 저장소 +new_org.link = 새 조직 +copy_path = 경로 복사 + +new_migrate.title = 마이그레이션 +new_migrate.link = 새 마이그레이션 +error413 = 사용 가능한 할당량을 모두 소진하였습니다. + [aria] navbar = 내비게이션 바 footer.links = 링크 @@ -183,6 +193,21 @@ buttons.code.tooltip = 코드 추가 buttons.link.tooltip = 링크 추가 buttons.quote.tooltip = 인용구 추가 +buttons.list.unordered.tooltip = 불릿 리스트 추가 +buttons.list.ordered.tooltip = 번호로 된 리스트 추가 +buttons.list.task.tooltip = 작업 목록 추가 +buttons.mention.tooltip = 사용자 또는 팀을 언급 +buttons.ref.tooltip = 이슈 또는 풀 리퀘스트 참조 +buttons.switch_to_legacy.tooltip = 대신에 구형 편집기 사용 +buttons.enable_monospace_font = 고정 폭 글꼴 활성화 +buttons.disable_monospace_font = 고정 폭 글꼴 비활성화 +buttons.new_table.tooltip = 테이블 추가 +table_modal.header = 테이블 추가 +table_modal.placeholder.header = 헤더 +table_modal.placeholder.content = 내용 +table_modal.label.rows = 행 +table_modal.label.columns = 열 + [filter] string.desc = 하 - 가 string.asc = 가 - 하 @@ -191,6 +216,10 @@ string.asc = 가 - 하 network_error = 네트워크 오류 server_internal = 내부 서버 오류 +occurred = 에러가 발생함 +report_message = 이것이 Forgejo의 버그라고 생각한다면, Codeberg 에서 이슈를 검색하거나 필요하다면 새 이슈를 만들어주세요. +not_found = 타겟을 찾을 수 없습니다. + [startpage] app_desc=편리한 설치형 Git 서비스 install=쉬운 설치 @@ -198,6 +227,11 @@ platform=크로스 플랫폼 lightweight=가벼움 license=오픈 소스 +install_desc = 간단히 당신의 기기에서바이너리를 실행하거나, Docker를 사용하거나, 패키지 저장소에서 설치할 수 있습니다. +platform_desc = Forgejo는 Linux와 FreeBSD등의 자유 오픈소스 운영 체제를 포함한 다양한 CPU 아키텍처에서 실행됩니다. 마음 가는대로 고르세요! +lightweight_desc = Forgejo의 낮은 전력 소모량은 값싼 Raspberry Pi마저 구동할 수 있게 합니다. 기기의 에너지를 절약하세요! +license_desc = Forgejo를 설치해보세요! Forgejo를 개선하기 위해 기여할 수 있습니다. 기여자가 되기를 망설이지 마세요! + [install] install=설치 title=초기 설정 @@ -205,7 +239,7 @@ docker_helper=Forgejo를 Docker에서 실행하려면 설정 전에 이 형식으로 입력하세요. -mailer_user=SMTP 사용자이름 +mailer_user=SMTP 사용자명 mailer_password=SMTP 비밀번호 register_confirm=가입시 이메일 확인 필수 mail_notify=이메일 알림 켜기 @@ -250,9 +284,9 @@ server_service_title=서버 및 기타 서비스 설정 offline_mode=로컬 모드 켜기 offline_mode.description=타사 콘텐츠 전송 네트워크를 사용하지 않도록 설정하고 모든 리소스를 로컬에서 제공합니다. disable_gravatar=Gravatar 사용안함 -disable_gravatar.description=Gravatar 및 타사 아바타 소스를 사용하지 않도록 설정합니다. 사용자가 로컬로 아바타를 업로드하지 않는 한 기본 아바타가 사용됩니다. +disable_gravatar.description=Gravatar를 비롯한 타사 아바타 출처를 사용하지 않도록 설정합니다. 사용자가 직접 아바타를 업로드하지 않는 한 기본 아바타를 사용합니다. federated_avatar_lookup=탈중앙화 아바타 사용 -federated_avatar_lookup.description=libravatar 기반 오픈소스 연합 아바타 조회를 허용합니다. +federated_avatar_lookup.description=Libravatar 아바타를 조회합니다. disable_registration=사용자 등록 비활성화 disable_registration.description=인스턴스 관리자만이 새 사용자 계정을 추가할 수 있게 됩니다. 공개 인스턴스를 제공할 예정이고 많은 양의 스팸 계정을 감당할 준비가 되어 있지 않다면 사용자 등록을 비활성화 할 것을 강력히 권고합니다. allow_only_external_registration.description=새 계정을 등록하려는 사용자는 설정된 외부 서비스를 이용해야만 새 계정을 등록할 수 있습니다. @@ -264,7 +298,7 @@ enable_captcha.description=사용자 등록시 캡차를 요구합니다. require_sign_in_view=인스턴스의 콘텐츠를 볼때 로그인 요구 admin_setting.description=관리자 계정을 만드는 것은 선택사항입니다. 첫번째로 등록된 사용자는 자동적으로 관리자로 지정됩니다. admin_title=관리자 계정 설정 -admin_name=관리자 이름 +admin_name=관리자의 사용자명 admin_password=비밀번호 confirm_password=비밀번호 확인 admin_email=이메일 주소 @@ -273,18 +307,18 @@ test_git_failed='git' 명령 테스트 실패: %v sqlite3_not_available=해당 버전에서는 SQLite3를 지원하지 않습니다. %s에서 공식 버전을 다운로드해주세요. ('gobuild' 버전이 아닙니다). invalid_db_setting=데이터베이스 설정이 올바르지 않습니다: %v invalid_repo_path=저장소(레파지토리) 의 경로가 올바르지 않습니다: %v -run_user_not_match=실행 사용자명이 현재 사용자명과 다릅니다: %s -> %s +run_user_not_match="실행 사용자명"이 현재 사용자명과 다릅니다: %s -> %s save_config_failed=설정을 저장할 수 없습니다: %v invalid_admin_setting=관리자 계정 설정이 올바르지 않습니다: %v invalid_log_root_path=로그(Log) 의 경로가 올바르지 않습니다: %v default_keep_email_private=이메일 주소 숨김처리를 기본값으로 설정 -default_keep_email_private.description=새 사용자에 대한 이메일 주소 숨김처리를 기본값으로 설정합니다. +default_keep_email_private.description=새 사용자에 대한 이메일 주소 숨김처리를 기본값으로 설정해 가입 직후 정보가 유출되는것을 방지합니다. default_allow_create_organization=조직 생성 허용을 기본값으로 설정 -default_allow_create_organization.description=신규 사용자 생성시 조직 생성을 기본값으로 설정합니다. -default_enable_timetracking=시간 추적 사용을 기본값으로 설정 -default_enable_timetracking.description=신규 레포지토리에 대한 시간 추적 사용을 기본값으로 설정합니다. +default_allow_create_organization.description=신규 사용자에게 기본적으로 조직 생성 권한을 부여합니다. 이 옵션이 꺼져있다면, 관리자가 신규 사용자에게 조직 생성 권한을 부여해야합니다. +default_enable_timetracking=시간 기록 기능을 기본적으로 사용 +default_enable_timetracking.description=신규 저장소가 시간기록 기능을 기본적으로 사용할 수 있습니다. no_reply_address=가려진 이메일 도메인 -no_reply_address_helper=가려진 이메일을 가진 사용자에게 적용될 이메일 도메인입니다. 예를 들어, 사용자 'joe'의 가려잔 이메일 도메인이 'noreply.example.org'로 설정되어 있으면 'joe@noreply.example.org'로 처리 됩니다. +no_reply_address_helper=이메일을 가린 사용자에게 적용될 이메일 도메인입니다. 예를 들어, 사용자명 'joe'가 도메인'noreply.example.org'로 이메일을 가리면 Git에 'joe@noreply.example.org'로 로그인 하게 됩니다. db_schema_helper = 데이터베이스 기본값 ("공개")를 사용하려면 빈 칸으로 두세요. require_db_desc = Forgejo를 사용하려면 MySQL, PostgreSQL, SQLite3 또는 TiDB (MySQL 프로토콜) 이 설치되어 있어야 합니다. domain = 서버 도메인 @@ -292,8 +326,19 @@ smtp_from_invalid = "이메일 발신인" 주소가 유효하지 않습니다 enable_captcha = 등록 시 CAPTCHA 활성화 allow_only_external_registration = 외부 서비스를 통한 등록만 허용 +reinstall_error = 이미 존재하는 Forgejo 데이터베이스에 설치를 시도중임 +reinstall_confirm_message = 이미 존재하는 Forgejo 데이터베이스에 재설치를 하는것은 다수의 문제의 원인이 될 수 있습니다. 대부분의 경우 이미 존재하는 "app.ini" 를 사용해 Forgejo를 구동해야합니다. 당신이 무엇을 하고있는지 명확히 알고있다면 다음 사항들을 확인하세요: +reinstall_confirm_check_1 = app.ini의 SECRET_KEY로 암호화 되어있는 데이터를 잃을 수 있습니다: 2FA/OTP를 통해 로그인 할 수 없으며 & 미러가 제대로 작동하지 않게됩니다. app.ini 파일에 정확한 SECRET_KEY가 있는것이 확실하다면 체크하세요. +reinstall_confirm_check_2 = 저장소와 설정에 재동기화가 요구될 수 있습니다. 이 박스에 체크하면 저장소의 훅과 authorized_key 들을 수동으로 재동기화해야 한다는 것을 인지한다는 것을 의미합니다. 저장소와 미러의 설정이 올바른지 확인하세요. +reinstall_confirm_check_3 = Forgejo가 올바른 app.ini 위치로 실행중이며 그것이 다시 설치할 대상이 맞다는것을 전적으로 확신합니다. 위의 위험성들을 인지하고 있음에 동의합니다. +err_admin_name_pattern_not_allowed = 관리자의 사용자명이 올바르지 않음, 사용자명이 예약된 패턴과 일치함 +app_slogan = 인스턴스 슬로건 +app_slogan_helper = 인스턴스의 슬로건을 입력하세요. 비워두면 비활성화됩니다. +run_user_helper = Forgejo를 구동하는 운영체제의 사용자명입니다. 이 사용자는 저장소 루트 경로에 접근권한이 있어야 합니다. +allow_dots_in_usernames = 사용자들이 마침표를 사용자명에 사용할 수 있도록 허가합니다. 이미 존재하는 계정에는 영향을 주지 않습니다. + [home] -uname_holder=사용자 이름 또는 이메일 주소 +uname_holder=사용자명 또는 이메일 주소 password_holder=비밀번호 switch_dashboard_context=대시보드 컨텍스트 바꾸기 my_repos=저장소 @@ -337,7 +382,7 @@ allow_password_change=사용자에게 비밀번호 변경을 요청 (권장됨) reset_password_mail_sent_prompt=확인 메일이 %s로 전송되었습니다. 받은 편지함으로 도착한 메일을 %s 안에 확인해서 비밀번호 찾기 절차를 완료하십시오. active_your_account=계정 활성화 account_activated=계정이 활성화 되었습니다 -prohibit_login = +prohibit_login = resent_limit_prompt=활성화를 위한 이메일을 이미 전송했습니다. 3분 내로 이메일을 받지 못한 경우 재시도해주세요. has_unconfirmed_mail=안녕하세요 %s, 이메일 주소(%s)가 확인되지 않았습니다. 확인 메일을 받으시지 못하겼거나 새로운 확인 메일이 필요하다면, 아래 버튼을 클릭해 재발송하실 수 있습니다. resend_mail=여기를 눌러 확인 메일 재전송 @@ -402,6 +447,8 @@ issue.action.new = @%[1]s님이 #%[2]d를 만들었습니다. +register_notify.text_2 = 당신의 계정에 사용자명으로 로그인 할 수 있습니다: %s + [modal] yes=예 no=아니오 @@ -409,8 +456,8 @@ cancel=취소 modify=변경하기 [form] -UserName=사용자 이름 -RepoName=저장소 이름 +UserName=사용자명 +RepoName=저장소명 Email=이메일 주소 Password=비밀번호 Retype=비밀번호 확인 @@ -444,14 +491,14 @@ captcha_incorrect=CAPTCHA 코드가 올바르지 않습니다. password_not_match=비밀번호가 일치하지 않습니다. lang_select_error=목록에서 언어를 선택해주세요. -username_been_taken=이미 사용하고 있는 아이디입니다. -repo_name_been_taken=이미 사용하고 있는 저장소 이름입니다. +username_been_taken=이미 사용되는 사용자명입니다. +repo_name_been_taken=이미 사용중인 저장소명 입니다. org_name_been_taken=이미 사용중인 조직 이름입니다. team_name_been_taken=이미 사용중인 팀 이름입니다. team_no_units_error=최소 하나 이상의 레포지토리 섹션에 대한 접근을 허용하십시오. email_been_used=이미 사용 중인 이메일 주소입니다. -username_password_incorrect=사용자 이름 또는 암호가 올바르지 않습니다. -enterred_invalid_repo_name=입력한 저장소의 이름이 올바르지 않습니다. +username_password_incorrect=사용자명 또는 암호가 올바르지 않습니다. +enterred_invalid_repo_name=입력한 저장소명이 올바르지 않습니다. enterred_invalid_owner_name=새로운 소유자 이름이 올바르지 않습니다. enterred_invalid_password=입력한 비밀번호는 올바르지 않습니다. user_not_exist=존재하지 않는 사용자입니다. @@ -467,10 +514,13 @@ target_branch_not_exist=대상 브랜치가 존재하지 않습니다. url_error = `"%s"는 유효한 URL이 아닙니다.` include_error = `"%s"을/를 포함해야 합니다.` regex_pattern_error = `regex 패턴이 잘못되었습니다: %s` -username_error = `영문("a-z", "A-Z"), 숫자("0-9"), 대시("-"), 밑줄("_"), 점(".")만 포함할 수 있습니다. 영문 혹은 숫자가 아닌 문자로 시작하거나 끝날 수 없으며 연속된 영문 혹은 숫자가 아닌 문자도 금지됩니다.` +username_error = `영문("a-z", "A-Z"), 숫자("0-9"), 대시("-"), 밑줄("_"), 마침표(".")만 포함할 수 있습니다. 영문 혹은 숫자가 아닌 문자로 시작하거나 끝날 수 없으며 연속된 영문 혹은 숫자가 아닌 문자도 금지됩니다.` glob_pattern_error = `glob 패턴이 잘못되었습니다: %s` +username_error_no_dots = `영문("a-z", "A-Z"), 숫자("0-9"), 대시("-"), 밑줄("_")만 포함할 수 있습니다. 영문 혹은 숫자가 아닌 문자로 시작하거나 끝날 수 없으며 연속된 영문 혹은 숫자가 아닌 문자도 금지됩니다.` +username_change_not_local_user = 외부 사용자들은 사용자명을 변경할 수 없습니다. + [user] change_avatar=아바타 변경… repositories=저장소 @@ -486,6 +536,10 @@ projects = 프로젝트 watched = 주시중인 저장소 +form.name_reserved = "%s" 사용자명이 예약(reserved)되었습니다. +form.name_pattern_not_allowed = "%s" 패턴이 사용자명으로 사용할 수 없습니다. +form.name_chars_not_allowed = "%s" 사용자명이 유효하지 않은 문자를 포함합니다. + [settings] profile=프로필 account=계정 @@ -503,14 +557,14 @@ account_link=연결된 계정 organization=조직 public_profile=공개 프로필 -password_username_disabled=로컬 사용자가 아닌 경우 사용자 이름 변경을 할 수 없습니다. 자세한 내용은 관리자에게 문의해주세요. +password_username_disabled=로컬 사용자가 아닌 경우 사용자명을 변경 할 수 없습니다. 자세한 내용은 관리자에게 문의해주세요. full_name=성명 website=웹 사이트 location=위치 update_theme=테마 변경 update_profile=프로필 업데이트 update_profile_success=프로필이 업데이트 되었습니다. -change_username=사용자 이름 변경 되었습니다. +change_username=사용자명이 변경 되었습니다. continue=계속하기 cancel=취소 language=언어 @@ -662,10 +716,14 @@ change_password = 비밀번호 변경 email_desc = 당신의 대표 이메일 주소는 알림, 비밀번호 재설정과 웹에서의 Git 작동에 사용되며 가려지지 않습니다. comment_type_group_dependency = 전제조건 +change_username_prompt = 참고: 사용자명의 변경은 계정의 URL을 변경시킵니다. +change_username_redirect_prompt = 과거 사용자명은 누군가 사용하기 전까지 리디렉트됩니다. +comment_type_group_time_tracking = 시간 기록 + [repo] owner=소유자 -repo_name=저장소 이름 -repo_name_helper=좋은 저장소 이름은 보통 짧고 기억하기 좋은 특별한 키워드로 이루어 집니다. +repo_name=저장소명 +repo_name_helper=좋은 저장소명은 보통 짧고 기억하기 좋은 특별한 키워드로 이루어 집니다. repo_size=저장소 용량 template=템플릿 template_select=템플릿을 선택합니다. @@ -763,6 +821,7 @@ file_too_large=보여주기에는 파일이 너무 큽니다. video_not_supported_in_browser=당신의 브라우저가 HTML5의 "video" 태그를 지원하지 않습니다. audio_not_supported_in_browser=당신의 브라우저가 HTML5의 "audio" 태그를 지원하지 않습니다. stored_lfs=Git LFS에 저장되어 있습니다 +stored_annex=Git Annex에 저장되어 있습니다 commit_graph=커밋 그래프 editor.new_file=새 파일 @@ -914,7 +973,7 @@ issues.subscribe=구독하기 issues.unsubscribe=구독 취소 issues.delete=삭제 issues.tracker=타임 트래커 -issues.start_tracking=타임 트래킹 시작 +issues.start_tracking=시간 기록 시작 issues.start_tracking_history=`님이 %s 작업 시작` issues.stop_tracking_history=`님이 %s 작업 중단` issues.add_time=수동으로 시간 입력 @@ -1114,7 +1173,7 @@ settings.tracker_url_format=외부 이슈 트래커 URL 형식 settings.tracker_issue_style=외부 이슈 트래커 숫자 포맷 settings.tracker_issue_style.numeric=숫자 settings.tracker_issue_style.alphanumeric=문자 숫자 -settings.enable_timetracker=시간 추적 활성화 +settings.enable_timetracker=시간 기록 활성화 settings.allow_only_contributors_to_track_time=기여자 트랙 타임만 settings.pulls_desc=저장소 풀 리퀘스트 활성화 settings.pulls.ignore_whitespace=공백은 충돌에서 무시하기 @@ -1160,7 +1219,7 @@ settings.update_githook=Hook 갱신 settings.payload_url=대상 URL settings.content_type=POST Content Type settings.secret=비밀 -settings.slack_username=사용자 이름 +settings.slack_username=사용자명 settings.slack_icon_url=아이콘 URL settings.discord_username=사용자명 settings.discord_icon_url=아이콘 URL @@ -1301,7 +1360,7 @@ settings.trust_model.committer.desc = 유효한 서명이 커미터와 일치할 visibility_helper = 저장소 비공개로 만들기 projects.description = 설명 (선택) settings.external_tracker_url_desc = 방문자들이 이슈 탭을 클릭하면 외부 이슈 트레커 URL로 연결됩니다. -settings.tracker_url_format_desc = {user}, {repo} and {index}를 사용자 이름, 저장소 이름, 이슈 번호로 사용할 수 있습니다. +settings.tracker_url_format_desc = {user}를 사용자명, {repo}를 저장소명, {index}를 이슈 번호로 사용할 수 있습니다. projects = 프로젝트 projects.desc = 이슈와 풀 리퀘스트를 프로젝트에서 관리합니다. projects.create = 프로젝트 만들기 @@ -1366,11 +1425,24 @@ pulls.merged_title_desc_one = 님이 %[2]s 에서 %[3]s다른 이슈에서 시간을 기록중입니다!` +issues.stop_tracking = 타이머 정지 +issues.cancel_tracking_history = `취소된 시간 기록 %s` +settings.enter_repo_name = 표시된 소유자와 저장소명을 정확하게 입력하세요: +settings.packagist_username = Packagist 사용자명 + +archive.title_date = 이 저장소는 %s에 보관처리되었습니다. 파일을 볼 수 있고 복제할 수도 있지만, 푸시하거나 이슈를 열거나 풀 리퀘스트를 만들 수 없습니다. + [graphs] [org] org_name_holder=조직 이름 -org_full_name_holder=조직 전체 이름 +org_full_name_holder=조직 별명 create_org=새로운 조직 repo_updated=업데이트됨 %s members=멤버 @@ -1407,7 +1479,7 @@ members.public=보임 members.public_helper=숨기기 members.private=숨김 members.private_helper=보이기 -members.member_role=회원 역할: +members.member_role=멤버 역할: members.owner=소유자 members.member=멤버 members.remove=제거 @@ -1432,6 +1504,8 @@ teams.search_repo_placeholder=저장소 찾기... teams.add_duplicate_users=사용자가 이미 팀 멤버입니다. teams.members.none=이 팀에 멤버가 없습니다. +form.name_pattern_not_allowed = "%s" 패턴이 조직명으로 사용할 수 없습니다. + [admin] dashboard=대시보드 users=사용자 계정 @@ -1631,9 +1705,9 @@ config.db_path=경로 config.service_config=서비스 설정 config.register_email_confirm=가입시 이메일 확인 필수 -config.disable_register=자체등록 사용안함 +config.disable_register=사용자 등록 거부 config.allow_only_external_registration=외부 서비스를 통해서만 등록 허용 -config.enable_openid_signup=OpenID 자체등록 활성화 +config.enable_openid_signup=OpenID 등록 활성화 config.enable_openid_signin=OpenID 로그인 활성화 config.show_registration_button=등록 버튼을 표시 config.require_sign_in_view=페이지를 보려면 로그인 필수 @@ -1642,8 +1716,8 @@ config.enable_captcha=CAPTCHA 활성화 config.active_code_lives=코드 만료 기한 config.default_keep_email_private=기본적으로 이메일 주소를 숨김 config.default_allow_create_organization=기본적으로 조직 생성을 허용 -config.enable_timetracking=타임 트래킹 활성화 -config.default_enable_timetracking=기본 타임 트래킹 활성화 +config.enable_timetracking=시간 기록 활성화 +config.default_enable_timetracking=기본으로 시간 기록을 활성화 config.default_allow_only_contributors_to_track_time=기여자 트랙 타임만 config.no_reply_address=가려진 이메일 도메인 config.default_enable_dependencies=기본적으로 이슈 종속성을 활성화 @@ -1731,6 +1805,13 @@ users.allow_git_hook_tooltip = Git 훅은 Forgejo가 실행중인 OS 유저로 emails.primary = 대표 +emails.filter_sort.name = 사용자명 +emails.filter_sort.name_reverse = 사용자명 (예약됨) +auths.attribute_username_placeholder = 비워두면 Forgejo에 입력된 사용자명을 사용합니다. +auths.sspi_strip_domain_names = 사용자명들에서 도메인명을 제거함 +auths.tip.yandex = %s에 새 애플리케이션을 만듭니다. "Yandex.Passport API"부분의 "Access to email address", "Access to user avatar", "Access to username, first name and surname, gender" 권한을 활성화 하세요. +config.allow_dots_in_usernames = 사용자들이 마침표를 사용자명에 사용할 수 있도록 허가합니다. 이미 존재하는 계정에는 영향을 주지 않습니다. + [action] create_repo=저장소를 만들었습니다. %s rename_repo=저장소 이름을 %[1]s에서에서 %[3]s으로 변경함 @@ -1838,4 +1919,11 @@ package_kind = 패키지 검색... project_kind = 프로젝트 검색... exact_tooltip = 검색어와 정확하게 일치하는 결과만 포함 issue_kind = 이슈 검색... -pull_kind = 풀 검색... \ No newline at end of file +pull_kind = 풀 검색... +fuzzy = 모호함 +union = 통합 검색 +union_tooltip = 공백으로 구분된 키워드 중 하나라도 일치하는 결과를 포함하세요 +exact = 정확한 +regexp = 정규 표현식 +regexp_tooltip = 검색어를 정규 표현식으로 해석합니다 +milestone_kind = 마일스톤 검색... \ No newline at end of file diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 397370c883..30b53cb7e5 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -40,7 +40,7 @@ passcode=Kods webauthn_insert_key=Jāievieto sava drošības atslēga webauthn_sign_in=Jānospiež poga uz drošības. Ja drošības atslēgai nav pogas, tā ir atkārtoti jāievieto. webauthn_press_button=Lūgums nospiest pogu uz savas drošības atslēgas… -webauthn_use_twofa=Izmantot divfaktoru kodu no tālruņa +webauthn_use_twofa=Izmantot divpakāpju kodu no sava tālruņa webauthn_error=Nevar nolasīt drošības atslēgu. webauthn_unsupported_browser=Pārlūks pašlaik nenodrošina WebAuthn. webauthn_error_unknown=Atgadījās nezināma kļūda. Lūgums mēģināt vēlreiz. @@ -52,7 +52,7 @@ webauthn_error_timeout=Iestājās noildze, pirms varēja nolasīt atslēgu. Lūg webauthn_reload=Pārlādēt repository=Glabātava -organization=Organizācija +organization=Apvienība mirror=Spoguļglabātava new_repo=Jauns repozitorijs new_migrate=Jauna migrācija @@ -75,7 +75,7 @@ mirrors=Spoguļglabātavas collaborative=Līdzdarbošanās forks=Atzarojumi -activities=Aktivitāte +activities=Darbības pull_requests=Izmaiņu pieprasījumi issues=Pieteikumi milestones=Atskaites punkti @@ -83,8 +83,8 @@ milestones=Atskaites punkti ok=Labi cancel=Atcelt retry=Mēģināt vēlreiz -rerun=Palaist atkārtoti -rerun_all=Palaist atkārtoti visus darbus +rerun=Atkārtoti izpildīt +rerun_all=Atkārtoti izpildīt visus darbus save=Saglabāt add=Pievienot add_all=Pievienot visus @@ -130,7 +130,7 @@ archived=Arhivētie concept_system_global=Globāls concept_user_individual=Individuāls concept_code_repository=Glabātava -concept_user_organization=Organizācija +concept_user_organization=Apvienība show_timestamps=Rādīt laika zīmogus show_log_seconds=Rādīt sekundes @@ -213,7 +213,7 @@ string.desc=Z - A [error] occurred=Radusies kļūda -report_message=Ja ir pārliecība, ka šī ir Forgejo nepilnība, lūgums pārbaudīt GitHub, vai tā jau nav zināma, vai izveidot jaunu pieteikumu, ja nepieciešams. +report_message=Ja ir pārliecība, ka šī ir Forgejo nepilnība, lūgums pārbaudīt Codeberg, vai tā jau nav zināma, vai izveidot jaunu pieteikumu, ja nepieciešams. missing_csrf=Kļūdains pieprasījums: netika iesūtīta drošības pilnvara invalid_csrf=Kļūdains pieprasījums: iesūtīta kļūdaina drošības pilnvara not_found=Pieprasītie dati netika atrasti. @@ -221,20 +221,20 @@ network_error=Tīkla kļūda server_internal = Iekšēja servera kļūda [startpage] -app_desc=Viegli uzstādāms Git serviss -install=Vienkārši instalējams +app_desc=Pašmitināms Git pakalpojums bez galvassāpēm +install=Viegli uzstādīt install_desc=Vienkārši jāpalaiž izpildāmā datne vajadzīgajai sistēmai, jāizmanto Docker vai jāiegūst pakotne. platform=Pieejama dažādām platformām lightweight=Viegla -lightweight_desc=Forgejo ir miminālas prasības un to var darbināt uz nedārga Raspberry Pi datora. Ietaupi savai ierīcei resursus! +lightweight_desc=Forgejo ir zemas tehniskās prasības, un tas var darboties nedārgā Raspberry Pi. Taupām savu ierīču patērēto enerģiju! license=Atvērtā pirmkoda license_desc=Iegūsti Forgejo! Pievienojies mums līdzdarbojoties, lai padarītu šo projektu vēl labāku! Nekautrējies un līdzdarbojies! -platform_desc = Ir apstiprināts, ka Forgejo darbojas brīvās operētājsistēmāš, piemēram, GNU/Linux un FreeBSD, kā arī ar dažādām procesoru arhitektūrām. Izvēlies to, kas patīk! +platform_desc = Ir apstiprināts, ka Forgejo darbojas brīvās operētājsistēmās, piemēram, GNU/Linux un FreeBSD, kā arī ar dažādām procesoru arhitektūrām. Izvēlies to, kas patīk! [install] -install=Instalācija +install=Uzstādīšana title=Sākotnējā konfigurācija -docker_helper=Ja Forgejo ir uzstādīts Docker konteinerī, izlasiet vadlīninas pirms maināt iestatījumus. +docker_helper=Ja Forgejo ir uzstādīts Docker konteinerā, lūgums izlasīt vadlīnijas, pirms tiek mainīti iestatījumi. require_db_desc=Forgejo nepieciešams MySQL, PostgreSQL, SQLite3 vai TiDB (ar MySQL protokolu). db_title=Datubāzes iestatījumi db_type=Datubāzes veids @@ -247,11 +247,11 @@ db_schema_helper=Atstāt tukšu, lai izmantotu datubāzes noklusējumu ("public" ssl_mode=SSL path=Ceļš sqlite_helper=SQLite3 datubāzes datnes ceļš.
Jāievada pilns ceļš, ja Forgejo tiek palaists kā sistēmas pakalpojums. -reinstall_error=Nevar instalēt datubāzē, kura jau satur Forgejo datus +reinstall_error=Tiek mēģināts uzstādīt esošā Forgejo datubāzē reinstall_confirm_message=Atkārtota uzstādīšana ar esošu Forgejo datubāzi var izraisīt vairākas nebūšanas. Vairumā gadījumu vajadzētu izmantot esošo "app.ini", lai palaistu Forgejo. Jāapstiprina zemāk esošais, ja ir skaidrs, kas tiek darīts: reinstall_confirm_check_1=Dati, kas šifrēti ar SECRET_KEY, kas ir norādīta app.ini datnē, var tikt pazaudēti: lietotāji nevarēs pieteikties ar 2FA/OTP, kā arī spoguļglabātavas var pārstāt darboties. Ar šīs izvēles rūtiņas atzīmēšanu tiek apstiprināts, ka pašreizējā app.ini datne satur pareizu SECRET_KEY vērtību. reinstall_confirm_check_2=Glabātavas un iestatījumus var būt nepieciešams atkārtoti sinhronizēt. Ar šīs izvēles rūtiņas atzīmēšanu tiek apstiprināts, ka pašrocīgi tiks veikta glabātavu aizķeru un authorized_keys datnes atkārtota sinhronizēšana, kā arī tiek apstiprināts, ka tiks nodrošināts, ka glabātavas un spoguļošanas iestatījumi ir pareizi. -reinstall_confirm_check_3=Ar šo tiek apstiprināts, ka ir pilnīga pārliecība, ka Forgejo darbojas ar pareizu app.ini atrašanāš vietu un ka tiešām ir nepieciešama atkārtota uzstādīšana. Tiek apliecināts, ka iepriekšminētais var novest pie kļūmēm. +reinstall_confirm_check_3=Ar šo tiek apstiprināts, ka ir pilnīga pārliecība, ka Forgejo darbojas ar pareizu app.ini atrašanās vietu un ka tiešām ir nepieciešama atkārtota uzstādīšana. Tiek apliecināts, ka iepriekšminētais var novest pie kļūmēm. err_empty_db_path=Nav norādīts SQLite3 datu bāzes ceļš. no_admin_and_disable_registration=Lietotāju reģistrēšanos nevar atspējot bez pārvaldītāja konta izveidošanas. err_empty_admin_password=Pārvaldītāja parole nevar būt tukša. @@ -267,7 +267,7 @@ repo_path=Glabātavu atrašanās vieta repo_path_helper=Attālās Git glabātavas tiks saglabātas šajā mapē. lfs_path=Git LFS atrašanās vieta lfs_path_helper=Datnes, kas pievienotas Git LFS, tiks glabātas šajā mapē. Atstāt tukšu, lai atspējotu. -run_user=Lietotājus, ar kuru palaist +run_user=Lietotājs, ar kuru palaist run_user_helper=Operētājsistēms lietotājs, ar kuru tiks palaists Forgejo. Jāņem vērā, ka šim lietotājam ir jābūt piekļuvei glabātavas atrašanās vietai. domain=Servera domēna vārds domain_helper=Domēns vai servera adrese. @@ -314,19 +314,19 @@ admin_name=Pārvaldītāja lietotājvārds admin_password=Parole confirm_password=Apstiprināt paroli admin_email=E-pasta adrese -install_btn_confirm=Instalēt Forgejo +install_btn_confirm=Uzstādīt Forgejo test_git_failed=Nevarēja pārbaudīt "git" komandu: %v sqlite3_not_available=Šī Forgejo versija neatbalsta SQLite3. Lūgums lejupielādēt oficiālo bināro versiju no %s (ne 'gobuild' versiju). invalid_db_setting=Nederīgi datu bāzes iestatījumi: %v invalid_db_table=Datubāzes tabula "%s" ir kļūdaina: %v invalid_repo_path=Nederīga glabātavu atrašanās vieta: %v -invalid_app_data_path=Lietojumprogrammas datu ceļš ir kļūdains: %v -run_user_not_match="Izpildīt kā lietotājam" lietotājvārds neatbilst pašreizējam lietotājam: %s -> %s +invalid_app_data_path=Lietotnes datu ceļš ir kļūdains: %v +run_user_not_match="Lietotājs, ar kuru palaist" lietotājvārds neatbilst pašreizējam lietotājam: %s -> %s internal_token_failed=Neizdevās izveidot iekšējo pilnvaru: %v secret_key_failed=Neizdevās izveidot drošības atslēgu: %v save_config_failed=Neizdevās saglabāt konfigurāciju: %v invalid_admin_setting=Pārvaldītāja konta iestatījums ir nederīgs: %v -invalid_log_root_path=Nederīgs žurnalizēšanas ceļš: %v +invalid_log_root_path=Žurnāla atrašanās vieta ir nederīga: %v default_keep_email_private=Pēc noklusējuma slēpt e-pasta adreses default_keep_email_private.description=Pēc noklusējuma iespējot e-pasta adreses slēpšanu jauniem lietotājiem, lai šī informāciju nenoplūstu uzreiz pēc reģistrēšanās. default_allow_create_organization=Pēc noklusējuma ļaut apvienību izveidošanu @@ -379,7 +379,7 @@ issues.in_your_repos=Manās glabātavās [explore] repos=Glabātavas users=Lietotāji -organizations=Organizācijas +organizations=Apvienības search=Meklēt go_to=Iet uz code=Kods @@ -424,7 +424,7 @@ account_activated=Konts ir aktivēts prohibit_login=Konta darbība ir apturēta prohibit_login_desc=Kontam ir liegts mijiedarboties ar serveri. Jāsazinās ar tā pārvaldītāju, lai atgūtu piekļuvi. resent_limit_prompt=Nesen jau tika pieprasīts aktivēšanas e-pasta ziņojums. Lūgums uzgaidīt 3 minūtes un mēģināt vēlreiz. -has_unconfirmed_mail=Sveiciens, %s! Tev ir neapstiprināta e-pasta adrese (%s). Ja neesi saņēmis apstiprinājuma e-pasta ziņojumu vai ir nepieciešams nosūtīt jaunu, lūgums klikšķināt uz zemāk esošās pogas. +has_unconfirmed_mail=Sveiciens, %s! Tev ir neapstiprināta e-pasta adrese (%s). Ja nav saņemts apstiprinājuma e-pasta ziņojums vai ir nepieciešams nosūtīt jaunu, lūgums klikšķināt uz zemāk esošās pogas. resend_mail=Klikšķināt šeit, lai atkārtoti nosūtītu aktivēšanas e-pasta ziņojumu email_not_associate=Šī e-pasta adrese nav saistīta ar nevienu kontu. send_reset_mail=Nosūtīt atkopes e-pasta ziņojumu @@ -445,10 +445,10 @@ twofa_scratch_token_incorrect=Ievadīts nepareizs vienreizējais kods. login_userpass=Pieteikties tab_openid=OpenID oauth_signup_tab=Izveidot jaunu kontu -oauth_signup_title=Pabeigt jaunā konta izveidošanu +oauth_signup_title=Pabeigt jauna konta izveidošanu oauth_signup_submit=Pabeigt konta izveidošanu oauth_signin_tab=Sasaistīt ar esošu kontu -oauth_signin_title=Pieteikties, lai autorizētu sasaistīto kontu +oauth_signin_title=Pieteikties, lai pilnvarotu sasaistīto kontu oauth_signin_submit=Sasaistīt kontu oauth.signin.error=Pilnvarošanas pieprasījuma apstrādes laikā atgadījās kļūda. Jā tā atkārtojas, lūgums sazināties ar vietnes pārvaldītāju. oauth.signin.error.access_denied=Pilnvarošanas pieprasījums tika noraidīts. @@ -462,12 +462,12 @@ openid_signin_desc=Jāievada OpenID URI. Piemēram, anna.openid.example.org vai disable_forgot_password_mail=Konta atkopšana ir atspējota, jo nav uzstādīta e-pasta izsūtīšana. Lūgums sazināties ar vietnes pārvaldītāju. disable_forgot_password_mail_admin=Kontu atkope ir pieejama tikai tad, kad ir veikta e-pasta servera iestatīšana. Lūgums iestatīt e-pasta serveri, lai iespējotu kontu atkopi. email_domain_blacklisted=Nav atļauts reģistrēties ar šādu e-pasta adresi. -authorize_application=Autorizēt lietotni -authorize_redirect_notice=Jūs tiksiet nosūtīts uz %s, ja autorizēsiet šo lietotni. +authorize_application=Pilnvarot lietotni +authorize_redirect_notice=Notiks pārvirzīšana uz %s, ja pilnvaroši šo lietotni. authorize_application_created_by=Šo lietotni izveidoja %s. authorize_application_description=Ja nodrošināsi piekļuvi, tā varēs piekļūt visai konta informācijai un mainīt to, tajā skaitā privātās glabātavas un apvienības. authorize_title=Pilnvarot "%s" piekļuvi Tavam kontam? -authorization_failed=Autorizācija neizdevās +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. @@ -507,7 +507,7 @@ register_notify.text_3=Ja šo kontu izveidoja kāds cits, vispirms ir nepiecieš reset_password=Atgūt kontu reset_password.title=%s, esat pieprasījis atjaunot savu kontu -reset_password.text=Nospiediet uz saites, lai atjaunotu savu kontu lapā %s: +reset_password.text=Lūgums klikšķināt uz šīs saites, lai atjaunotu savu %s kontu: register_success=Reģistrācija bija sekmīga @@ -515,7 +515,7 @@ issue_assigned.pull=@%[1]s piešķīra izmaiņu pieprasījumu %[2]s glabātavā issue_assigned.issue=@%[1]s piešķīra pieteikumu %[2]s glabātavā %[3]s. issue.x_mentioned_you=@%s pieminēja Jūs: -issue.action.force_push=%[1]s piespiedu kārtā aizgādāja izmaiņas %[2]s no %[3]s uz %[4]s. +issue.action.force_push=%[1]s uzspiesti aizgādāja izmaiņas %[2]s no %[3]s uz %[4]s. issue.action.push_1=@%[1]s aizgādāja %[3]d iesūtījumu uz %[2]s issue.action.push_n=@%[1]s aizgādāja %[3]d iesūtījumus uz %[2]s issue.action.close=@%[1]s aizvēra #%[2]d. @@ -545,9 +545,9 @@ repo.transfer.body=Lai to pieņemtu vai noraidītu, jāapmeklē %s vai arī vien repo.collaborator.added.subject=%s pievienoja Tevi glabātavai %s kā līdzdalībnieku repo.collaborator.added.text=Tevi pievienoja kā līdzdalībnieku glabātavā: -team_invite.subject=%[1]s uzaicināja Jūs pievienoties organizācijai %[2]s -team_invite.text_1=%[1]s uzaicināja Jūs pievienoties komandai %[2]s organizācijā %[3]s. -team_invite.text_2=Uzspiediet uz šīs saites, lai pievienoties komandai: +team_invite.subject=%[1]s uzaicināja pievienoties apvienībai %[2]s +team_invite.text_1=%[1]s uzaicināja pievienoties apvienības %[3] komandai %[2]s. +team_invite.text_2=Lūgums klikšķināt uz sekojošās saites, lai pievienotos komandai: team_invite.text_3=Piezīme: šis uzaicinājums ir paredzēts %[1]s. Ja šis ielūgums netika gaidīts, šo e-pasta ziņojumu var neņemt vērā. totp_enrolled.subject = Ir aktivēts TOTP kā divpakāpju pieteikšanās veids account_security_caution.text_1 = Ja tas biji Tu, tad šo e-pasta ziņojumu var droši neņemt vērā. @@ -585,7 +585,7 @@ SSHTitle=SSH atslēgas nosaukums HttpsUrl=HTTPS URL PayloadUrl=Vērtuma URL TeamName=Komandas nosaukums -AuthName=Autorizācijas nosaukums +AuthName=Pilnvarošanas nosaukums AdminEmail=Pārvaldītāja e-pasta adrese NewBranchName=Jaunais zara nosaukums @@ -621,14 +621,14 @@ username_been_taken=Lietotājvārds jau ir aizņemts. username_change_not_local_user=Ne-lokālie lietotāji nevar mainīt savus lietotājvārdus. username_has_not_been_changed=Lietotājvārds netika mainīts repo_name_been_taken=Glabātavas nosaukums jau tiek izmantots. -repository_force_private=Iespējoti piespiedu privātās glabātavas: privātās glabātavas nevar padarīt pieejamas visiem. +repository_force_private=Iespējots "Uzspiest privātās": privātās glabātavas nevar padarīt pieejamas visiem. repository_files_already_exist=Šajā glabātavā jau atrodas datnes. Jāsazinās ar sistēmas pārvaldītāju. repository_files_already_exist.adopt=Šajā glabātavā jau atrodas datnes, un tās var tikai tikt pieņemtas. repository_files_already_exist.delete=Šajā glabātavā jau atrodas datnes. Tās ir jāizdzēš. repository_files_already_exist.adopt_or_delete=Šajā glabātavā jau atrodas datnes. Vai nu tās ir jāpieņem vai jāizdzēš. visit_rate_limit=Attālinātā piekļuve ir ierobežota ar ātruma ierobežotāju. 2fa_auth_required=Attālinātai piekļuvei ir nepieciešama divu faktoru autentifikācija. -org_name_been_taken=Organizācijas nosaukums jau ir aizņemts. +org_name_been_taken=Apvienības nosaukums jau ir aizņemts. team_name_been_taken=Komandas nosaukums jau ir aizņemts. team_no_units_error=Komandai ir jābūt iespējotai vismaz vienai sadaļai. email_been_used=E-pasta adrese jau ir izmantota. @@ -641,15 +641,15 @@ password_uppercase_one=Vismaz viens lielais burts password_digit_one=Vismaz viens cipars password_special_one=Vismaz viena īpaša rakstzīme (punkts, iekavas, pēdiņas utt.) enterred_invalid_repo_name=Ievadītais glabātavas nosaukums ir nepareizs. -enterred_invalid_org_name=Ievadītais organizācijas nosaukums ir nepareizs. +enterred_invalid_org_name=Ievadītais apvienības nosaukums ir nepareizs. enterred_invalid_owner_name=Jaunā īpašnieka vārds nav derīgs. enterred_invalid_password=Ievadītā parole ir nepareiza. user_not_exist=Lietotājs nepastāv. team_not_exist=Komanda nepastāv. last_org_owner=Nevar noņemt īpašnieku komandas pēdējo lietotāju. Apvienībai ir jābūt vismaz vienam īpašniekam. -cannot_add_org_to_team=Organizāciju nevar pievienot kā komandas biedru. -duplicate_invite_to_team=Lietotājs jau ir uzaicināts kā komandas biedrs. -organization_leave_success=Jūs esat pametis organizāciju %s. +cannot_add_org_to_team=Apvienību nevar pievienot kā komandas dalībnieku. +duplicate_invite_to_team=Lietotājs jau tika uzaicināts kā komandas dalībnieks. +organization_leave_success=Ir veiksmīgi atstāta apvienība %s. invalid_ssh_key=Nav iespējams pārbaudīt SSH atslēgu: %s invalid_gpg_key=Nav iespējams pārbaudīt GPG atslēgu: %s @@ -680,6 +680,8 @@ AccessToken = Piekļuves pilnvara To = Zara nosaukums +email_domain_is_not_allowed = Lietotāja e-pasta adreses %s domēna vārds ir pretrunāt ar EMAIL_DOMAIN_ALLOWLIST vai EMAIL_DOMAIN_BLOCKLIST. Jāpārliecinās, ka e-pasta adrese ir norādīta pareizi. + [user] change_avatar=Mainīt profila attēlu… joined_on=Pievienojās %s @@ -695,7 +697,7 @@ following_few=%d seko follow=Sekot unfollow=Nesekot user_bio=Biogrāfija -disabled_public_activity=Šis lietotājs ir atslēdzies iespēju aplūkot tā aktivitāti. +disabled_public_activity=Šis lietotājs ir atspējojis darbību redzamību visiem. email_visibility.limited=E-pasta adrese ir redzama visiem autentificētajiem lietotājiem email_visibility.private=E-pasta adrese ir redzama tikai administratoriem show_on_map=Rādīt šo vietu kartē @@ -734,19 +736,19 @@ avatar=Profila attēls ssh_gpg_keys=SSH / GPG atslēgas social=Sociālie konti applications=Lietotnes -orgs=Pārvaldīt apvienības +orgs=Apvienības repos=Glabātavas -delete=Dzēst kontu +delete=Izdzēst kontu twofa=Divpakāpju pieteikšanās (TOTP) account_link=Saistītie konti -organization=Organizācijas +organization=Apvienības uid=UID webauthn=Divpakāpju pieteikšanās (drošības atslēgas) public_profile=Publiskais 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=Norādīt, kā profils tiek attēlots citiem lietotājiem. Primārā e-pasta adrese tiks izmantota paziņojumiem, paroles atjaunošanai un Git tīmekļa darbībām. +profile_desc=Par Tevi password_username_disabled=Ārējiem lietotājiem nav atļauts mainīt savu lietotājvārdu. Lūgums sazināties ar vietnes pārvaldītāju, lai uzzinātu vairāk. full_name=Pilns vārds website=Mājas lapa @@ -759,13 +761,13 @@ update_language_success=Valoda tika nomainīta. update_profile_success=Profils tika atjaunināts. change_username=Lietotājvārds mainīts. change_username_prompt=Piezīme: lietotājvārda mainīšana maina arī konta URL. -change_username_redirect_prompt=Iepriekšējais lietotājvārds tiks pārvirzīts, kamēr neviens cits to neizmanto. +change_username_redirect_prompt=Iepriekšējais lietotājvārds tiks pārvirzīts, līdz kāds to izmantos. continue=Turpināt cancel=Atcelt language=Valoda ui=Motīvs hidden_comment_types=Slēpjamo piebilžu veidi -hidden_comment_types_description=Šeit atzīmētie piebilžu veidi netiks attēloti pieteikumu lapās. "Iezīme" atzīmēšana, piemēram, noņems visas " pievienoja/noņēma