diff --git a/.deadcode-out b/.deadcode-out index 24facdf12e..61c5bcb055 100644 --- a/.deadcode-out +++ b/.deadcode-out @@ -13,6 +13,13 @@ forgejo.org/models IsErrSHANotFound IsErrMergeDivergingFastForwardOnly +forgejo.org/models/activities + GetActivityByID + NewFederatedUserActivity + CreateUserActivity + GetFollowingFeeds + FederatedUserActivity.loadActor + forgejo.org/models/auth WebAuthnCredentials @@ -20,13 +27,15 @@ forgejo.org/models/db TruncateBeans InTransaction DumpTables - GetTableNames forgejo.org/models/dbfs file.renameTo Create Rename +forgejo.org/models/forgefed + GetFederationHost + forgejo.org/models/forgejo/semver GetVersion SetVersionString @@ -52,10 +61,17 @@ forgejo.org/models/user IsErrExternalLoginUserAlreadyExist IsErrExternalLoginUserNotExist NewFederatedUser + NewFederatedUserFollower IsErrUserSettingIsNotExist GetUserAllSettings DeleteUserSetting GetFederatedUser + GetFederatedUserByUserID + UpdateFederatedUser + GetFollowersForUser + AddFollower + RemoveFollower + IsFollowingAp forgejo.org/modules/activitypub NewContext @@ -86,14 +102,24 @@ forgejo.org/modules/eventsource Event.String forgejo.org/modules/forgefed + NewForgeFollowFromAp NewForgeFollow + ForgeFollow.MarshalJSON + ForgeFollow.UnmarshalJSON + ForgeFollow.Validate NewForgeUndoLike ForgeUndoLike.UnmarshalJSON ForgeUndoLike.Validate + NewForgeUserActivityFromAp + NewForgeUserActivity + ForgeUserActivity.Validate NewPersonIDFromModel GetItemByType JSONUnmarshalerFn NotEmpty + NewForgeUserActivityNoteFromAp + newNote + ForgeUserActivityNote.Validate ToRepository OnRepository @@ -205,6 +231,7 @@ forgejo.org/modules/util/filebuffer forgejo.org/modules/validation IsErrNotValid + ValidateIDExists forgejo.org/modules/web RouteMock @@ -221,9 +248,6 @@ forgejo.org/routers/web/org forgejo.org/services/context GetPrivateContext -forgejo.org/services/federation - FollowRemoteActor - forgejo.org/services/repository IsErrForkAlreadyExist diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 3f250e5682..28fa9e4555 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,7 +6,7 @@ "ghcr.io/devcontainers/features/node:1": { "version": "22" }, - "ghcr.io/devcontainers/features/git-lfs:1.2.5": {}, + "ghcr.io/devcontainers/features/git-lfs:1.2.4": {}, "ghcr.io/warrenbuckley/codespace-features/sqlite:1": {} }, "customizations": { diff --git a/.forgejo/issue_template/bug-report-ui.yaml b/.forgejo/issue_template/bug-report-ui.yaml index 1c66c3b648..8bb7bf1d49 100644 --- a/.forgejo/issue_template/bug-report-ui.yaml +++ b/.forgejo/issue_template/bug-report-ui.yaml @@ -23,9 +23,8 @@ body: It is running the latest development branch and will confirm the problem is not already fixed. If you can reproduce it, provide a URL in the description. options: - - "Yes, I've linked the repository below" - - "No, I've tried it and the problem is not present there" - - "No, I can't try it on the test instance for some reason" + - "Yes" + - "No" validations: required: true - type: textarea diff --git a/.forgejo/issue_template/bug-report.yaml b/.forgejo/issue_template/bug-report.yaml index c11ebf9c1f..a2b50dbca2 100644 --- a/.forgejo/issue_template/bug-report.yaml +++ b/.forgejo/issue_template/bug-report.yaml @@ -23,9 +23,8 @@ body: It is running the latest development branch and will confirm the problem is not already fixed. If you can reproduce it, provide a URL in the description. options: - - "Yes, I've linked the repository below" - - "No, I've tried it and the problem is not present there" - - "No, I can't try it on the test instance for some reason" + - "Yes" + - "No" validations: required: true - type: textarea diff --git a/.forgejo/workflows-composite/install-minimum-git-version/action.yaml b/.forgejo/workflows-composite/install-minimum-git-version/action.yaml deleted file mode 100644 index d4e6e3f2a7..0000000000 --- a/.forgejo/workflows-composite/install-minimum-git-version/action.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Install the minimal version of Git supported by Forgejo -# -runs: - using: "composite" - steps: - - name: install git and git-lfs - run: | - set -x - - export DEBIAN_FRONTEND=noninteractive - - apt-get update -qq - apt-get -q install -y -qq curl ca-certificates - - curl -sS -o /tmp/git-man.deb http://archive.ubuntu.com/ubuntu/pool/main/g/git/git-man_2.34.1-1ubuntu1_all.deb - curl -sS -o /tmp/git.deb https://archive.ubuntu.com/ubuntu/pool/main/g/git/git_2.34.1-1ubuntu1_amd64.deb - curl -sS -o /tmp/git-lfs.deb https://archive.ubuntu.com/ubuntu/pool/universe/g/git-lfs/git-lfs_3.0.2-1_amd64.deb - - apt-get -q install --allow-downgrades -y -qq /tmp/git-man.deb - apt-get -q install --allow-downgrades -y -qq /tmp/git.deb - apt-get -q install --allow-downgrades -y -qq /tmp/git-lfs.deb diff --git a/.forgejo/workflows/build-release-integration.yml b/.forgejo/workflows/build-release-integration.yml index 6fecac3ff6..1af6d567dd 100644 --- a/.forgejo/workflows/build-release-integration.yml +++ b/.forgejo/workflows/build-release-integration.yml @@ -28,7 +28,7 @@ jobs: - uses: https://data.forgejo.org/actions/checkout@v4 - id: forgejo - uses: https://data.forgejo.org/actions/setup-forgejo@v3.0.3 + uses: https://data.forgejo.org/actions/setup-forgejo@v2.0.4 with: user: root password: admin1234 diff --git a/.forgejo/workflows/build-release.yml b/.forgejo/workflows/build-release.yml index b70439f12f..3ab63b0589 100644 --- a/.forgejo/workflows/build-release.yml +++ b/.forgejo/workflows/build-release.yml @@ -164,7 +164,7 @@ jobs: - name: build container & release if: ${{ secrets.TOKEN != '' }} - uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.4.1 + uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.5 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.4.1 + uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.5 with: forgejo: "${{ env.GITHUB_SERVER_URL }}" owner: "${{ env.GITHUB_REPOSITORY_OWNER }}" @@ -201,7 +201,7 @@ jobs: - name: end-to-end tests if: ${{ secrets.TOKEN != '' && vars.ROLE == 'forgejo-integration' && vars.SKIP_END_TO_END != 'true' }} - uses: https://data.forgejo.org/actions/cascading-pr@v2.3.0 + uses: https://data.forgejo.org/actions/cascading-pr@v2.2.0 with: origin-url: ${{ env.GITHUB_SERVER_URL }} origin-repo: ${{ github.repository }} @@ -212,7 +212,6 @@ jobs: destination-repo: forgejo/end-to-end destination-branch: main destination-token: ${{ secrets.CASCADE_DESTINATION_TOKEN }} - close: true update: .forgejo/cascading-release-end-to-end - name: copy to experimental diff --git a/.forgejo/workflows/cascade-setup-end-to-end.yml b/.forgejo/workflows/cascade-setup-end-to-end.yml index e62dbd9e7d..7c8c56de13 100644 --- a/.forgejo/workflows/cascade-setup-end-to-end.yml +++ b/.forgejo/workflows/cascade-setup-end-to-end.yml @@ -41,7 +41,7 @@ jobs: with: fetch-depth: '0' show-progress: 'false' - - uses: https://data.forgejo.org/actions/cascading-pr@v2.3.0 + - uses: https://data.forgejo.org/actions/cascading-pr@v2.2.0 with: origin-url: ${{ env.GITHUB_SERVER_URL }} origin-repo: ${{ github.repository }} @@ -53,5 +53,5 @@ jobs: destination-repo: forgejo/end-to-end destination-branch: main destination-token: ${{ secrets.END_TO_END_CASCADING_PR_DESTINATION }} - close: true + close-merge: true update: .forgejo/cascading-pr-end-to-end diff --git a/.forgejo/workflows/coverage.yml b/.forgejo/workflows/coverage.yml deleted file mode 100644 index 194b116251..0000000000 --- a/.forgejo/workflows/coverage.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: coverage - -on: - workflow_dispatch: - inputs: - repository: - description: 'repository' - type: string - ref: - description: 'ref' - type: string - unit-tests-env: - description: 'COVERAGE_TEST_PACKAGES=forgejo.org/modules/actions' - type: string - integration-tests-env: - description: 'COVERAGE_TEST_ARGS=-run=TestAPIListRepoComments' - type: string - -jobs: - all: - runs-on: docker - container: - image: 'data.forgejo.org/oci/ci:1' - options: --tmpfs /tmp:exec,noatime - services: - elasticsearch: - image: data.forgejo.org/oci/bitnami/elasticsearch:7 - options: --tmpfs /bitnami/elasticsearch/data - env: - discovery.type: single-node - ES_JAVA_OPTS: "-Xms512m -Xmx512m" - minio: - image: data.forgejo.org/oci/bitnami/minio:2024.8.17 - options: >- - --hostname gitea.minio --tmpfs /bitnami/minio/data:noatime - env: - MINIO_DOMAIN: minio - MINIO_ROOT_USER: 123456 - MINIO_ROOT_PASSWORD: 12345678 - mysql: - image: 'data.forgejo.org/oci/bitnami/mysql:8.4' - env: - ALLOW_EMPTY_PASSWORD: yes - MYSQL_DATABASE: testgitea - # - # See also https://codeberg.org/forgejo/forgejo/issues/976 - # - MYSQL_EXTRA_FLAGS: --innodb-adaptive-flushing=OFF --innodb-buffer-pool-size=4G --innodb-log-buffer-size=128M --innodb-flush-log-at-trx-commit=0 --innodb-flush-log-at-timeout=30 --innodb-flush-method=nosync --innodb-fsync-threshold=1000000000 --disable-log-bin - options: --tmpfs /bitnami/mysql/data:noatime - ldap: - image: data.forgejo.org/oci/test-openldap:latest - pgsql: - image: data.forgejo.org/oci/bitnami/postgresql:16 - env: - POSTGRESQL_DATABASE: test - POSTGRESQL_PASSWORD: postgres - POSTGRESQL_FSYNC: off - POSTGRESQL_EXTRA_FLAGS: -c full_page_writes=off - options: --tmpfs /bitnami/postgresql - cacher: - image: registry.redict.io/redict:7.3.5-scratch - options: --tmpfs /data:noatime - steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - with: - repository: ${{ inputs.repository }} - ref: ${{ inputs.ref }} - - uses: ./.forgejo/workflows-composite/setup-env - - name: install git >= 2.42 - uses: ./.forgejo/workflows-composite/apt-install-from - with: - packages: git - - uses: ./.forgejo/workflows-composite/build-backend - - run: | - su forgejo -c '${{ inputs.unit-tests-env }} make coverage-run' - su forgejo -c '${{ inputs.integration-tests-env }} make coverage-run-pgsql' - su forgejo -c '${{ inputs.integration-tests-env }} make coverage-run-mysql' - su forgejo -c '${{ inputs.integration-tests-env }} make coverage-run-sqlite' - su forgejo -c 'make coverage-merge' - timeout-minutes: 180 - env: - TEST_ELASTICSEARCH_URL: http://elasticsearch:9200 - TEST_MINIO_ENDPOINT: minio:9000 - TEST_LDAP: 1 - TEST_REDIS_SERVER: cacher:6379 - - uses: https://code.forgejo.org/forgejo/upload-artifact@v4 - with: - name: coverage - path: ${{ forge.workspace }}/coverage/merged diff --git a/.forgejo/workflows/merge-requirements.yml b/.forgejo/workflows/merge-requirements.yml index 9bed4b8797..9aaf2af68d 100644 --- a/.forgejo/workflows/merge-requirements.yml +++ b/.forgejo/workflows/merge-requirements.yml @@ -1,4 +1,4 @@ -# Copyright 2025 The Forgejo Authors +# Copyright 2024 The Forgejo Authors # SPDX-License-Identifier: MIT name: requirements @@ -13,8 +13,7 @@ on: jobs: merge-conditions: - if: > - vars.ROLE == 'forgejo-coding' && forge.event.pull_request.head.repo.full_name != 'forgejo-cascading-pr/forgejo' + if: vars.ROLE == 'forgejo-coding' runs-on: docker container: image: 'data.forgejo.org/oci/node:22-bookworm' @@ -27,9 +26,9 @@ jobs: - name: Missing test label if: > !( - contains(toJSON(forge.event.pull_request.labels), 'test/present') - || contains(toJSON(forge.event.pull_request.labels), 'test/not-needed') - || contains(toJSON(forge.event.pull_request.labels), 'test/manual') + contains(toJSON(github.event.pull_request.labels), 'test/present') + || contains(toJSON(github.event.pull_request.labels), 'test/not-needed') + || contains(toJSON(github.event.pull_request.labels), 'test/manual') ) run: | echo "A team member must set the label to either 'present', 'not-needed' or 'manual'." @@ -37,8 +36,8 @@ jobs: - name: Missing manual test instructions if: > ( - contains(toJSON(forge.event.pull_request.labels), 'test/manual') - && !contains(toJSON(forge.event.pull_request.body), '# Test') + contains(toJSON(github.event.pull_request.labels), 'test/manual') + && !contains(toJSON(github.event.pull_request.body), '# Test') ) run: | echo "Manual test label is set. The PR description needs to contain test steps introduced by a heading like:" diff --git a/.forgejo/workflows/publish-release.yml b/.forgejo/workflows/publish-release.yml index 5303f902e3..3aec46fb03 100644 --- a/.forgejo/workflows/publish-release.yml +++ b/.forgejo/workflows/publish-release.yml @@ -44,7 +44,7 @@ jobs: - uses: https://data.forgejo.org/actions/checkout@v4 - name: copy & sign - uses: https://data.forgejo.org/forgejo/forgejo-build-publish/publish@v5.4.1 + uses: https://data.forgejo.org/forgejo/forgejo-build-publish/publish@v5.3.5 with: from-forgejo: ${{ vars.FORGEJO }} to-forgejo: ${{ vars.FORGEJO }} @@ -80,7 +80,7 @@ jobs: label: trigger - name: upgrade v*.next.forgejo.org - uses: https://data.forgejo.org/infrastructure/next-digest@v1.2.2 + uses: https://data.forgejo.org/infrastructure/next-digest@v1.1.0 with: url: https://placeholder:${{ secrets.TOKEN_NEXT_DIGEST }}@invisible.forgejo.org/infrastructure/next-digest ref_name: '${{ github.ref_name }}' diff --git a/.forgejo/workflows/release-notes-assistant-milestones.yml b/.forgejo/workflows/release-notes-assistant-milestones.yml index 57c9a23f02..7f77098357 100644 --- a/.forgejo/workflows/release-notes-assistant-milestones.yml +++ b/.forgejo/workflows/release-notes-assistant-milestones.yml @@ -5,34 +5,32 @@ on: - cron: '@daily' env: - RNA_WORKDIR: /srv/rna - RNA_VERSION: v1.4.1 # renovate: datasource=gitea-releases depName=forgejo/release-notes-assistant registryUrl=https://code.forgejo.org + RNA_VERSION: v1.2.5 # renovate: datasource=gitea-releases depName=forgejo/release-notes-assistant registryUrl=https://code.forgejo.org jobs: release-notes: if: vars.ROLE == 'forgejo-coding' runs-on: docker container: - image: 'data.forgejo.org/oci/ci:1' + image: 'data.forgejo.org/oci/node:22-bookworm' steps: - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: https://data.forgejo.org/actions/cache@v4 + - uses: https://data.forgejo.org/actions/setup-go@v5 with: - key: rna-${{ env.RNA_VERSION }} - path: ${{ env.RNA_WORKDIR }} + go-version-file: "go.mod" + cache: false - - name: install release-notes-assistant + - name: apt install jq run: | - set -x - wget -O /usr/local/bin/rna https://code.forgejo.org/forgejo/release-notes-assistant/releases/download/${{ env.RNA_VERSION}}/release-notes-assistant - chmod +x /usr/local/bin/rna + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq + apt-get -q install -y -qq jq - name: update open milestones run: | set -x - mkdir -p ${{ env.RNA_WORKDIR }} - curl -sS $FORGEJO_SERVER_URL/api/v1/repos/$FORGEJO_REPOSITORY/milestones?state=open | jq -r '.[] | .title' | while read forgejo version ; do + curl -sS $GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY/milestones?state=open | jq -r '.[] | .title' | while read forgejo version ; do milestone="$forgejo $version" - rna --workdir ${{ env.RNA_WORKDIR }} --config .release-notes-assistant.yaml --storage milestone --storage-location "$milestone" --forgejo-url $FORGEJO_SERVER_URL --repository $FORGEJO_REPOSITORY --token ${{ secrets.RELEASE_NOTES_ASSISTANT_TOKEN }} release $version + go run code.forgejo.org/forgejo/release-notes-assistant@$RNA_VERSION --config .release-notes-assistant.yaml --storage milestone --storage-location "$milestone" --forgejo-url $GITHUB_SERVER_URL --repository $GITHUB_REPOSITORY --token ${{ secrets.RELEASE_NOTES_ASSISTANT_TOKEN }} release $version done diff --git a/.forgejo/workflows/release-notes-assistant.yml b/.forgejo/workflows/release-notes-assistant.yml index a727e57afb..cdcd2e6fe4 100644 --- a/.forgejo/workflows/release-notes-assistant.yml +++ b/.forgejo/workflows/release-notes-assistant.yml @@ -8,7 +8,7 @@ on: - labeled env: - RNA_VERSION: v1.4.1 # renovate: datasource=gitea-releases depName=forgejo/release-notes-assistant registryUrl=https://code.forgejo.org + RNA_VERSION: v1.2.5 # renovate: datasource=gitea-releases depName=forgejo/release-notes-assistant registryUrl=https://code.forgejo.org jobs: release-notes: diff --git a/.forgejo/workflows/renovate.yml b/.forgejo/workflows/renovate.yml index 9e7f03f299..5aa6c8cd98 100644 --- a/.forgejo/workflows/renovate.yml +++ b/.forgejo/workflows/renovate.yml @@ -28,7 +28,7 @@ jobs: runs-on: docker container: - image: data.forgejo.org/renovate/renovate:41.76.0 + image: data.forgejo.org/renovate/renovate:41.1.4 steps: - name: Load renovate repo cache @@ -49,7 +49,7 @@ jobs: LOG_LEVEL: debug RENOVATE_BASE_DIR: ${{ github.workspace }}/.tmp RENOVATE_ENDPOINT: ${{ github.server_url }} - RENOVATE_PLATFORM: forgejo + RENOVATE_PLATFORM: gitea RENOVATE_REPOSITORY_CACHE: 'enabled' RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }} RENOVATE_GIT_AUTHOR: 'Renovate Bot ' @@ -63,10 +63,6 @@ jobs: OSV_OFFLINE_ROOT_DIR: ${{ github.workspace }}/.tmp/osv - # use direct connection for these domains for renovate go datasource instead of the go proxy - # allows faster lookups - GONOPROXY: code.forgejo.org - - name: Save renovate repo cache if: always() && env.RENOVATE_DRY_RUN != 'full' uses: https://data.forgejo.org/actions/cache/save@3624ceb22c1c5a301c8db4169662070a689d9ea8 # v4.1.1 diff --git a/.forgejo/workflows/testing-integration.yml b/.forgejo/workflows/testing-integration.yml index 6822c45f39..9e5cfb92ed 100644 --- a/.forgejo/workflows/testing-integration.yml +++ b/.forgejo/workflows/testing-integration.yml @@ -1,8 +1,7 @@ # # Additional integration tests designed to run once a day when # `mirror.yml` pushes to https://codeberg.org/forgejo-integration/forgejo -# and send a notification via email to the contact email of the -# organization should they fail. +# and send a notification via email should they fail. # # For debug purposes: # @@ -23,8 +22,6 @@ on: - 'forgejo' - 'v*/forgejo' -enable-email-notifications: true - jobs: test-unit: # if: vars.ROLE == 'forgejo-coding' @@ -36,8 +33,11 @@ jobs: steps: - uses: https://data.forgejo.org/actions/checkout@v4 - uses: ./.forgejo/workflows-composite/setup-env - - name: install git 2.34.1 and git-lfs 3.0.2 - uses: ./.forgejo/workflows-composite/install-minimum-git-version + - name: install git 2.30 + uses: ./.forgejo/workflows-composite/apt-install-from + with: + packages: git/bullseye git-lfs/bullseye + release: bullseye - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-backend test-check' @@ -55,8 +55,11 @@ jobs: steps: - uses: https://data.forgejo.org/actions/checkout@v4 - uses: ./.forgejo/workflows-composite/setup-env - - name: install git 2.34.1 and git-lfs 3.0.2 - uses: ./.forgejo/workflows-composite/install-minimum-git-version + - name: install git 2.30 + uses: ./.forgejo/workflows-composite/apt-install-from + with: + packages: git/bullseye git-lfs/bullseye + release: bullseye - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-sqlite-migration test-sqlite' @@ -66,34 +69,3 @@ jobs: RACE_ENABLED: true TEST_TAGS: sqlite sqlite_unlock_notify USE_REPO_TEST_DIR: 1 - test-mariadb: -# if: vars.ROLE == 'forgejo-coding' - if: vars.ROLE == 'forgejo-integration' - runs-on: docker - name: ${{ format('test-mariadb (v{0})', matrix.version) }} - strategy: - matrix: - version: ['10.6', '11.8'] - container: - image: 'data.forgejo.org/oci/node:22-bookworm' - options: --tmpfs /tmp:exec,noatime - services: - mysql: - image: ${{ format('data.forgejo.org/oci/mariadb:{0}', matrix.version) }} - env: - MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: yes - MARIADB_DATABASE: testgitea - options: --tmpfs /var/lib/mysql:noatime - steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - uses: ./.forgejo/workflows-composite/setup-env - - name: install dependencies & git >= 2.42 - uses: ./.forgejo/workflows-composite/apt-install-from - with: - packages: git 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 diff --git a/.forgejo/workflows/testing.yml b/.forgejo/workflows/testing.yml index 4c5e18a5e9..7a93bb66a8 100644 --- a/.forgejo/workflows/testing.yml +++ b/.forgejo/workflows/testing.yml @@ -37,11 +37,7 @@ jobs: - run: make deps-frontend - run: make lint-frontend - run: make checks-frontend - - run: | - # Usage of `dayjs` can be impacted by local system timezone and can be sensitive to DST differences; since - # frontend tests are very short they're run twice with varying DST rules to reduce regression risk. - TZ=Europe/Berlin make test-frontend-coverage - TZ=America/Edmonton make test-frontend-coverage + - run: make test-frontend-coverage - run: make frontend - name: Install zstd for cache saving # works around https://github.com/actions/cache/issues/1169, because the diff --git a/.gitignore b/.gitignore index ffc493a51d..744e24a09a 100644 --- a/.gitignore +++ b/.gitignore @@ -37,8 +37,6 @@ _testmain.go *coverage.out coverage.all -coverage.html -coverage.html.gz coverage/ cpu.out @@ -55,8 +53,6 @@ cpu.out *.log *.log.*.gz -/build/lint-locale/lint-locale -/build/lint-locale-usage/lint-locale-usage /gitea /gitea-vet /debug @@ -133,4 +129,3 @@ prime/ # Manpage /man -tests/integration/api_activitypub_person_inbox_useractivity_test.go diff --git a/.golangci.yml b/.golangci.yml index b8884dd080..532132838d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -42,10 +42,6 @@ linters: desc: do not use the ini package, use gitea's config system instead - pkg: github.com/minio/sha256-simd desc: use crypto/sha256 instead, see https://codeberg.org/forgejo/forgejo/pulls/1528 - - pkg: github.com/go-git/go-git - desc: use forgejo.org/modules/git instead, see https://codeberg.org/forgejo/forgejo/pulls/4941 - - pkg: gopkg.in/yaml.v3 - desc: use go.yaml.in/yaml instead, see https://codeberg.org/forgejo/forgejo/pulls/8956 gocritic: disabled-checks: - ifElseChain @@ -83,10 +79,6 @@ linters: - name: unreachable-code - name: var-declaration - name: var-naming - arguments: - - [] - - [] - - - skip-package-name-checks: true - name: redefines-builtin-id disabled: true staticcheck: diff --git a/CODEOWNERS b/CODEOWNERS index 25a3f698dc..34cdceca09 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -39,5 +39,4 @@ options/locale/.* @0ko options/locale_next/.* @0ko # Personal interest -build/lint-locale-usage/.* @fogti .*/webhook.* @oliverpool diff --git a/Makefile b/Makefile index 6f7a99d40c..e770f2a989 100644 --- a/Makefile +++ b/Makefile @@ -39,15 +39,15 @@ XGO_VERSION := go-1.21.x AIR_PACKAGE ?= github.com/air-verse/air@v1 # renovate: datasource=go EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.3.0 # renovate: datasource=go GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.8.0 # renovate: datasource=go -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.3.1 # renovate: datasource=go -GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15 # renovate: datasource=go +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 # renovate: datasource=go +GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 # renovate: datasource=go SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 # renovate: datasource=go XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0 # renovate: datasource=go GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go -DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.36.0 # renovate: datasource=go -GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.6.0 # renovate: datasource=go -RENOVATE_NPM_PACKAGE ?= renovate@41.76.0 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate +DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.34.0 # renovate: datasource=go +GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.5.2 # renovate: datasource=go +RENOVATE_NPM_PACKAGE ?= renovate@41.1.4 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate # https://github.com/disposable-email-domains/disposable-email-domains/commits/main/ DISPOSABLE_EMAILS_SHA ?= 0c27e671231d27cf66370034d7f6818037416989 # renovate: ... @@ -115,6 +115,9 @@ LDFLAGS := $(LDFLAGS) -X "main.ReleaseVersion=$(RELEASE_VERSION)" -X "main.MakeV LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64 +ifeq ($(HAS_GO), yes) + GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list forgejo.org/models/migrations/...) $(shell $(GO) list forgejo.org/models/forgejo_migrations/...) forgejo.org/tests/integration/migration-test forgejo.org/tests forgejo.org/tests/integration forgejo.org/tests/e2e,$(shell $(GO) list ./...)) +endif REMOTE_CACHER_MODULES ?= cache nosql session queue GO_TEST_REMOTE_CACHER_PACKAGES ?= $(addprefix forgejo.org/modules/,$(REMOTE_CACHER_MODULES)) @@ -156,6 +159,9 @@ GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" ! -path modules/optio GO_SOURCES += $(GENERATED_GO_DEST) GO_SOURCES_NO_BINDATA := $(GO_SOURCES) +ifeq ($(HAS_GO), yes) + MIGRATION_PACKAGES := $(shell $(GO) list forgejo.org/models/migrations/... forgejo.org/models/forgejo_migrations/...) +endif ifeq ($(filter $(TAGS_SPLIT),bindata),bindata) GO_SOURCES += $(BINDATA_DEST) @@ -232,9 +238,6 @@ help: @echo " - test-frontend-coverage test frontend files and display code coverage" @echo " - test-backend test backend files" @echo " - test-remote-cacher test backend files that use a remote cache" - @echo " - coverage-run* test and collect coverages in the coverage/data directory" - @echo " - coverage-show-html display coverage-run results in an HTML page" - @echo " - coverage-show-percent display coverage-run per package coverage percentage" @echo " - test-e2e-sqlite[\#name.test.e2e] test end to end using playwright and sqlite" @echo " - webpack build webpack files" @echo " - svg build svg files" @@ -279,24 +282,6 @@ show-version-minor: verify-version show-version-api: verify-version @echo ${FORGEJO_VERSION_API} -### -# Package computation targets -### - -# Target to compute GO_TEST_PACKAGES - only runs when needed -.PHONY: compute-go-test-packages -compute-go-test-packages: -ifeq ($(HAS_GO), yes) - $(eval GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list forgejo.org/models/migrations/...) $(shell $(GO) list forgejo.org/models/forgejo_migrations/...) forgejo.org/tests/integration/migration-test forgejo.org/tests forgejo.org/tests/integration forgejo.org/tests/e2e,$(shell $(GO) list ./...))) -endif - -# Target to compute MIGRATION_PACKAGES - only runs when needed -.PHONY: compute-migration-packages -compute-migration-packages: -ifeq ($(HAS_GO), yes) - $(eval MIGRATION_PACKAGES := $(shell $(GO) list forgejo.org/models/migrations/... forgejo.org/models/forgejo_migrations/...)) -endif - ### # Check system and environment requirements ### @@ -475,7 +460,7 @@ lint-locale: .PHONY: lint-locale-usage lint-locale-usage: - $(GO) run ./build/lint-locale-usage --allow-masked-usages-from=build/lint-locale-usage/allowed-masked-usage.txt + $(GO) run build/lint-locale-usage/lint-locale-usage.go .PHONY: lint-md lint-md: node_modules @@ -537,9 +522,9 @@ watch-backend: go-check test: test-frontend test-backend .PHONY: test-backend -test-backend: | compute-go-test-packages +test-backend: @echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." - @TZ=UTC $(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES) + @$(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES) .PHONY: test-remote-cacher test-remote-cacher: @@ -567,39 +552,20 @@ test-check: fi .PHONY: test\#% -test\#%: | compute-go-test-packages +test\#%: @echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." - @TZ=UTC $(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES) + @$(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES) -coverage-merge: - rm -fr coverage/merged ; mkdir -p coverage/merged - $(GO) tool covdata merge -i `find coverage/data -name 'covmeta.*' | sed -e 's|/covmeta.*|,|' | tr -d '\n' | sed -e 's/,$$//'` -o coverage/merged +.PHONY: coverage +coverage: + grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' coverage.out > coverage-bodged.out + grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' integration.coverage.out > integration.coverage-bodged.out + $(GO) run build/gocovmerge.go integration.coverage-bodged.out coverage-bodged.out > coverage.all -coverage-convert: coverage-merge - $(GO) tool covdata textfmt -i=coverage/merged -o=coverage/textfmt.out - -coverage-show-html: coverage-convert - ( cd coverage ; $(GO) tool cover -html=textfmt.out -o coverage.html ) - xdg-open coverage/coverage.html - -coverage-show-percentage: coverage-convert - go tool cover -func=coverage/textfmt.out - -coverage-run: | compute-go-test-packages - contrib/coverage-helper.sh test_packages $(COVERAGE_TEST_PACKAGES) - -coverage-run-%: generate-ini-% | compute-migration-packages - # - # Migration tests go first - # - $(MAKE) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/$*.ini COVERAGE_TEST_ARGS= COVERAGE_TEST_PACKAGES=forgejo.org/tests/integration/migration-test coverage-run - for pkg in $(MIGRATION_PACKAGES); do \ - $(MAKE) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/$*.ini COVERAGE_TEST_DATABASE=$* COVERAGE_TEST_ARGS= COVERAGE_TEST_PACKAGES=$$pkg coverage-run ; \ - done - # - # All other integration tests follow - # - $(MAKE) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/$*.ini COVERAGE_TEST_DATABASE=$* COVERAGE_TEST_PACKAGES=forgejo.org/tests/integration coverage-run +.PHONY: unit-test-coverage +unit-test-coverage: + @echo "Running unit-test-coverage $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." + @$(GOTEST) $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1 .PHONY: tidy tidy: @@ -672,7 +638,6 @@ generate-ini-pgsql: -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ -e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \ -e 's|{{TEST_STORAGE_TYPE}}|$(or $(TEST_STORAGE_TYPE),minio)|g' \ - -e 's|{{TEST_S3_HOST}}|$(or $(TEST_S3_HOST),minio:9000)|g' \ tests/pgsql.ini.tmpl > tests/pgsql.ini .PHONY: test-pgsql @@ -719,7 +684,7 @@ test-e2e-mysql\#%: playwright e2e.mysql.test generate-ini-mysql GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GOTESTCOMPILEDRUNPREFIX) ./e2e.mysql.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run TestE2e/$* .PHONY: test-e2e-pgsql -GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.initest-e2e-pgsql: playwright e2e.pgsql.test generate-ini-pgsql +test-e2e-pgsql: playwright e2e.pgsql.test generate-ini-pgsql GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GOTESTCOMPILEDRUNPREFIX) ./e2e.pgsql.test $(GOTESTCOMPILEDRUNSUFFIX) -test.run TestE2e .PHONY: test-e2e-pgsql\#% @@ -742,6 +707,14 @@ bench-mysql: integrations.mysql.test generate-ini-mysql bench-pgsql: integrations.pgsql.test generate-ini-pgsql GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench . +.PHONY: integration-test-coverage +integration-test-coverage: integrations.cover.test generate-ini-mysql + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out + +.PHONY: integration-test-coverage-sqlite +integration-test-coverage-sqlite: integrations.cover.sqlite.test generate-ini-sqlite + GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.cover.sqlite.test -test.coverprofile=integration.coverage.out + integrations.mysql.test: git-check $(GO_SOURCES) $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration -o integrations.mysql.test @@ -751,6 +724,12 @@ integrations.pgsql.test: git-check $(GO_SOURCES) integrations.sqlite.test: git-check $(GO_SOURCES) $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration -o integrations.sqlite.test -tags '$(TEST_TAGS)' +integrations.cover.test: git-check $(GO_SOURCES) + $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.test + +integrations.cover.sqlite.test: git-check $(GO_SOURCES) + $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.sqlite.test -tags '$(TEST_TAGS)' + .PHONY: migrations.mysql.test migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql $(GOTEST) $(GOTESTFLAGS) -c forgejo.org/tests/integration/migration-test -o migrations.mysql.test @@ -767,7 +746,7 @@ migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTESTCOMPILEDRUNPREFIX) ./migrations.sqlite.test $(GOTESTCOMPILEDRUNSUFFIX) .PHONY: migrations.individual.mysql.test -migrations.individual.mysql.test: $(GO_SOURCES) | compute-migration-packages +migrations.individual.mysql.test: $(GO_SOURCES) for pkg in $(MIGRATION_PACKAGES); do \ GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg || exit 1; \ done @@ -777,7 +756,7 @@ migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' forgejo.org/models/migrations/$* .PHONY: migrations.individual.pgsql.test -migrations.individual.pgsql.test: $(GO_SOURCES) | compute-migration-packages +migrations.individual.pgsql.test: $(GO_SOURCES) for pkg in $(MIGRATION_PACKAGES); do \ GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg || exit 1;\ done @@ -787,7 +766,7 @@ migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' forgejo.org/models/migrations/$* .PHONY: migrations.individual.sqlite.test -migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite | compute-migration-packages +migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite for pkg in $(MIGRATION_PACKAGES); do \ GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GOTEST) $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg || exit 1; \ done @@ -961,7 +940,6 @@ fomantic: cd $(FOMANTIC_WORK_DIR) && npm install --no-save cp -f $(FOMANTIC_WORK_DIR)/theme.config.less $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/theme.config cp -rf $(FOMANTIC_WORK_DIR)/_site $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/ - rm -rf $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/themes/default/modules/dropdown.overrides $(SED_INPLACE) -e 's/ overrideBrowserslist\r/ overrideBrowserslist: ["defaults"]\r/g' $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/tasks/config/tasks.js cd $(FOMANTIC_WORK_DIR) && npx gulp -f node_modules/fomantic-ui/gulpfile.js build # fomantic uses "touchstart" as click event for some browsers, it's not ideal, so we force fomantic to always use "click" as click event diff --git a/README.md b/README.md index e6f1b6c3d1..f95aebadeb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Hi there! Tired of big platforms playing monopoly? Providing Git hosting for your project, friends, company or community? **Forgejo** (/for'd͡ส’e.jo/ inspired by forฤejo โ€“ the Esperanto word for *forge*) has you covered with its intuitive interface, -light and easy hosting and a lot of built-in functionality. +light and easy hosting and a lot of builtin functionality. Forgejo was [created in 2022](https://forgejo.org/2022-12-15-hello-forgejo/) because we think that the project should be owned by an independent community. diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index c688045d1c..32f7b8c264 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -4,7 +4,7 @@ A minor or major Forgejo release is published every [three months](https://forge A [patch or minor release](https://semver.org/spec/v2.0.0.html) (e.g. upgrading from v7.0.0 to v7.0.1 or v7.1.0) does not require manual intervention. But [major releases](https://semver.org/spec/v2.0.0.html#spec-item-8) where the first version number changes (e.g. upgrading from v1.21 to v7.0) contain breaking changes and the release notes explain how to deal with them. -The release notes of each release [are available in the release-notes-published directory of this repository](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/release-notes-published), starting with [Forgejo 7.0.7](release-notes-published/7.0.7.md) and [Forgejo 8.0.1](release-notes-published/8.0.1.md). +The release notes of each release [are available in the release-notes-published directory of this repository](release-notes-published), starting with [Forgejo 7.0.7](release-notes-published/7.0.7.md) and [Forgejo 8.0.1](release-notes-published/8.0.1.md). ## 9.0.2 diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 494671f320..fb6c201a5e 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -34,141 +34,6 @@ "path": "code.forgejo.org/forgejo/reply/LICENSE", "licenseText": "MIT License\n\nCopyright (c) The Forgejo Authors\nCopyright (c) Discourse\nCopyright (c) Claudemiro\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act", - "path": "code.forgejo.org/forgejo/runner/v11/act/LICENSE", - "licenseText": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. \u003chttps://fsf.org/\u003e\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n Preamble\n\n The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works. By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users. We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors. You can apply it to\nyour programs, too.\n\n When we speak of free software, we are referring to freedom, not\nprice. Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights. Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received. You must make sure that they, too, receive\nor can get the source code. And you must show them these terms so they\nknow their rights.\n\n Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software. For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so. This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software. The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable. Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts. If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary. To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n The precise terms and conditions for copying, distribution and\nmodification follow.\n\n TERMS AND CONDITIONS\n\n 0. Definitions.\n\n \"This License\" refers to version 3 of the GNU General Public License.\n\n \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n \"The Program\" refers to any copyrightable work licensed under this\nLicense. Each licensee is addressed as \"you\". \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy. The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy. Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies. Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License. If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n 1. Source Code.\n\n The \"source code\" for a work means the preferred form of the work\nfor making modifications to it. \"Object code\" means any non-source\nform of a work.\n\n A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form. A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities. However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work. For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n The Corresponding Source for a work in source code form is that\nsame work.\n\n 2. Basic Permissions.\n\n All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met. This License explicitly affirms your unlimited\npermission to run the unmodified Program. The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work. This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force. You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright. Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n Conveying under any other circumstances is permitted solely under\nthe conditions stated below. Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n 4. Conveying Verbatim Copies.\n\n You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n 5. Conveying Modified Source Versions.\n\n You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n a) The work must carry prominent notices stating that you modified\n it, and giving a relevant date.\n\n b) The work must carry prominent notices stating that it is\n released under this License and any conditions added under section\n 7. This requirement modifies the requirement in section 4 to\n \"keep intact all notices\".\n\n c) You must license the entire work, as a whole, under this\n License to anyone who comes into possession of a copy. This\n License will therefore apply, along with any applicable section 7\n additional terms, to the whole of the work, and all its parts,\n regardless of how they are packaged. This License gives no\n permission to license the work in any other way, but it does not\n invalidate such permission if you have separately received it.\n\n d) If the work has interactive user interfaces, each must display\n Appropriate Legal Notices; however, if the Program has interactive\n interfaces that do not display Appropriate Legal Notices, your\n work need not make them do so.\n\n A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit. Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n 6. Conveying Non-Source Forms.\n\n You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n a) Convey the object code in, or embodied in, a physical product\n (including a physical distribution medium), accompanied by the\n Corresponding Source fixed on a durable physical medium\n customarily used for software interchange.\n\n b) Convey the object code in, or embodied in, a physical product\n (including a physical distribution medium), accompanied by a\n written offer, valid for at least three years and valid for as\n long as you offer spare parts or customer support for that product\n model, to give anyone who possesses the object code either (1) a\n copy of the Corresponding Source for all the software in the\n product that is covered by this License, on a durable physical\n medium customarily used for software interchange, for a price no\n more than your reasonable cost of physically performing this\n conveying of source, or (2) access to copy the\n Corresponding Source from a network server at no charge.\n\n c) Convey individual copies of the object code with a copy of the\n written offer to provide the Corresponding Source. This\n alternative is allowed only occasionally and noncommercially, and\n only if you received the object code with such an offer, in accord\n with subsection 6b.\n\n d) Convey the object code by offering access from a designated\n place (gratis or for a charge), and offer equivalent access to the\n Corresponding Source in the same way through the same place at no\n further charge. You need not require recipients to copy the\n Corresponding Source along with the object code. If the place to\n copy the object code is a network server, the Corresponding Source\n may be on a different server (operated by you or a third party)\n that supports equivalent copying facilities, provided you maintain\n clear directions next to the object code saying where to find the\n Corresponding Source. Regardless of what server hosts the\n Corresponding Source, you remain obligated to ensure that it is\n available for as long as needed to satisfy these requirements.\n\n e) Convey the object code using peer-to-peer transmission, provided\n you inform other peers where the object code and Corresponding\n Source of the work are being offered to the general public at no\n charge under subsection 6d.\n\n A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling. In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage. For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product. A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source. The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information. But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed. Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n 7. Additional Terms.\n\n \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law. If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit. (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.) You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n a) Disclaiming warranty or limiting liability differently from the\n terms of sections 15 and 16 of this License; or\n\n b) Requiring preservation of specified reasonable legal notices or\n author attributions in that material or in the Appropriate Legal\n Notices displayed by works containing it; or\n\n c) Prohibiting misrepresentation of the origin of that material, or\n requiring that modified versions of such material be marked in\n reasonable ways as different from the original version; or\n\n d) Limiting the use for publicity purposes of names of licensors or\n authors of the material; or\n\n e) Declining to grant rights under trademark law for use of some\n trade names, trademarks, or service marks; or\n\n f) Requiring indemnification of licensors and authors of that\n material by anyone who conveys the material (or modified versions of\n it) with contractual assumptions of liability to the recipient, for\n any liability that these contractual assumptions directly impose on\n those licensors and authors.\n\n All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10. If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term. If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n 8. Termination.\n\n You may not propagate or modify a covered work except as expressly\nprovided under this License. Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License. If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n 9. Acceptance Not Required for Having Copies.\n\n You are not required to accept this License in order to receive or\nrun a copy of the Program. Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance. However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work. These actions infringe copyright if you do\nnot accept this License. Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n 10. Automatic Licensing of Downstream Recipients.\n\n Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License. You are not responsible\nfor enforcing compliance by third parties with this License.\n\n An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations. If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License. For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n 11. Patents.\n\n A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based. The\nwork thus licensed is called the contributor's \"contributor version\".\n\n A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version. For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement). To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients. \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License. You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n 12. No Surrender of Others' Freedom.\n\n If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License. If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all. For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n 13. Use with the GNU Affero General Public License.\n\n Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work. The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n 14. Revised Versions of this License.\n\n The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time. Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n Each version is given a distinguishing version number. If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation. If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n Later license versions may give you additional or different\npermissions. However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n 15. Disclaimer of Warranty.\n\n THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n 16. Limitation of Liability.\n\n IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n 17. Interpretation of Sections 15 and 16.\n\n If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n END OF TERMS AND CONDITIONS\n\n How to Apply These Terms to Your New Programs\n\n If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n To do so, attach the following notices to the program. It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n \u003cone line to give the program's name and a brief idea of what it does.\u003e\n Copyright (C) \u003cyear\u003e \u003cname of author\u003e\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n \u003cprogram\u003e Copyright (C) \u003cyear\u003e \u003cname of author\u003e\n This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n This is free software, and you are welcome to redistribute it\n under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License. Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n\u003chttps://www.gnu.org/licenses/\u003e.\n\n The GNU General Public License does not permit incorporating your program\ninto proprietary programs. If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library. If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License. But first, please read\n\u003chttps://www.gnu.org/licenses/why-not-lgpl.html\u003e.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/lookpath", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/lookpath/LICENSE", - "licenseText": "Copyright (c) 2009 The Go Authors. 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\t* Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\t* 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\t* 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": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@actions/core", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@actions/core/LICENSE.md", - "licenseText": "The MIT License (MIT)\n\nCopyright 2019 GitHub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@actions/github/node_modules/@actions/http-client", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@actions/github/node_modules/@actions/http-client/LICENSE", - "licenseText": "Actions Http Client for Node.js\n\nCopyright (c) GitHub, Inc.\n\nAll rights reserved.\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and\nassociated documentation files (the \"Software\"), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\nNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@actions/http-client", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@actions/http-client/LICENSE", - "licenseText": "Actions Http Client for Node.js\n\nCopyright (c) GitHub, Inc.\n\nAll rights reserved.\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and\nassociated documentation files (the \"Software\"), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\nNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/auth-token", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/auth-token/LICENSE", - "licenseText": "The MIT License\n\nCopyright (c) 2019 Octokit contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/core", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/core/LICENSE", - "licenseText": "The MIT License\n\nCopyright (c) 2019 Octokit contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/endpoint", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/endpoint/LICENSE", - "licenseText": "The MIT License\n\nCopyright (c) 2018 Octokit contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/graphql", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/graphql/LICENSE", - "licenseText": "The MIT License\n\nCopyright (c) 2018 Octokit contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/openapi-types", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/openapi-types/LICENSE", - "licenseText": "Copyright 2020 Gregor Martynus\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/plugin-paginate-rest", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/plugin-paginate-rest/LICENSE", - "licenseText": "MIT License Copyright (c) 2019 Octokit contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/plugin-rest-endpoint-methods", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/plugin-rest-endpoint-methods/LICENSE", - "licenseText": "MIT License Copyright (c) 2019 Octokit contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/request-error", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/request-error/LICENSE", - "licenseText": "The MIT License\n\nCopyright (c) 2019 Octokit contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/request", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/request/LICENSE", - "licenseText": "The MIT License\n\nCopyright (c) 2018 Octokit contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/types", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@octokit/types/LICENSE", - "licenseText": "MIT License Copyright (c) 2019 Octokit contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@vercel/ncc", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/@vercel/ncc/LICENSE", - "licenseText": "Copyright 2018 ZEIT, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/before-after-hook", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/before-after-hook/LICENSE", - "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2018 Gregor Martynus and other contributors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/deprecation", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/deprecation/LICENSE", - "licenseText": "The ISC License\n\nCopyright (c) Gregor Martynus and contributors\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\nIN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/is-plain-object", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/is-plain-object/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2014-2017, Jon Schlinkert.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/node-fetch", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/node-fetch/LICENSE.md", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2016 David Frank\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/once", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/once/LICENSE", - "licenseText": "The ISC License\n\nCopyright (c) Isaac Z. Schlueter and Contributors\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\nIN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/tunnel", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/tunnel/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2012 Koichi Kobayashi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/universal-user-agent", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/universal-user-agent/LICENSE.md", - "licenseText": "# [ISC License](https://spdx.org/licenses/ISC)\n\nCopyright (c) 2018, Gregor Martynus (https://github.com/gr2m)\n\nPermission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/uuid", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/uuid/LICENSE.md", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2010-2020 Robert Kieffer and other contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/webidl-conversions", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/webidl-conversions/LICENSE.md", - "licenseText": "# The BSD 2-Clause License\n\nCopyright (c) 2014, Domenic Denicola\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/whatwg-url", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/whatwg-url/LICENSE.txt", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015โ€“2016 Sebastian Mayr\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/wrappy", - "path": "code.forgejo.org/forgejo/runner/v11/act/act/runner/testdata/actions/node20/node_modules/wrappy/LICENSE", - "licenseText": "The ISC License\n\nCopyright (c) Isaac Z. Schlueter and Contributors\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\nIN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n" - }, { "name": "code.forgejo.org/go-chi/binding", "path": "code.forgejo.org/go-chi/binding/LICENSE", @@ -249,11 +114,6 @@ "path": "github.com/RoaringBitmap/roaring/v2/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2016 by the authors\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n================================================================================\n\nPortions of runcontainer.go are from the Go standard library, which is licensed\nunder:\n\nCopyright (c) 2009 The Go Authors. 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\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following disclaimer\n in the documentation and/or other materials provided with the\n distribution.\n * Neither the name of Google Inc. 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\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/STARRY-S/zip", - "path": "github.com/STARRY-S/zip/LICENSE", - "licenseText": "BSD 3-Clause License\n\nCopyright (c) 2023, Starry\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. 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\n3. 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/SaveTheRbtz/zstd-seekable-format-go/pkg", "path": "github.com/SaveTheRbtz/zstd-seekable-format-go/pkg/LICENSE", @@ -384,26 +244,6 @@ "path": "github.com/blevesearch/zapx/v16/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License." }, - { - "name": "github.com/bmatcuk/doublestar/v4", - "path": "github.com/bmatcuk/doublestar/v4/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2014 Bob Matcuk\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n" - }, - { - "name": "github.com/bodgit/plumbing", - "path": "github.com/bodgit/plumbing/LICENSE", - "licenseText": "BSD 3-Clause License\n\nCopyright (c) 2019, Matt Dainty\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\n" - }, - { - "name": "github.com/bodgit/sevenzip", - "path": "github.com/bodgit/sevenzip/LICENSE", - "licenseText": "BSD 3-Clause License\n\nCopyright (c) 2020, Matt Dainty\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/bodgit/windows", - "path": "github.com/bodgit/windows/LICENSE", - "licenseText": "BSD 3-Clause License\n\nCopyright (c) 2020, Matt Dainty\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\n" - }, { "name": "github.com/boombuler/barcode", "path": "github.com/boombuler/barcode/LICENSE", @@ -724,21 +564,11 @@ "path": "github.com/gorilla/sessions/LICENSE", "licenseText": "Copyright (c) 2024 The Gorilla Authors. 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\t * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\t * 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\t * 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/hashicorp/errwrap", - "path": "github.com/hashicorp/errwrap/LICENSE", - "licenseText": "Mozilla Public License, version 2.0\n\n1. Definitions\n\n1.1. โ€œContributorโ€\n\n means each individual or legal entity that creates, contributes to the\n creation of, or owns Covered Software.\n\n1.2. โ€œContributor Versionโ€\n\n means the combination of the Contributions of others (if any) used by a\n Contributor and that particular Contributorโ€™s Contribution.\n\n1.3. โ€œContributionโ€\n\n means Covered Software of a particular Contributor.\n\n1.4. โ€œCovered Softwareโ€\n\n means Source Code Form to which the initial Contributor has attached the\n notice in Exhibit A, the Executable Form of such Source Code Form, and\n Modifications of such Source Code Form, in each case including portions\n thereof.\n\n1.5. โ€œIncompatible With Secondary Licensesโ€\n means\n\n a. that the initial Contributor has attached the notice described in\n Exhibit B to the Covered Software; or\n\n b. that the Covered Software was made available under the terms of version\n 1.1 or earlier of the License, but not also under the terms of a\n Secondary License.\n\n1.6. โ€œExecutable Formโ€\n\n means any form of the work other than Source Code Form.\n\n1.7. โ€œLarger Workโ€\n\n means a work that combines Covered Software with other material, in a separate\n file or files, that is not Covered Software.\n\n1.8. โ€œLicenseโ€\n\n means this document.\n\n1.9. โ€œLicensableโ€\n\n means having the right to grant, to the maximum extent possible, whether at the\n time of the initial grant or subsequently, any and all of the rights conveyed by\n this License.\n\n1.10. โ€œModificationsโ€\n\n means any of the following:\n\n a. any file in Source Code Form that results from an addition to, deletion\n from, or modification of the contents of Covered Software; or\n\n b. any new file in Source Code Form that contains any Covered Software.\n\n1.11. โ€œPatent Claimsโ€ of a Contributor\n\n means any patent claim(s), including without limitation, method, process,\n and apparatus claims, in any patent Licensable by such Contributor that\n would be infringed, but for the grant of the License, by the making,\n using, selling, offering for sale, having made, import, or transfer of\n either its Contributions or its Contributor Version.\n\n1.12. โ€œSecondary Licenseโ€\n\n means either the GNU General Public License, Version 2.0, the GNU Lesser\n General Public License, Version 2.1, the GNU Affero General Public\n License, Version 3.0, or any later versions of those licenses.\n\n1.13. โ€œSource Code Formโ€\n\n means the form of the work preferred for making modifications.\n\n1.14. โ€œYouโ€ (or โ€œYourโ€)\n\n means an individual or a legal entity exercising rights under this\n License. For legal entities, โ€œYouโ€ includes any entity that controls, is\n controlled by, or is under common control with You. For purposes of this\n definition, โ€œcontrolโ€ means (a) the power, direct or indirect, to cause\n the direction or management of such entity, whether by contract or\n otherwise, or (b) ownership of more than fifty percent (50%) of the\n outstanding shares or beneficial ownership of such entity.\n\n\n2. License Grants and Conditions\n\n2.1. Grants\n\n Each Contributor hereby grants You a world-wide, royalty-free,\n non-exclusive license:\n\n a. under intellectual property rights (other than patent or trademark)\n Licensable by such Contributor to use, reproduce, make available,\n modify, display, perform, distribute, and otherwise exploit its\n Contributions, either on an unmodified basis, with Modifications, or as\n part of a Larger Work; and\n\n b. under Patent Claims of such Contributor to make, use, sell, offer for\n sale, have made, import, and otherwise transfer either its Contributions\n or its Contributor Version.\n\n2.2. Effective Date\n\n The licenses granted in Section 2.1 with respect to any Contribution become\n effective for each Contribution on the date the Contributor first distributes\n such Contribution.\n\n2.3. Limitations on Grant Scope\n\n The licenses granted in this Section 2 are the only rights granted under this\n License. No additional rights or licenses will be implied from the distribution\n or licensing of Covered Software under this License. Notwithstanding Section\n 2.1(b) above, no patent license is granted by a Contributor:\n\n a. for any code that a Contributor has removed from Covered Software; or\n\n b. for infringements caused by: (i) Your and any other third partyโ€™s\n modifications of Covered Software, or (ii) the combination of its\n Contributions with other software (except as part of its Contributor\n Version); or\n\n c. under Patent Claims infringed by Covered Software in the absence of its\n Contributions.\n\n This License does not grant any rights in the trademarks, service marks, or\n logos of any Contributor (except as may be necessary to comply with the\n notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\n No Contributor makes additional grants as a result of Your choice to\n distribute the Covered Software under a subsequent version of this License\n (see Section 10.2) or under the terms of a Secondary License (if permitted\n under the terms of Section 3.3).\n\n2.5. Representation\n\n Each Contributor represents that the Contributor believes its Contributions\n are its original creation(s) or it has sufficient rights to grant the\n rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\n This License is not intended to limit any rights You have under applicable\n copyright doctrines of fair use, fair dealing, or other equivalents.\n\n2.7. Conditions\n\n Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in\n Section 2.1.\n\n\n3. Responsibilities\n\n3.1. Distribution of Source Form\n\n All distribution of Covered Software in Source Code Form, including any\n Modifications that You create or to which You contribute, must be under the\n terms of this License. You must inform recipients that the Source Code Form\n of the Covered Software is governed by the terms of this License, and how\n they can obtain a copy of this License. You may not attempt to alter or\n restrict the recipientsโ€™ rights in the Source Code Form.\n\n3.2. Distribution of Executable Form\n\n If You distribute Covered Software in Executable Form then:\n\n a. such Covered Software must also be made available in Source Code Form,\n as described in Section 3.1, and You must inform recipients of the\n Executable Form how they can obtain a copy of such Source Code Form by\n reasonable means in a timely manner, at a charge no more than the cost\n of distribution to the recipient; and\n\n b. You may distribute such Executable Form under the terms of this License,\n or sublicense it under different terms, provided that the license for\n the Executable Form does not attempt to limit or alter the recipientsโ€™\n rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\n You may create and distribute a Larger Work under terms of Your choice,\n provided that You also comply with the requirements of this License for the\n Covered Software. If the Larger Work is a combination of Covered Software\n with a work governed by one or more Secondary Licenses, and the Covered\n Software is not Incompatible With Secondary Licenses, this License permits\n You to additionally distribute such Covered Software under the terms of\n such Secondary License(s), so that the recipient of the Larger Work may, at\n their option, further distribute the Covered Software under the terms of\n either this License or such Secondary License(s).\n\n3.4. Notices\n\n You may not remove or alter the substance of any license notices (including\n copyright notices, patent notices, disclaimers of warranty, or limitations\n of liability) contained within the Source Code Form of the Covered\n Software, except that You may alter any license notices to the extent\n required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\n You may choose to offer, and to charge a fee for, warranty, support,\n indemnity or liability obligations to one or more recipients of Covered\n Software. However, You may do so only on Your own behalf, and not on behalf\n of any Contributor. You must make it absolutely clear that any such\n warranty, support, indemnity, or liability obligation is offered by You\n alone, and You hereby agree to indemnify every Contributor for any\n liability incurred by such Contributor as a result of warranty, support,\n indemnity or liability terms You offer. You may include additional\n disclaimers of warranty and limitations of liability specific to any\n jurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n\n If it is impossible for You to comply with any of the terms of this License\n with respect to some or all of the Covered Software due to statute, judicial\n order, or regulation then You must: (a) comply with the terms of this License\n to the maximum extent possible; and (b) describe the limitations and the code\n they affect. Such description must be placed in a text file included with all\n distributions of the Covered Software under this License. Except to the\n extent prohibited by statute or regulation, such description must be\n sufficiently detailed for a recipient of ordinary skill to be able to\n understand it.\n\n5. Termination\n\n5.1. The rights granted under this License will terminate automatically if You\n fail to comply with any of its terms. However, if You become compliant,\n then the rights granted under this License from a particular Contributor\n are reinstated (a) provisionally, unless and until such Contributor\n explicitly and finally terminates Your grants, and (b) on an ongoing basis,\n if such Contributor fails to notify You of the non-compliance by some\n reasonable means prior to 60 days after You have come back into compliance.\n Moreover, Your grants from a particular Contributor are reinstated on an\n ongoing basis if such Contributor notifies You of the non-compliance by\n some reasonable means, this is the first time You have received notice of\n non-compliance with this License from such Contributor, and You become\n compliant prior to 30 days after Your receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\n infringement claim (excluding declaratory judgment actions, counter-claims,\n and cross-claims) alleging that a Contributor Version directly or\n indirectly infringes any patent, then the rights granted to You by any and\n all Contributors for the Covered Software under Section 2.1 of this License\n shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user\n license agreements (excluding distributors and resellers) which have been\n validly granted by You or Your distributors under this License prior to\n termination shall survive termination.\n\n6. Disclaimer of Warranty\n\n Covered Software is provided under this License on an โ€œas isโ€ basis, without\n warranty of any kind, either expressed, implied, or statutory, including,\n without limitation, warranties that the Covered Software is free of defects,\n merchantable, fit for a particular purpose or non-infringing. The entire\n risk as to the quality and performance of the Covered Software is with You.\n Should any Covered Software prove defective in any respect, You (not any\n Contributor) assume the cost of any necessary servicing, repair, or\n correction. This disclaimer of warranty constitutes an essential part of this\n License. No use of any Covered Software is authorized under this License\n except under this disclaimer.\n\n7. Limitation of Liability\n\n Under no circumstances and under no legal theory, whether tort (including\n negligence), contract, or otherwise, shall any Contributor, or anyone who\n distributes Covered Software as permitted above, be liable to You for any\n direct, indirect, special, incidental, or consequential damages of any\n character including, without limitation, damages for lost profits, loss of\n goodwill, work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses, even if such party shall have been\n informed of the possibility of such damages. This limitation of liability\n shall not apply to liability for death or personal injury resulting from such\n partyโ€™s negligence to the extent applicable law prohibits such limitation.\n Some jurisdictions do not allow the exclusion or limitation of incidental or\n consequential damages, so this exclusion and limitation may not apply to You.\n\n8. Litigation\n\n Any litigation relating to this License may be brought only in the courts of\n a jurisdiction where the defendant maintains its principal place of business\n and such litigation shall be governed by laws of that jurisdiction, without\n reference to its conflict-of-law provisions. Nothing in this Section shall\n prevent a partyโ€™s ability to bring cross-claims or counter-claims.\n\n9. Miscellaneous\n\n This License represents the complete agreement concerning the subject matter\n hereof. If any provision of this License is held to be unenforceable, such\n provision shall be reformed only to the extent necessary to make it\n enforceable. Any law or regulation which provides that the language of a\n contract shall be construed against the drafter shall not be used to construe\n this License against a Contributor.\n\n\n10. Versions of the License\n\n10.1. New Versions\n\n Mozilla Foundation is the license steward. Except as provided in Section\n 10.3, no one other than the license steward has the right to modify or\n publish new versions of this License. Each version will be given a\n distinguishing version number.\n\n10.2. Effect of New Versions\n\n You may distribute the Covered Software under the terms of the version of\n the License under which You originally received the Covered Software, or\n under the terms of any subsequent version published by the license\n steward.\n\n10.3. Modified Versions\n\n If you create software not governed by this License, and you want to\n create a new license for such software, you may create and use a modified\n version of this License if you rename the license and remove any\n references to the name of the license steward (except to note that such\n modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses\n If You choose to distribute Source Code Form that is Incompatible With\n Secondary Licenses under the terms of this version of the License, the\n notice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n\n This Source Code Form is subject to the\n terms of the Mozilla Public License, v.\n 2.0. If a copy of the MPL was not\n distributed with this file, You can\n obtain one at\n http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular file, then\nYou may include the notice in a location (such as a LICENSE file in a relevant\ndirectory) where a recipient would be likely to look for such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - โ€œIncompatible With Secondary Licensesโ€ Notice\n\n This Source Code Form is โ€œIncompatible\n With Secondary Licensesโ€, as defined by\n the Mozilla Public License, v. 2.0.\n\n" - }, { "name": "github.com/hashicorp/go-cleanhttp", "path": "github.com/hashicorp/go-cleanhttp/LICENSE", "licenseText": "Mozilla Public License, version 2.0\n\n1. Definitions\n\n1.1. \"Contributor\"\n\n means each individual or legal entity that creates, contributes to the\n creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n\n means the combination of the Contributions of others (if any) used by a\n Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n\n means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n\n means Source Code Form to which the initial Contributor has attached the\n notice in Exhibit A, the Executable Form of such Source Code Form, and\n Modifications of such Source Code Form, in each case including portions\n thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n means\n\n a. that the initial Contributor has attached the notice described in\n Exhibit B to the Covered Software; or\n\n b. that the Covered Software was made available under the terms of\n version 1.1 or earlier of the License, but not also under the terms of\n a Secondary License.\n\n1.6. \"Executable Form\"\n\n means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n\n means a work that combines Covered Software with other material, in a\n separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n\n means this document.\n\n1.9. \"Licensable\"\n\n means having the right to grant, to the maximum extent possible, whether\n at the time of the initial grant or subsequently, any and all of the\n rights conveyed by this License.\n\n1.10. \"Modifications\"\n\n means any of the following:\n\n a. any file in Source Code Form that results from an addition to,\n deletion from, or modification of the contents of Covered Software; or\n\n b. any new file in Source Code Form that contains any Covered Software.\n\n1.11. \"Patent Claims\" of a Contributor\n\n means any patent claim(s), including without limitation, method,\n process, and apparatus claims, in any patent Licensable by such\n Contributor that would be infringed, but for the grant of the License,\n by the making, using, selling, offering for sale, having made, import,\n or transfer of either its Contributions or its Contributor Version.\n\n1.12. \"Secondary License\"\n\n means either the GNU General Public License, Version 2.0, the GNU Lesser\n General Public License, Version 2.1, the GNU Affero General Public\n License, Version 3.0, or any later versions of those licenses.\n\n1.13. \"Source Code Form\"\n\n means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n\n means an individual or a legal entity exercising rights under this\n License. For legal entities, \"You\" includes any entity that controls, is\n controlled by, or is under common control with You. For purposes of this\n definition, \"control\" means (a) the power, direct or indirect, to cause\n the direction or management of such entity, whether by contract or\n otherwise, or (b) ownership of more than fifty percent (50%) of the\n outstanding shares or beneficial ownership of such entity.\n\n\n2. License Grants and Conditions\n\n2.1. Grants\n\n Each Contributor hereby grants You a world-wide, royalty-free,\n non-exclusive license:\n\n a. under intellectual property rights (other than patent or trademark)\n Licensable by such Contributor to use, reproduce, make available,\n modify, display, perform, distribute, and otherwise exploit its\n Contributions, either on an unmodified basis, with Modifications, or\n as part of a Larger Work; and\n\n b. under Patent Claims of such Contributor to make, use, sell, offer for\n sale, have made, import, and otherwise transfer either its\n Contributions or its Contributor Version.\n\n2.2. Effective Date\n\n The licenses granted in Section 2.1 with respect to any Contribution\n become effective for each Contribution on the date the Contributor first\n distributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\n The licenses granted in this Section 2 are the only rights granted under\n this License. No additional rights or licenses will be implied from the\n distribution or licensing of Covered Software under this License.\n Notwithstanding Section 2.1(b) above, no patent license is granted by a\n Contributor:\n\n a. for any code that a Contributor has removed from Covered Software; or\n\n b. for infringements caused by: (i) Your and any other third party's\n modifications of Covered Software, or (ii) the combination of its\n Contributions with other software (except as part of its Contributor\n Version); or\n\n c. under Patent Claims infringed by Covered Software in the absence of\n its Contributions.\n\n This License does not grant any rights in the trademarks, service marks,\n or logos of any Contributor (except as may be necessary to comply with\n the notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\n No Contributor makes additional grants as a result of Your choice to\n distribute the Covered Software under a subsequent version of this\n License (see Section 10.2) or under the terms of a Secondary License (if\n permitted under the terms of Section 3.3).\n\n2.5. Representation\n\n Each Contributor represents that the Contributor believes its\n Contributions are its original creation(s) or it has sufficient rights to\n grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\n This License is not intended to limit any rights You have under\n applicable copyright doctrines of fair use, fair dealing, or other\n equivalents.\n\n2.7. Conditions\n\n Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in\n Section 2.1.\n\n\n3. Responsibilities\n\n3.1. Distribution of Source Form\n\n All distribution of Covered Software in Source Code Form, including any\n Modifications that You create or to which You contribute, must be under\n the terms of this License. You must inform recipients that the Source\n Code Form of the Covered Software is governed by the terms of this\n License, and how they can obtain a copy of this License. You may not\n attempt to alter or restrict the recipients' rights in the Source Code\n Form.\n\n3.2. Distribution of Executable Form\n\n If You distribute Covered Software in Executable Form then:\n\n a. such Covered Software must also be made available in Source Code Form,\n as described in Section 3.1, and You must inform recipients of the\n Executable Form how they can obtain a copy of such Source Code Form by\n reasonable means in a timely manner, at a charge no more than the cost\n of distribution to the recipient; and\n\n b. You may distribute such Executable Form under the terms of this\n License, or sublicense it under different terms, provided that the\n license for the Executable Form does not attempt to limit or alter the\n recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\n You may create and distribute a Larger Work under terms of Your choice,\n provided that You also comply with the requirements of this License for\n the Covered Software. If the Larger Work is a combination of Covered\n Software with a work governed by one or more Secondary Licenses, and the\n Covered Software is not Incompatible With Secondary Licenses, this\n License permits You to additionally distribute such Covered Software\n under the terms of such Secondary License(s), so that the recipient of\n the Larger Work may, at their option, further distribute the Covered\n Software under the terms of either this License or such Secondary\n License(s).\n\n3.4. Notices\n\n You may not remove or alter the substance of any license notices\n (including copyright notices, patent notices, disclaimers of warranty, or\n limitations of liability) contained within the Source Code Form of the\n Covered Software, except that You may alter any license notices to the\n extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\n You may choose to offer, and to charge a fee for, warranty, support,\n indemnity or liability obligations to one or more recipients of Covered\n Software. However, You may do so only on Your own behalf, and not on\n behalf of any Contributor. You must make it absolutely clear that any\n such warranty, support, indemnity, or liability obligation is offered by\n You alone, and You hereby agree to indemnify every Contributor for any\n liability incurred by such Contributor as a result of warranty, support,\n indemnity or liability terms You offer. You may include additional\n disclaimers of warranty and limitations of liability specific to any\n jurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n\n If it is impossible for You to comply with any of the terms of this License\n with respect to some or all of the Covered Software due to statute,\n judicial order, or regulation then You must: (a) comply with the terms of\n this License to the maximum extent possible; and (b) describe the\n limitations and the code they affect. Such description must be placed in a\n text file included with all distributions of the Covered Software under\n this License. Except to the extent prohibited by statute or regulation,\n such description must be sufficiently detailed for a recipient of ordinary\n skill to be able to understand it.\n\n5. Termination\n\n5.1. The rights granted under this License will terminate automatically if You\n fail to comply with any of its terms. However, if You become compliant,\n then the rights granted under this License from a particular Contributor\n are reinstated (a) provisionally, unless and until such Contributor\n explicitly and finally terminates Your grants, and (b) on an ongoing\n basis, if such Contributor fails to notify You of the non-compliance by\n some reasonable means prior to 60 days after You have come back into\n compliance. Moreover, Your grants from a particular Contributor are\n reinstated on an ongoing basis if such Contributor notifies You of the\n non-compliance by some reasonable means, this is the first time You have\n received notice of non-compliance with this License from such\n Contributor, and You become compliant prior to 30 days after Your receipt\n of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\n infringement claim (excluding declaratory judgment actions,\n counter-claims, and cross-claims) alleging that a Contributor Version\n directly or indirectly infringes any patent, then the rights granted to\n You by any and all Contributors for the Covered Software under Section\n 2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user\n license agreements (excluding distributors and resellers) which have been\n validly granted by You or Your distributors under this License prior to\n termination shall survive termination.\n\n6. Disclaimer of Warranty\n\n Covered Software is provided under this License on an \"as is\" basis,\n without warranty of any kind, either expressed, implied, or statutory,\n including, without limitation, warranties that the Covered Software is free\n of defects, merchantable, fit for a particular purpose or non-infringing.\n The entire risk as to the quality and performance of the Covered Software\n is with You. Should any Covered Software prove defective in any respect,\n You (not any Contributor) assume the cost of any necessary servicing,\n repair, or correction. This disclaimer of warranty constitutes an essential\n part of this License. No use of any Covered Software is authorized under\n this License except under this disclaimer.\n\n7. Limitation of Liability\n\n Under no circumstances and under no legal theory, whether tort (including\n negligence), contract, or otherwise, shall any Contributor, or anyone who\n distributes Covered Software as permitted above, be liable to You for any\n direct, indirect, special, incidental, or consequential damages of any\n character including, without limitation, damages for lost profits, loss of\n goodwill, work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses, even if such party shall have been\n informed of the possibility of such damages. This limitation of liability\n shall not apply to liability for death or personal injury resulting from\n such party's negligence to the extent applicable law prohibits such\n limitation. Some jurisdictions do not allow the exclusion or limitation of\n incidental or consequential damages, so this exclusion and limitation may\n not apply to You.\n\n8. Litigation\n\n Any litigation relating to this License may be brought only in the courts\n of a jurisdiction where the defendant maintains its principal place of\n business and such litigation shall be governed by laws of that\n jurisdiction, without reference to its conflict-of-law provisions. Nothing\n in this Section shall prevent a party's ability to bring cross-claims or\n counter-claims.\n\n9. Miscellaneous\n\n This License represents the complete agreement concerning the subject\n matter hereof. If any provision of this License is held to be\n unenforceable, such provision shall be reformed only to the extent\n necessary to make it enforceable. Any law or regulation which provides that\n the language of a contract shall be construed against the drafter shall not\n be used to construe this License against a Contributor.\n\n\n10. Versions of the License\n\n10.1. New Versions\n\n Mozilla Foundation is the license steward. Except as provided in Section\n 10.3, no one other than the license steward has the right to modify or\n publish new versions of this License. Each version will be given a\n distinguishing version number.\n\n10.2. Effect of New Versions\n\n You may distribute the Covered Software under the terms of the version\n of the License under which You originally received the Covered Software,\n or under the terms of any subsequent version published by the license\n steward.\n\n10.3. Modified Versions\n\n If you create software not governed by this License, and you want to\n create a new license for such software, you may create and use a\n modified version of this License if you rename the license and remove\n any references to the name of the license steward (except to note that\n such modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\n Licenses If You choose to distribute Source Code Form that is\n Incompatible With Secondary Licenses under the terms of this version of\n the License, the notice described in Exhibit B of this License must be\n attached.\n\nExhibit A - Source Code Form License Notice\n\n This Source Code Form is subject to the\n terms of the Mozilla Public License, v.\n 2.0. If a copy of the MPL was not\n distributed with this file, You can\n obtain one at\n http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular file,\nthen You may include the notice in a location (such as a LICENSE file in a\nrelevant directory) where a recipient would be likely to look for such a\nnotice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n\n This Source Code Form is \"Incompatible\n With Secondary Licenses\", as defined by\n the Mozilla Public License, v. 2.0.\n\n" }, - { - "name": "github.com/hashicorp/go-multierror", - "path": "github.com/hashicorp/go-multierror/LICENSE", - "licenseText": "Mozilla Public License, version 2.0\n\n1. Definitions\n\n1.1. โ€œContributorโ€\n\n means each individual or legal entity that creates, contributes to the\n creation of, or owns Covered Software.\n\n1.2. โ€œContributor Versionโ€\n\n means the combination of the Contributions of others (if any) used by a\n Contributor and that particular Contributorโ€™s Contribution.\n\n1.3. โ€œContributionโ€\n\n means Covered Software of a particular Contributor.\n\n1.4. โ€œCovered Softwareโ€\n\n means Source Code Form to which the initial Contributor has attached the\n notice in Exhibit A, the Executable Form of such Source Code Form, and\n Modifications of such Source Code Form, in each case including portions\n thereof.\n\n1.5. โ€œIncompatible With Secondary Licensesโ€\n means\n\n a. that the initial Contributor has attached the notice described in\n Exhibit B to the Covered Software; or\n\n b. that the Covered Software was made available under the terms of version\n 1.1 or earlier of the License, but not also under the terms of a\n Secondary License.\n\n1.6. โ€œExecutable Formโ€\n\n means any form of the work other than Source Code Form.\n\n1.7. โ€œLarger Workโ€\n\n means a work that combines Covered Software with other material, in a separate\n file or files, that is not Covered Software.\n\n1.8. โ€œLicenseโ€\n\n means this document.\n\n1.9. โ€œLicensableโ€\n\n means having the right to grant, to the maximum extent possible, whether at the\n time of the initial grant or subsequently, any and all of the rights conveyed by\n this License.\n\n1.10. โ€œModificationsโ€\n\n means any of the following:\n\n a. any file in Source Code Form that results from an addition to, deletion\n from, or modification of the contents of Covered Software; or\n\n b. any new file in Source Code Form that contains any Covered Software.\n\n1.11. โ€œPatent Claimsโ€ of a Contributor\n\n means any patent claim(s), including without limitation, method, process,\n and apparatus claims, in any patent Licensable by such Contributor that\n would be infringed, but for the grant of the License, by the making,\n using, selling, offering for sale, having made, import, or transfer of\n either its Contributions or its Contributor Version.\n\n1.12. โ€œSecondary Licenseโ€\n\n means either the GNU General Public License, Version 2.0, the GNU Lesser\n General Public License, Version 2.1, the GNU Affero General Public\n License, Version 3.0, or any later versions of those licenses.\n\n1.13. โ€œSource Code Formโ€\n\n means the form of the work preferred for making modifications.\n\n1.14. โ€œYouโ€ (or โ€œYourโ€)\n\n means an individual or a legal entity exercising rights under this\n License. For legal entities, โ€œYouโ€ includes any entity that controls, is\n controlled by, or is under common control with You. For purposes of this\n definition, โ€œcontrolโ€ means (a) the power, direct or indirect, to cause\n the direction or management of such entity, whether by contract or\n otherwise, or (b) ownership of more than fifty percent (50%) of the\n outstanding shares or beneficial ownership of such entity.\n\n\n2. License Grants and Conditions\n\n2.1. Grants\n\n Each Contributor hereby grants You a world-wide, royalty-free,\n non-exclusive license:\n\n a. under intellectual property rights (other than patent or trademark)\n Licensable by such Contributor to use, reproduce, make available,\n modify, display, perform, distribute, and otherwise exploit its\n Contributions, either on an unmodified basis, with Modifications, or as\n part of a Larger Work; and\n\n b. under Patent Claims of such Contributor to make, use, sell, offer for\n sale, have made, import, and otherwise transfer either its Contributions\n or its Contributor Version.\n\n2.2. Effective Date\n\n The licenses granted in Section 2.1 with respect to any Contribution become\n effective for each Contribution on the date the Contributor first distributes\n such Contribution.\n\n2.3. Limitations on Grant Scope\n\n The licenses granted in this Section 2 are the only rights granted under this\n License. No additional rights or licenses will be implied from the distribution\n or licensing of Covered Software under this License. Notwithstanding Section\n 2.1(b) above, no patent license is granted by a Contributor:\n\n a. for any code that a Contributor has removed from Covered Software; or\n\n b. for infringements caused by: (i) Your and any other third partyโ€™s\n modifications of Covered Software, or (ii) the combination of its\n Contributions with other software (except as part of its Contributor\n Version); or\n\n c. under Patent Claims infringed by Covered Software in the absence of its\n Contributions.\n\n This License does not grant any rights in the trademarks, service marks, or\n logos of any Contributor (except as may be necessary to comply with the\n notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\n No Contributor makes additional grants as a result of Your choice to\n distribute the Covered Software under a subsequent version of this License\n (see Section 10.2) or under the terms of a Secondary License (if permitted\n under the terms of Section 3.3).\n\n2.5. Representation\n\n Each Contributor represents that the Contributor believes its Contributions\n are its original creation(s) or it has sufficient rights to grant the\n rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\n This License is not intended to limit any rights You have under applicable\n copyright doctrines of fair use, fair dealing, or other equivalents.\n\n2.7. Conditions\n\n Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in\n Section 2.1.\n\n\n3. Responsibilities\n\n3.1. Distribution of Source Form\n\n All distribution of Covered Software in Source Code Form, including any\n Modifications that You create or to which You contribute, must be under the\n terms of this License. You must inform recipients that the Source Code Form\n of the Covered Software is governed by the terms of this License, and how\n they can obtain a copy of this License. You may not attempt to alter or\n restrict the recipientsโ€™ rights in the Source Code Form.\n\n3.2. Distribution of Executable Form\n\n If You distribute Covered Software in Executable Form then:\n\n a. such Covered Software must also be made available in Source Code Form,\n as described in Section 3.1, and You must inform recipients of the\n Executable Form how they can obtain a copy of such Source Code Form by\n reasonable means in a timely manner, at a charge no more than the cost\n of distribution to the recipient; and\n\n b. You may distribute such Executable Form under the terms of this License,\n or sublicense it under different terms, provided that the license for\n the Executable Form does not attempt to limit or alter the recipientsโ€™\n rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\n You may create and distribute a Larger Work under terms of Your choice,\n provided that You also comply with the requirements of this License for the\n Covered Software. If the Larger Work is a combination of Covered Software\n with a work governed by one or more Secondary Licenses, and the Covered\n Software is not Incompatible With Secondary Licenses, this License permits\n You to additionally distribute such Covered Software under the terms of\n such Secondary License(s), so that the recipient of the Larger Work may, at\n their option, further distribute the Covered Software under the terms of\n either this License or such Secondary License(s).\n\n3.4. Notices\n\n You may not remove or alter the substance of any license notices (including\n copyright notices, patent notices, disclaimers of warranty, or limitations\n of liability) contained within the Source Code Form of the Covered\n Software, except that You may alter any license notices to the extent\n required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\n You may choose to offer, and to charge a fee for, warranty, support,\n indemnity or liability obligations to one or more recipients of Covered\n Software. However, You may do so only on Your own behalf, and not on behalf\n of any Contributor. You must make it absolutely clear that any such\n warranty, support, indemnity, or liability obligation is offered by You\n alone, and You hereby agree to indemnify every Contributor for any\n liability incurred by such Contributor as a result of warranty, support,\n indemnity or liability terms You offer. You may include additional\n disclaimers of warranty and limitations of liability specific to any\n jurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n\n If it is impossible for You to comply with any of the terms of this License\n with respect to some or all of the Covered Software due to statute, judicial\n order, or regulation then You must: (a) comply with the terms of this License\n to the maximum extent possible; and (b) describe the limitations and the code\n they affect. Such description must be placed in a text file included with all\n distributions of the Covered Software under this License. Except to the\n extent prohibited by statute or regulation, such description must be\n sufficiently detailed for a recipient of ordinary skill to be able to\n understand it.\n\n5. Termination\n\n5.1. The rights granted under this License will terminate automatically if You\n fail to comply with any of its terms. However, if You become compliant,\n then the rights granted under this License from a particular Contributor\n are reinstated (a) provisionally, unless and until such Contributor\n explicitly and finally terminates Your grants, and (b) on an ongoing basis,\n if such Contributor fails to notify You of the non-compliance by some\n reasonable means prior to 60 days after You have come back into compliance.\n Moreover, Your grants from a particular Contributor are reinstated on an\n ongoing basis if such Contributor notifies You of the non-compliance by\n some reasonable means, this is the first time You have received notice of\n non-compliance with this License from such Contributor, and You become\n compliant prior to 30 days after Your receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\n infringement claim (excluding declaratory judgment actions, counter-claims,\n and cross-claims) alleging that a Contributor Version directly or\n indirectly infringes any patent, then the rights granted to You by any and\n all Contributors for the Covered Software under Section 2.1 of this License\n shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user\n license agreements (excluding distributors and resellers) which have been\n validly granted by You or Your distributors under this License prior to\n termination shall survive termination.\n\n6. Disclaimer of Warranty\n\n Covered Software is provided under this License on an โ€œas isโ€ basis, without\n warranty of any kind, either expressed, implied, or statutory, including,\n without limitation, warranties that the Covered Software is free of defects,\n merchantable, fit for a particular purpose or non-infringing. The entire\n risk as to the quality and performance of the Covered Software is with You.\n Should any Covered Software prove defective in any respect, You (not any\n Contributor) assume the cost of any necessary servicing, repair, or\n correction. This disclaimer of warranty constitutes an essential part of this\n License. No use of any Covered Software is authorized under this License\n except under this disclaimer.\n\n7. Limitation of Liability\n\n Under no circumstances and under no legal theory, whether tort (including\n negligence), contract, or otherwise, shall any Contributor, or anyone who\n distributes Covered Software as permitted above, be liable to You for any\n direct, indirect, special, incidental, or consequential damages of any\n character including, without limitation, damages for lost profits, loss of\n goodwill, work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses, even if such party shall have been\n informed of the possibility of such damages. This limitation of liability\n shall not apply to liability for death or personal injury resulting from such\n partyโ€™s negligence to the extent applicable law prohibits such limitation.\n Some jurisdictions do not allow the exclusion or limitation of incidental or\n consequential damages, so this exclusion and limitation may not apply to You.\n\n8. Litigation\n\n Any litigation relating to this License may be brought only in the courts of\n a jurisdiction where the defendant maintains its principal place of business\n and such litigation shall be governed by laws of that jurisdiction, without\n reference to its conflict-of-law provisions. Nothing in this Section shall\n prevent a partyโ€™s ability to bring cross-claims or counter-claims.\n\n9. Miscellaneous\n\n This License represents the complete agreement concerning the subject matter\n hereof. If any provision of this License is held to be unenforceable, such\n provision shall be reformed only to the extent necessary to make it\n enforceable. Any law or regulation which provides that the language of a\n contract shall be construed against the drafter shall not be used to construe\n this License against a Contributor.\n\n\n10. Versions of the License\n\n10.1. New Versions\n\n Mozilla Foundation is the license steward. Except as provided in Section\n 10.3, no one other than the license steward has the right to modify or\n publish new versions of this License. Each version will be given a\n distinguishing version number.\n\n10.2. Effect of New Versions\n\n You may distribute the Covered Software under the terms of the version of\n the License under which You originally received the Covered Software, or\n under the terms of any subsequent version published by the license\n steward.\n\n10.3. Modified Versions\n\n If you create software not governed by this License, and you want to\n create a new license for such software, you may create and use a modified\n version of this License if you rename the license and remove any\n references to the name of the license steward (except to note that such\n modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses\n If You choose to distribute Source Code Form that is Incompatible With\n Secondary Licenses under the terms of this version of the License, the\n notice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n\n This Source Code Form is subject to the\n terms of the Mozilla Public License, v.\n 2.0. If a copy of the MPL was not\n distributed with this file, You can\n obtain one at\n http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular file, then\nYou may include the notice in a location (such as a LICENSE file in a relevant\ndirectory) where a recipient would be likely to look for such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - โ€œIncompatible With Secondary Licensesโ€ Notice\n\n This Source Code Form is โ€œIncompatible\n With Secondary Licensesโ€, as defined by\n the Mozilla Public License, v. 2.0.\n" - }, { "name": "github.com/hashicorp/go-retryablehttp", "path": "github.com/hashicorp/go-retryablehttp/LICENSE", @@ -765,8 +595,8 @@ "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015 Huan Du\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n" }, { - "name": "github.com/inbucket/html2text", - "path": "github.com/inbucket/html2text/LICENSE", + "name": "github.com/jaytaylor/html2text", + "path": "github.com/jaytaylor/html2text/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015 Jay Taylor\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n" }, { @@ -874,11 +704,6 @@ "path": "github.com/mattn/go-runewidth/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2016 Yasuhiro Matsumoto\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, - { - "name": "github.com/mattn/go-shellwords", - "path": "github.com/mattn/go-shellwords/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2017 Yasuhiro Matsumoto\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, { "name": "github.com/meilisearch/meilisearch-go", "path": "github.com/meilisearch/meilisearch-go/LICENSE", @@ -890,8 +715,8 @@ "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, { - "name": "github.com/mholt/archives", - "path": "github.com/mholt/archives/LICENSE", + "name": "github.com/mholt/archiver/v3", + "path": "github.com/mholt/archiver/v3/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2016 Matthew Holt\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE." }, { @@ -904,11 +729,6 @@ "path": "github.com/miekg/dns/LICENSE", "licenseText": "BSD 3-Clause License\n\nCopyright (c) 2009, The Go Authors. Extensions copyright (c) 2011, Miek Gieben. \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\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. 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\n3. 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/mikelolasagasti/xz", - "path": "github.com/mikelolasagasti/xz/LICENSE", - "licenseText": "Copyright (C) 2015-2017 Michael Cross \u003chttps://github.com/xi2\u003e\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n" - }, { "name": "github.com/minio/crc64nvme", "path": "github.com/minio/crc64nvme/LICENSE", @@ -924,11 +744,6 @@ "path": "github.com/minio/minio-go/v7/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, - { - "name": "github.com/minio/minlz", - "path": "github.com/minio/minlz/LICENSE", - "licenseText": "\r\n Apache License\r\n Version 2.0, January 2004\r\n http://www.apache.org/licenses/\r\n\r\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n 1. Definitions.\r\n\r\n \"License\" shall mean the terms and conditions for use, reproduction,\r\n and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n \"Licensor\" shall mean the copyright owner or entity authorized by\r\n the copyright owner that is granting the License.\r\n\r\n \"Legal Entity\" shall mean the union of the acting entity and all\r\n other entities that control, are controlled by, or are under common\r\n control with that entity. For the purposes of this definition,\r\n \"control\" means (i) the power, direct or indirect, to cause the\r\n direction or management of such entity, whether by contract or\r\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n exercising permissions granted by this License.\r\n\r\n \"Source\" form shall mean the preferred form for making modifications,\r\n including but not limited to software source code, documentation\r\n source, and configuration files.\r\n\r\n \"Object\" form shall mean any form resulting from mechanical\r\n transformation or translation of a Source form, including but\r\n not limited to compiled object code, generated documentation,\r\n and conversions to other media types.\r\n\r\n \"Work\" shall mean the work of authorship, whether in Source or\r\n Object form, made available under the License, as indicated by a\r\n copyright notice that is included in or attached to the work\r\n (an example is provided in the Appendix below).\r\n\r\n \"Derivative Works\" shall mean any work, whether in Source or Object\r\n form, that is based on (or derived from) the Work and for which the\r\n editorial revisions, annotations, elaborations, or other modifications\r\n represent, as a whole, an original work of authorship. For the purposes\r\n of this License, Derivative Works shall not include works that remain\r\n separable from, or merely link (or bind by name) to the interfaces of,\r\n the Work and Derivative Works thereof.\r\n\r\n \"Contribution\" shall mean any work of authorship, including\r\n the original version of the Work and any modifications or additions\r\n to that Work or Derivative Works thereof, that is intentionally\r\n submitted to Licensor for inclusion in the Work by the copyright owner\r\n or by an individual or Legal Entity authorized to submit on behalf of\r\n the copyright owner. For the purposes of this definition, \"submitted\"\r\n means any form of electronic, verbal, or written communication sent\r\n to the Licensor or its representatives, including but not limited to\r\n communication on electronic mailing lists, source code control systems,\r\n and issue tracking systems that are managed by, or on behalf of, the\r\n Licensor for the purpose of discussing and improving the Work, but\r\n excluding communication that is conspicuously marked or otherwise\r\n designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n on behalf of whom a Contribution has been received by Licensor and\r\n subsequently incorporated within the Work.\r\n\r\n 2. Grant of Copyright License. Subject to the terms and conditions of\r\n this License, each Contributor hereby grants to You a perpetual,\r\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n copyright license to reproduce, prepare Derivative Works of,\r\n publicly display, publicly perform, sublicense, and distribute the\r\n Work and such Derivative Works in Source or Object form.\r\n\r\n 3. Grant of Patent License. Subject to the terms and conditions of\r\n this License, each Contributor hereby grants to You a perpetual,\r\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n (except as stated in this section) patent license to make, have made,\r\n use, offer to sell, sell, import, and otherwise transfer the Work,\r\n where such license applies only to those patent claims licensable\r\n by such Contributor that are necessarily infringed by their\r\n Contribution(s) alone or by combination of their Contribution(s)\r\n with the Work to which such Contribution(s) was submitted. If You\r\n institute patent litigation against any entity (including a\r\n cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n or a Contribution incorporated within the Work constitutes direct\r\n or contributory patent infringement, then any patent licenses\r\n granted to You under this License for that Work shall terminate\r\n as of the date such litigation is filed.\r\n\r\n 4. Redistribution. You may reproduce and distribute copies of the\r\n Work or Derivative Works thereof in any medium, with or without\r\n modifications, and in Source or Object form, provided that You\r\n meet the following conditions:\r\n\r\n (a) You must give any other recipients of the Work or\r\n Derivative Works a copy of this License; and\r\n\r\n (b) You must cause any modified files to carry prominent notices\r\n stating that You changed the files; and\r\n\r\n (c) You must retain, in the Source form of any Derivative Works\r\n that You distribute, all copyright, patent, trademark, and\r\n attribution notices from the Source form of the Work,\r\n excluding those notices that do not pertain to any part of\r\n the Derivative Works; and\r\n\r\n (d) If the Work includes a \"NOTICE\" text file as part of its\r\n distribution, then any Derivative Works that You distribute must\r\n include a readable copy of the attribution notices contained\r\n within such NOTICE file, excluding those notices that do not\r\n pertain to any part of the Derivative Works, in at least one\r\n of the following places: within a NOTICE text file distributed\r\n as part of the Derivative Works; within the Source form or\r\n documentation, if provided along with the Derivative Works; or,\r\n within a display generated by the Derivative Works, if and\r\n wherever such third-party notices normally appear. The contents\r\n of the NOTICE file are for informational purposes only and\r\n do not modify the License. You may add Your own attribution\r\n notices within Derivative Works that You distribute, alongside\r\n or as an addendum to the NOTICE text from the Work, provided\r\n that such additional attribution notices cannot be construed\r\n as modifying the License.\r\n\r\n You may add Your own copyright statement to Your modifications and\r\n may provide additional or different license terms and conditions\r\n for use, reproduction, or distribution of Your modifications, or\r\n for any such Derivative Works as a whole, provided Your use,\r\n reproduction, and distribution of the Work otherwise complies with\r\n the conditions stated in this License.\r\n\r\n 5. Submission of Contributions. Unless You explicitly state otherwise,\r\n any Contribution intentionally submitted for inclusion in the Work\r\n by You to the Licensor shall be under the terms and conditions of\r\n this License, without any additional terms or conditions.\r\n Notwithstanding the above, nothing herein shall supersede or modify\r\n the terms of any separate license agreement you may have executed\r\n with Licensor regarding such Contributions.\r\n\r\n 6. Trademarks. This License does not grant permission to use the trade\r\n names, trademarks, service marks, or product names of the Licensor,\r\n except as required for reasonable and customary use in describing the\r\n origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n 7. Disclaimer of Warranty. Unless required by applicable law or\r\n agreed to in writing, Licensor provides the Work (and each\r\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n implied, including, without limitation, any warranties or conditions\r\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n PARTICULAR PURPOSE. You are solely responsible for determining the\r\n appropriateness of using or redistributing the Work and assume any\r\n risks associated with Your exercise of permissions under this License.\r\n\r\n 8. Limitation of Liability. In no event and under no legal theory,\r\n whether in tort (including negligence), contract, or otherwise,\r\n unless required by applicable law (such as deliberate and grossly\r\n negligent acts) or agreed to in writing, shall any Contributor be\r\n liable to You for damages, including any direct, indirect, special,\r\n incidental, or consequential damages of any character arising as a\r\n result of this License or out of the use or inability to use the\r\n Work (including but not limited to damages for loss of goodwill,\r\n work stoppage, computer failure or malfunction, or any and all\r\n other commercial damages or losses), even if such Contributor\r\n has been advised of the possibility of such damages.\r\n\r\n 9. Accepting Warranty or Additional Liability. While redistributing\r\n the Work or Derivative Works thereof, You may choose to offer,\r\n and charge a fee for, acceptance of support, warranty, indemnity,\r\n or other liability obligations and/or rights consistent with this\r\n License. However, in accepting such obligations, You may act only\r\n on Your own behalf and on Your sole responsibility, not on behalf\r\n of any other Contributor, and only if You agree to indemnify,\r\n defend, and hold each Contributor harmless for any liability\r\n incurred by, or claims asserted against, such Contributor by reason\r\n of your accepting any such warranty or additional liability.\r\n\r\nEND OF TERMS AND CONDITIONS" - }, { "name": "github.com/mitchellh/mapstructure", "path": "github.com/mitchellh/mapstructure/LICENSE", @@ -949,26 +764,21 @@ "path": "github.com/munnerz/goautoneg/LICENSE", "licenseText": "Copyright (c) 2011, Open Knowledge Foundation Ltd.\nAll 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\n notice, this list of conditions and the following disclaimer.\n\n Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n\n Neither the name of the Open Knowledge Foundation Ltd. nor the\n names of its contributors may be used to endorse or promote\n products derived from this software without specific prior written\n 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\nHOLDER 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/nektos/act/pkg", + "path": "github.com/nektos/act/pkg/LICENSE", + "licenseText": "MIT License\n\nCopyright (c) 2022 The Gitea Authors\nCopyright (c) 2019\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, { "name": "github.com/niklasfasching/go-org/org", "path": "github.com/niklasfasching/go-org/org/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2018 Niklas Fasching\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "name": "github.com/nwaples/rardecode/v2", - "path": "github.com/nwaples/rardecode/v2/LICENSE", + "name": "github.com/nwaples/rardecode", + "path": "github.com/nwaples/rardecode/LICENSE", "licenseText": "Copyright (c) 2015, Nicholas Waples\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\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/olekukonko/errors", - "path": "github.com/olekukonko/errors/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2025 Oleku Konko\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, - { - "name": "github.com/olekukonko/ll", - "path": "github.com/olekukonko/ll/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2025 Oleku Konko\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, { "name": "github.com/olekukonko/tablewriter", "path": "github.com/olekukonko/tablewriter/LICENSE.md", @@ -1094,11 +904,6 @@ "path": "github.com/skeema/knownhosts/LICENSE", "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright {yyyy} {name of copyright owner}\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, - { - "name": "github.com/sorairolake/lzip-go", - "path": "github.com/sorairolake/lzip-go/LICENSE", - "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n---\n\nMIT License\n\nCopyright (c) 2024 Shun Sakai\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, { "name": "github.com/ssor/bom", "path": "github.com/ssor/bom/LICENSE", @@ -1194,16 +999,6 @@ "path": "go.uber.org/zap/exp/zapslog/LICENSE", "licenseText": "Copyright (c) 2016-2024 Uber Technologies, Inc.\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": "go.yaml.in/yaml/v3", - "path": "go.yaml.in/yaml/v3/LICENSE", - "licenseText": "\nThis project is covered by two different licenses: MIT and Apache.\n\n#### MIT License ####\n\nThe following files were ported to Go from C files of libyaml, and thus\nare still covered by their original MIT license, with the additional\ncopyright staring in 2011 when the project was ported over:\n\n apic.go emitterc.go parserc.go readerc.go scannerc.go\n writerc.go yamlh.go yamlprivateh.go\n\nCopyright (c) 2006-2010 Kirill Simonov\nCopyright (c) 2006-2011 Kirill Simonov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n### Apache License ###\n\nAll the remaining project files are covered by the Apache license:\n\nCopyright (c) 2011-2019 Canonical Ltd\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" - }, - { - "name": "go4.org", - "path": "go4.org/LICENSE", - "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright {yyyy} {name of copyright owner}\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n" - }, { "name": "golang.org/x/crypto", "path": "golang.org/x/crypto/LICENSE", diff --git a/build/lint-locale-usage/allowed-masked-usage.txt b/build/lint-locale-usage/allowed-masked-usage.txt deleted file mode 100644 index 06675530db..0000000000 --- a/build/lint-locale-usage/allowed-masked-usage.txt +++ /dev/null @@ -1,54 +0,0 @@ -# translation tooling test keys -meta.last_line -translation_meta.test - -# models/admin/task.go: instances of $TranslatableMessage.Format -# this also gets instantiated as a Messenger once -repo.migrate.migrating_failed.error - -# models/asymkey/gpg_key_object_verification.go: $ObjectVerification.Reason -# unfortunately, it is non-trivial to parse all the occurences -gpg.error.extract_sign -gpg.error.failed_retrieval_gpg_keys -gpg.error.generate_hash -gpg.error.no_committer_account - -# models/system/notice.go: func (n *Notice) TrStr() string -admin.notices.type_1 -admin.notices.type_2 - -# modules/setting/ui.go -themes.names. - -# services/context/context.go -relativetime. - -# templates/mail/issue/default.tmpl: $.locale.Tr -mail.issue.in_tree_path - -# templates/package/metadata/arch.tmpl: $.locale.Tr -packages.details.license - -# templates/repo/issue/view_content.tmpl: indirection via $closeTranslationKey -repo.issues.close -repo.pulls.close - -# templates/repo/issue/view_content/comments.tmpl: indirection via $refTr -repo.issues.ref_closing_from -repo.issues.ref_issue_from -repo.issues.ref_pull_from -repo.issues.ref_reopening_from - -# templates/repo/issue/view_content/comments.tmpl: ctx.Locale.Tr (printf "projects.type-%d.display_name" .OldProject.Type) -projects. -projects.type-1.display_name -projects.type-2.display_name -projects.type-3.display_name - -# templates/repo/settings/webhook/link_menu.tmpl, templates/webhook/new.tmpl: repo.settings.web_hook_name_ -# tests/integration/repo_archive_text_test.go -repo.settings. - -# services/migrations/migrate.go: messenger calls -# ToDo: give them a unique prefix -repo.migrate. diff --git a/build/lint-locale-usage/handle-go.go b/build/lint-locale-usage/handle-go.go deleted file mode 100644 index a91a210313..0000000000 --- a/build/lint-locale-usage/handle-go.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package main - -import ( - "fmt" - "go/ast" - goParser "go/parser" - "go/token" - "strconv" - "strings" -) - -func (handler Handler) handleGoTrBasicLit(fset *token.FileSet, argLit *ast.BasicLit, prefix string) { - if argLit.Kind == token.STRING { - // extract string content - arg, err := strconv.Unquote(argLit.Value) - if err != nil { - return - } - // found interesting strings - arg = prefix + arg - if strings.HasSuffix(arg, ".") || strings.HasSuffix(arg, "_") { - prep, trunc := PrepareMsgidPrefix(arg) - if trunc { - handler.OnWarning(fset, argLit.ValuePos, fmt.Sprintf("needed to truncate message id prefix: %s", arg)) - } - handler.OnMsgidPrefix(fset, argLit.ValuePos, prep, trunc) - } else { - handler.OnMsgid(fset, argLit.ValuePos, arg) - } - } -} - -func (handler Handler) handleGoTrArgument(fset *token.FileSet, n ast.Expr, prefix string) { - if argLit, ok := n.(*ast.BasicLit); ok { - handler.handleGoTrBasicLit(fset, argLit, prefix) - } else if argBinExpr, ok := n.(*ast.BinaryExpr); ok { - if argBinExpr.Op != token.ADD { - // pass - } else if argLit, ok := argBinExpr.X.(*ast.BasicLit); ok && argLit.Kind == token.STRING { - // extract string content - arg, err := strconv.Unquote(argLit.Value) - if err != nil { - return - } - // found interesting strings - arg = prefix + arg - prep, trunc := PrepareMsgidPrefix(arg) - if trunc { - handler.OnWarning(fset, argLit.ValuePos, fmt.Sprintf("needed to truncate message id prefix: %s", arg)) - } - handler.OnMsgidPrefix(fset, argLit.ValuePos, prep, trunc) - } - } -} - -func (handler Handler) handleGoCommentGroup(fset *token.FileSet, cg *ast.CommentGroup, commentPrefix string) *string { - if cg == nil { - return nil - } - var matches []token.Pos - matchInsPrefix := "" - commentPrefix = "//" + commentPrefix - for _, comment := range cg.List { - ctxt := strings.TrimSpace(comment.Text) - if ctxt == commentPrefix { - matches = append(matches, comment.Slash) - } else if after, found := strings.CutPrefix(ctxt, commentPrefix+"Suffix "); found { - matches = append(matches, comment.Slash) - matchInsPrefix = strings.TrimSpace(after) - } - } - switch len(matches) { - case 0: - return nil - case 1: - return &matchInsPrefix - default: - handler.OnWarning( - fset, - matches[0], - fmt.Sprintf("encountered multiple %s... directives, ignoring", strings.TrimSpace(commentPrefix)), - ) - return &matchInsPrefix - } -} - -// the `Handle*File` functions follow the following calling convention: -// * `fname` is the name of the input file -// * `src` is either `nil` (then the function invokes `ReadFile` to read the file) -// or the contents of the file as {`[]byte`, or a `string`} - -func (handler Handler) HandleGoFile(fname string, src any) error { - fset := token.NewFileSet() - node, err := goParser.ParseFile(fset, fname, src, goParser.SkipObjectResolution|goParser.ParseComments) - if err != nil { - return LocatedError{ - Location: fname, - Kind: "Go parser", - Err: err, - } - } - - ast.Inspect(node, func(n ast.Node) bool { - // search for function calls of the form `anything.Tr(any-string-lit, ...)` - - switch n2 := n.(type) { - case *ast.CallExpr: - if len(n2.Args) == 0 { - return true - } - funSel, ok := n2.Fun.(*ast.SelectorExpr) - if !ok { - return true - } - - ltf, ok := handler.LocaleTrFunctions[funSel.Sel.Name] - if !ok { - return true - } - - var gotUnexpectedInvoke *int - - for _, argNum := range ltf { - if len(n2.Args) <= int(argNum) { - argc := len(n2.Args) - gotUnexpectedInvoke = &argc - } else { - handler.handleGoTrArgument(fset, n2.Args[int(argNum)], "") - } - } - - if gotUnexpectedInvoke != nil { - handler.OnUnexpectedInvoke(fset, funSel.Sel.NamePos, funSel.Sel.Name, *gotUnexpectedInvoke) - } - case *ast.CompositeLit: - ident, ok := n2.Type.(*ast.Ident) - if !ok { - return true - } - - // special case: models/unit/unit.go - if strings.HasSuffix(fname, "unit.go") && ident.Name == "Unit" { - if len(n2.Elts) != 6 { - handler.OnWarning(fset, n2.Pos(), "unexpected initialization of 'Unit' (unexpected number of arguments)") - } - // NameKey has index 2 - // invoked like '{{ctx.Locale.Tr $unit.NameKey}}' - nameKey, ok := n2.Elts[2].(*ast.BasicLit) - if !ok || nameKey.Kind != token.STRING { - handler.OnWarning(fset, n2.Elts[2].Pos(), "unexpected initialization of 'Unit' (expected string literal as NameKey)") - return true - } - - // extract string content - arg, err := strconv.Unquote(nameKey.Value) - if err == nil { - // found interesting strings - handler.OnMsgid(fset, nameKey.ValuePos, arg) - } - } - case *ast.FuncDecl: - matchInsPrefix := handler.handleGoCommentGroup(fset, n2.Doc, "llu:returnsTrKey") - if matchInsPrefix == nil { - return true - } - results := n2.Type.Results.List - if len(results) != 1 { - handler.OnWarning(fset, n2.Type.Func, fmt.Sprintf("function %s has unexpected return type; expected single return value", n2.Name.Name)) - return true - } - - ast.Inspect(n2.Body, func(n ast.Node) bool { - // search for return stmts - // TODO: what about nested functions? - if ret, ok := n.(*ast.ReturnStmt); ok { - for _, res := range ret.Results { - ast.Inspect(res, func(n ast.Node) bool { - if expr, ok := n.(ast.Expr); ok { - handler.handleGoTrArgument(fset, expr, *matchInsPrefix) - } - return true - }) - } - return false - } - return true - }) - return true - case *ast.GenDecl: - if !(n2.Tok == token.CONST || n2.Tok == token.VAR) { - return true - } - matchInsPrefix := handler.handleGoCommentGroup(fset, n2.Doc, " llu:TrKeys") - if matchInsPrefix == nil { - return true - } - for _, spec := range n2.Specs { - // interpret all contained strings as message IDs - ast.Inspect(spec, func(n ast.Node) bool { - if argLit, ok := n.(*ast.BasicLit); ok { - handler.handleGoTrBasicLit(fset, argLit, *matchInsPrefix) - return false - } - return true - }) - } - } - - return true - }) - - return nil -} diff --git a/build/lint-locale-usage/handle-tmpl.go b/build/lint-locale-usage/handle-tmpl.go deleted file mode 100644 index a71d7d47e3..0000000000 --- a/build/lint-locale-usage/handle-tmpl.go +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package main - -import ( - "fmt" - "go/token" - "os" - "strings" - "text/template" - tmplParser "text/template/parse" - - fjTemplates "forgejo.org/modules/templates" - "forgejo.org/modules/util" -) - -// derived from source: modules/templates/scopedtmpl/scopedtmpl.go, L169-L213 -func (handler Handler) handleTemplateNode(fset *token.FileSet, node tmplParser.Node) { - switch node.Type() { - case tmplParser.NodeAction: - handler.handleTemplatePipeNode(fset, node.(*tmplParser.ActionNode).Pipe) - case tmplParser.NodeList: - nodeList := node.(*tmplParser.ListNode) - handler.handleTemplateFileNodes(fset, nodeList.Nodes) - case tmplParser.NodePipe: - handler.handleTemplatePipeNode(fset, node.(*tmplParser.PipeNode)) - case tmplParser.NodeTemplate: - handler.handleTemplatePipeNode(fset, node.(*tmplParser.TemplateNode).Pipe) - case tmplParser.NodeIf: - nodeIf := node.(*tmplParser.IfNode) - handler.handleTemplateBranchNode(fset, nodeIf.BranchNode) - case tmplParser.NodeRange: - nodeRange := node.(*tmplParser.RangeNode) - handler.handleTemplateBranchNode(fset, nodeRange.BranchNode) - case tmplParser.NodeWith: - nodeWith := node.(*tmplParser.WithNode) - handler.handleTemplateBranchNode(fset, nodeWith.BranchNode) - - case tmplParser.NodeCommand: - nodeCommand := node.(*tmplParser.CommandNode) - - handler.handleTemplateFileNodes(fset, nodeCommand.Args) - - if len(nodeCommand.Args) < 2 { - return - } - - funcname := "" - if nodeChain, ok := nodeCommand.Args[0].(*tmplParser.ChainNode); ok { - if nodeIdent, ok := nodeChain.Node.(*tmplParser.IdentifierNode); ok { - if nodeIdent.Ident != "ctx" || len(nodeChain.Field) != 2 || nodeChain.Field[0] != "Locale" { - return - } - funcname = nodeChain.Field[1] - } - } else if nodeField, ok := nodeCommand.Args[0].(*tmplParser.FieldNode); ok { - if len(nodeField.Ident) != 2 || !(nodeField.Ident[0] == "locale" || nodeField.Ident[0] == "Locale") { - return - } - funcname = nodeField.Ident[1] - } - - var gotUnexpectedInvoke *int - ltf, ok := handler.LocaleTrFunctions[funcname] - if !ok { - return - } - - for _, argNum := range ltf { - if len(nodeCommand.Args) >= int(argNum+2) { - handler.handleTemplateMsgid(fset, nodeCommand.Args[int(argNum+1)]) - } else { - argc := len(nodeCommand.Args) - 1 - gotUnexpectedInvoke = &argc - } - } - - if gotUnexpectedInvoke != nil { - handler.OnUnexpectedInvoke(fset, token.Pos(nodeCommand.Pos), funcname, *gotUnexpectedInvoke) - } - - default: - } -} - -func (handler Handler) handleTemplateMsgid(fset *token.FileSet, node tmplParser.Node) { - // the column numbers are a bit "off", but much better than nothing - pos := token.Pos(node.Position()) - - switch node.Type() { - case tmplParser.NodeString: - nodeString := node.(*tmplParser.StringNode) - // found interesting strings - handler.OnMsgid(fset, pos, nodeString.Text) - - case tmplParser.NodePipe: - nodePipe := node.(*tmplParser.PipeNode) - handler.handleTemplatePipeNode(fset, nodePipe) - - if len(nodePipe.Cmds) == 0 { - handler.OnWarning(fset, pos, fmt.Sprintf("unsupported invocation of locate function (no commands): %s", node.String())) - } else if len(nodePipe.Cmds) != 1 { - handler.OnWarning(fset, pos, fmt.Sprintf("unsupported invocation of locate function (too many commands): %s", node.String())) - return - } - nodeCommand := nodePipe.Cmds[0] - if len(nodeCommand.Args) < 2 { - handler.OnWarning(fset, pos, fmt.Sprintf("unsupported invocation of locate function (not enough arguments): %s", node.String())) - return - } - - nodeIdent, ok := nodeCommand.Args[0].(*tmplParser.IdentifierNode) - if !ok || (nodeIdent.Ident != "print" && nodeIdent.Ident != "printf") { - // handler.OnWarning(fset, pos, fmt.Sprintf("unsupported invocation of locate function (bad command): %s", node.String())) - return - } - - nodeString, ok := nodeCommand.Args[1].(*tmplParser.StringNode) - if !ok { - //handler.OnWarning( - // fset, - // pos, - // fmt.Sprintf("unsupported invocation of locate function (string should be first argument to %s): %s", nodeIdent.Ident, node.String()), - //) - return - } - - msgidPrefix := nodeString.Text - stringPos := token.Pos(nodeString.Pos) - - if len(nodeCommand.Args) == 2 { - // found interesting strings - handler.OnMsgid(fset, stringPos, msgidPrefix) - } else { - if nodeIdent.Ident == "printf" { - parts := strings.SplitN(msgidPrefix, "%", 2) - if len(parts) != 2 { - handler.OnWarning( - fset, - stringPos, - fmt.Sprintf("unsupported invocation of locate function (format string doesn't match \"prefix%%smth\" pattern): %s", nodeString.String()), - ) - return - } - msgidPrefix = parts[0] - } - - msgidPrefixFin, truncated := PrepareMsgidPrefix(msgidPrefix) - if truncated { - handler.OnWarning(fset, stringPos, fmt.Sprintf("needed to truncate message id prefix: %s", msgidPrefix)) - } - - // found interesting strings - handler.OnMsgidPrefix(fset, stringPos, msgidPrefixFin, truncated) - } - - default: - // handler.OnWarning(fset, pos, fmt.Sprintf("unknown invocation of locate function: %s", node.String())) - } -} - -func (handler Handler) handleTemplatePipeNode(fset *token.FileSet, pipeNode *tmplParser.PipeNode) { - if pipeNode == nil { - return - } - - // NOTE: we can't pass `pipeNode.Cmds` to handleTemplateFileNodes due to incompatible argument types - for _, node := range pipeNode.Cmds { - handler.handleTemplateNode(fset, node) - } -} - -func (handler Handler) handleTemplateBranchNode(fset *token.FileSet, branchNode tmplParser.BranchNode) { - handler.handleTemplatePipeNode(fset, branchNode.Pipe) - handler.handleTemplateFileNodes(fset, branchNode.List.Nodes) - if branchNode.ElseList != nil { - handler.handleTemplateFileNodes(fset, branchNode.ElseList.Nodes) - } -} - -func (handler Handler) handleTemplateFileNodes(fset *token.FileSet, nodes []tmplParser.Node) { - for _, node := range nodes { - handler.handleTemplateNode(fset, node) - } -} - -// the `Handle*File` functions follow the following calling convention: -// * `fname` is the name of the input file -// * `src` is either `nil` (then the function invokes `ReadFile` to read the file) -// or the contents of the file as {`[]byte`, or a `string`} - -func (handler Handler) HandleTemplateFile(fname string, src any) error { - var tmplContent []byte - switch src2 := src.(type) { - case nil: - var err error - tmplContent, err = os.ReadFile(fname) - if err != nil { - return LocatedError{ - Location: fname, - Kind: "ReadFile", - Err: err, - } - } - case []byte: - tmplContent = src2 - case string: - // SAFETY: we do not modify tmplContent below - tmplContent = util.UnsafeStringToBytes(src2) - default: - panic("invalid type for 'src'") - } - - fset := token.NewFileSet() - fset.AddFile(fname, 1, len(tmplContent)).SetLinesForContent(tmplContent) - // SAFETY: we do not modify tmplContent2 below - tmplContent2 := util.UnsafeBytesToString(tmplContent) - - tmpl := template.New(fname) - tmpl.Funcs(fjTemplates.NewFuncMap()) - tmplParsed, err := tmpl.Parse(tmplContent2) - if err != nil { - return LocatedError{ - Location: fname, - Kind: "Template parser", - Err: err, - } - } - handler.handleTemplateFileNodes(fset, tmplParsed.Root.Nodes) - return nil -} diff --git a/build/lint-locale-usage/lint-locale-usage.go b/build/lint-locale-usage/lint-locale-usage.go index 8c67a781e9..88375c1c36 100644 --- a/build/lint-locale-usage/lint-locale-usage.go +++ b/build/lint-locale-usage/lint-locale-usage.go @@ -5,19 +5,22 @@ package main import ( - "bufio" - "errors" - "flag" "fmt" + "go/ast" + goParser "go/parser" "go/token" "io/fs" "os" "path/filepath" - "sort" + "strconv" "strings" + "text/template" + tmplParser "text/template/parse" "forgejo.org/modules/container" + fjTemplates "forgejo.org/modules/templates" "forgejo.org/modules/translation/localeiter" + "forgejo.org/modules/util" ) // this works by first gathering all valid source string IDs from `en-US` reference files @@ -60,180 +63,241 @@ func InitLocaleTrFunctions() map[string][]uint { type Handler struct { OnMsgid func(fset *token.FileSet, pos token.Pos, msgid string) - OnMsgidPrefix func(fset *token.FileSet, pos token.Pos, msgidPrefix string, truncated bool) OnUnexpectedInvoke func(fset *token.FileSet, pos token.Pos, funcname string, argc int) - OnWarning func(fset *token.FileSet, pos token.Pos, msg string) LocaleTrFunctions map[string][]uint } -type StringTrie interface { - Matches(key []string) bool -} +// the `Handle*File` functions follow the following calling convention: +// * `fname` is the name of the input file +// * `src` is either `nil` (then the function invokes `ReadFile` to read the file) +// or the contents of the file as {`[]byte`, or a `string`} -type StringTrieMap map[string]StringTrie - -func (m StringTrieMap) Matches(key []string) bool { - if len(key) == 0 || m == nil { - return true - } - value, ok := m[key[0]] - if !ok { - return false - } - if value == nil { - return true - } - return value.Matches(key[1:]) -} - -func (m StringTrieMap) Insert(key []string) { - if m == nil { - return - } - - switch len(key) { - case 0: - return - - case 1: - m[key[0]] = nil - - default: - if value, ok := m[key[0]]; ok { - if value == nil { - return - } - } else { - m[key[0]] = make(StringTrieMap) - } - m[key[0]].(StringTrieMap).Insert(key[1:]) - } -} - -func ParseAllowedMaskedUsages(fname string, usedMsgids container.Set[string], allowedMaskedPrefixes StringTrieMap, chkMsgid func(msgid string) bool) error { - file, err := os.Open(fname) +func (handler Handler) HandleGoFile(fname string, src any) error { + fset := token.NewFileSet() + node, err := goParser.ParseFile(fset, fname, src, goParser.SkipObjectResolution) if err != nil { return LocatedError{ Location: fname, - Kind: "Open", + Kind: "Go parser", Err: err, } } - defer file.Close() - scanner := bufio.NewScanner(file) - lno := 0 - for scanner.Scan() { - lno++ - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue + ast.Inspect(node, func(n ast.Node) bool { + // search for function calls of the form `anything.Tr(any-string-lit, ...)` + + call, ok := n.(*ast.CallExpr) + if !ok || len(call.Args) < 1 { + return true } - if linePrefix, found := strings.CutSuffix(line, "."); found { - allowedMaskedPrefixes.Insert(strings.Split(linePrefix, ".")) - } else { - if !chkMsgid(line) { - return LocatedError{ - Location: fmt.Sprintf("%s: line %d", fname, lno), - Kind: "undefined msgid", - Err: errors.New(line), + + funSel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return true + } + + ltf, ok := handler.LocaleTrFunctions[funSel.Sel.Name] + if !ok { + return true + } + + var gotUnexpectedInvoke *int + + for _, argNum := range ltf { + if len(call.Args) >= int(argNum+1) { + argLit, ok := call.Args[int(argNum)].(*ast.BasicLit) + if !ok || argLit.Kind != token.STRING { + continue } + + // extract string content + arg, err := strconv.Unquote(argLit.Value) + if err == nil { + // found interesting strings + handler.OnMsgid(fset, argLit.ValuePos, arg) + } + } else { + argc := len(call.Args) + gotUnexpectedInvoke = &argc } - usedMsgids.Add(line) } - } - if err := scanner.Err(); err != nil { - return LocatedError{ - Location: fname, - Kind: "Scanner", - Err: err, + + if gotUnexpectedInvoke != nil { + handler.OnUnexpectedInvoke(fset, funSel.Sel.NamePos, funSel.Sel.Name, *gotUnexpectedInvoke) } - } + + return true + }) + return nil } -// Truncating a message id prefix to the last dot -func PrepareMsgidPrefix(s string) (string, bool) { - index := strings.LastIndexByte(s, 0x2e) - if index == -1 { - return "", true +// derived from source: modules/templates/scopedtmpl/scopedtmpl.go, L169-L213 +func (handler Handler) handleTemplateNode(fset *token.FileSet, node tmplParser.Node) { + switch node.Type() { + case tmplParser.NodeAction: + handler.handleTemplatePipeNode(fset, node.(*tmplParser.ActionNode).Pipe) + case tmplParser.NodeList: + nodeList := node.(*tmplParser.ListNode) + handler.handleTemplateFileNodes(fset, nodeList.Nodes) + case tmplParser.NodePipe: + handler.handleTemplatePipeNode(fset, node.(*tmplParser.PipeNode)) + case tmplParser.NodeTemplate: + handler.handleTemplatePipeNode(fset, node.(*tmplParser.TemplateNode).Pipe) + case tmplParser.NodeIf: + nodeIf := node.(*tmplParser.IfNode) + handler.handleTemplateBranchNode(fset, nodeIf.BranchNode) + case tmplParser.NodeRange: + nodeRange := node.(*tmplParser.RangeNode) + handler.handleTemplateBranchNode(fset, nodeRange.BranchNode) + case tmplParser.NodeWith: + nodeWith := node.(*tmplParser.WithNode) + handler.handleTemplateBranchNode(fset, nodeWith.BranchNode) + + case tmplParser.NodeCommand: + nodeCommand := node.(*tmplParser.CommandNode) + + handler.handleTemplateFileNodes(fset, nodeCommand.Args) + + if len(nodeCommand.Args) < 2 { + return + } + + nodeChain, ok := nodeCommand.Args[0].(*tmplParser.ChainNode) + if !ok { + return + } + + nodeIdent, ok := nodeChain.Node.(*tmplParser.IdentifierNode) + if !ok || nodeIdent.Ident != "ctx" || len(nodeChain.Field) != 2 || nodeChain.Field[0] != "Locale" { + return + } + + ltf, ok := handler.LocaleTrFunctions[nodeChain.Field[1]] + if !ok { + return + } + + var gotUnexpectedInvoke *int + + for _, argNum := range ltf { + if len(nodeCommand.Args) >= int(argNum+2) { + nodeString, ok := nodeCommand.Args[int(argNum+1)].(*tmplParser.StringNode) + if ok { + // found interesting strings + // the column numbers are a bit "off", but much better than nothing + handler.OnMsgid(fset, token.Pos(nodeString.Pos), nodeString.Text) + } + } else { + argc := len(nodeCommand.Args) - 1 + gotUnexpectedInvoke = &argc + } + } + + if gotUnexpectedInvoke != nil { + handler.OnUnexpectedInvoke(fset, token.Pos(nodeChain.Pos), nodeChain.Field[1], *gotUnexpectedInvoke) + } + + default: } - return s[:index], index != len(s)-1 } -func Usage() { - outp := flag.CommandLine.Output() - fmt.Fprintf(outp, "Usage of %s:\n", os.Args[0]) - flag.PrintDefaults() - - fmt.Fprintf(outp, "\nThis command assumes that it gets started from the project root directory.\n") - - fmt.Fprintf(outp, "\nExit codes:\n") - for _, i := range []string{ - "0\tsuccess, no issues found", - "1\tunable to walk directory tree", - "2\tunable to parse locale ini/json files", - "3\tunable to parse go or text/template files", - "4\tfound missing message IDs", - "5\tfound unused message IDs", - } { - fmt.Fprintf(outp, "\t%s\n", i) +func (handler Handler) handleTemplatePipeNode(fset *token.FileSet, pipeNode *tmplParser.PipeNode) { + if pipeNode == nil { + return } - fmt.Fprintf(outp, "\nSpecial Go doc comments:\n") - for _, i := range []string{ - "//llu:returnsTrKey", - "\tcan be used in front of functions to indicate", - "\tthat the function returns message IDs", - "\tWARNING: this currently doesn't support nested functions properly", - "", - "//llu:returnsTrKeySuffix prefix.", - "\tsimilar to llu:returnsTrKey, but the given prefix is prepended", - "\tto the found strings before interpreting them as msgids", - "", - "// llu:TrKeys", - "\tcan be used in front of 'const' and 'var' blocks", - "\tin order to mark all contained strings as message IDs", - "", - "// llu:TrKeysSuffix prefix.", - "\tlike llu:returnsTrKeySuffix, but for 'const' and 'var' blocks", - } { - if i == "" { - fmt.Fprintf(outp, "\n") - } else { - fmt.Fprintf(outp, "\t%s\n", i) + // NOTE: we can't pass `pipeNode.Cmds` to handleTemplateFileNodes due to incompatible argument types + for _, node := range pipeNode.Cmds { + handler.handleTemplateNode(fset, node) + } +} + +func (handler Handler) handleTemplateBranchNode(fset *token.FileSet, branchNode tmplParser.BranchNode) { + handler.handleTemplatePipeNode(fset, branchNode.Pipe) + handler.handleTemplateFileNodes(fset, branchNode.List.Nodes) + if branchNode.ElseList != nil { + handler.handleTemplateFileNodes(fset, branchNode.ElseList.Nodes) + } +} + +func (handler Handler) handleTemplateFileNodes(fset *token.FileSet, nodes []tmplParser.Node) { + for _, node := range nodes { + handler.handleTemplateNode(fset, node) + } +} + +func (handler Handler) HandleTemplateFile(fname string, src any) error { + var tmplContent []byte + switch src2 := src.(type) { + case nil: + var err error + tmplContent, err = os.ReadFile(fname) + if err != nil { + return LocatedError{ + Location: fname, + Kind: "ReadFile", + Err: err, + } + } + case []byte: + tmplContent = src2 + case string: + // SAFETY: we do not modify tmplContent below + tmplContent = util.UnsafeStringToBytes(src2) + default: + panic("invalid type for 'src'") + } + + fset := token.NewFileSet() + fset.AddFile(fname, 1, len(tmplContent)).SetLinesForContent(tmplContent) + // SAFETY: we do not modify tmplContent2 below + tmplContent2 := util.UnsafeBytesToString(tmplContent) + + tmpl := template.New(fname) + tmpl.Funcs(fjTemplates.NewFuncMap()) + tmplParsed, err := tmpl.Parse(tmplContent2) + if err != nil { + return LocatedError{ + Location: fname, + Kind: "Template parser", + Err: err, } } + handler.handleTemplateFileNodes(fset, tmplParsed.Root.Nodes) + return nil } +// This command assumes that we get started from the project root directory +// +// Possible command line flags: +// +// --allow-missing-msgids don't return an error code if missing message IDs are found +// +// EXIT CODES: +// +// 0 success, no issues found +// 1 unable to walk directory tree +// 2 unable to parse locale ini/json files +// 3 unable to parse go or text/template files +// 4 found missing message IDs +// //nolint:forbidigo func main() { allowMissingMsgids := false - allowUnusedMsgids := false - usedMsgids := make(container.Set[string]) - allowedMaskedPrefixes := make(StringTrieMap) - - // It's possible for execl to hand us an empty os.Args. - if len(os.Args) == 0 { - flag.CommandLine = flag.NewFlagSet("lint-locale-usage", flag.ExitOnError) - } else { - flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + for _, arg := range os.Args[1:] { + if arg == "--allow-missing-msgids" { + allowMissingMsgids = true + } } - flag.CommandLine.Usage = Usage - flag.Usage = Usage - flag.BoolVar( - &allowMissingMsgids, - "allow-missing-msgids", - false, - "don't return an error code if missing message IDs are found", - ) - flag.BoolVar( - &allowUnusedMsgids, - "allow-unused-msgids", - false, - "don't return an error code if unused message IDs are found", - ) + onError := func(err error) { + if err == nil { + return + } + fmt.Println(err.Error()) + os.Exit(3) + } msgids := make(container.Set[string]) @@ -270,50 +334,17 @@ func main() { gotAnyMsgidError := false - flag.Func( - "allow-masked-usages-from", - "supply a file containing a newline-separated list of allowed masked usages", - func(argval string) error { - return ParseAllowedMaskedUsages(argval, usedMsgids, allowedMaskedPrefixes, func(msgid string) bool { - return msgids.Contains(msgid) - }) - }, - ) - flag.Parse() - - onError := func(err error) { - if err == nil { - return - } - fmt.Println(err.Error()) - os.Exit(3) - } - handler := Handler{ - OnMsgidPrefix: func(fset *token.FileSet, pos token.Pos, msgidPrefix string, truncated bool) { - msgidPrefixSplit := strings.Split(msgidPrefix, ".") - if !truncated { - allowedMaskedPrefixes.Insert(msgidPrefixSplit) - } else if !allowedMaskedPrefixes.Matches(msgidPrefixSplit) { - gotAnyMsgidError = true - fmt.Printf("%s:\tmissing msgid prefix: %s\n", fset.Position(pos).String(), msgidPrefix) - } - }, OnMsgid: func(fset *token.FileSet, pos token.Pos, msgid string) { if !msgids.Contains(msgid) { gotAnyMsgidError = true fmt.Printf("%s:\tmissing msgid: %s\n", fset.Position(pos).String(), msgid) - } else { - usedMsgids.Add(msgid) } }, OnUnexpectedInvoke: func(fset *token.FileSet, pos token.Pos, funcname string, argc int) { gotAnyMsgidError = true fmt.Printf("%s:\tunexpected invocation of %s with %d arguments\n", fset.Position(pos).String(), funcname, argc) }, - OnWarning: func(fset *token.FileSet, pos token.Pos, msg string) { - fmt.Printf("%s:\tWARNING: %s\n", fset.Position(pos).String(), msg) - }, LocaleTrFunctions: InitLocaleTrFunctions(), } @@ -346,27 +377,7 @@ func main() { os.Exit(1) } - unusedMsgids := []string{} - - for msgid := range msgids { - if !usedMsgids.Contains(msgid) && !allowedMaskedPrefixes.Matches(strings.Split(msgid, ".")) { - unusedMsgids = append(unusedMsgids, msgid) - } - } - - sort.Strings(unusedMsgids) - - if len(unusedMsgids) != 0 { - fmt.Printf("=== unused msgids (%d): ===\n", len(unusedMsgids)) - for _, msgid := range unusedMsgids { - fmt.Printf("- %s\n", msgid) - } - } - if !allowMissingMsgids && gotAnyMsgidError { os.Exit(4) } - if !allowUnusedMsgids && len(unusedMsgids) != 0 { - os.Exit(5) - } } diff --git a/cmd/admin_auth.go b/cmd/admin_auth.go index 91b344b1e9..cb95b3b3c8 100644 --- a/cmd/admin_auth.go +++ b/cmd/admin_auth.go @@ -17,15 +17,6 @@ import ( "github.com/urfave/cli/v3" ) -type ( - authService struct { - initDB func(ctx context.Context) error - createAuthSource func(context.Context, *auth_model.Source) error - updateAuthSource func(context.Context, *auth_model.Source) error - getAuthSourceByID func(ctx context.Context, id int64) (*auth_model.Source, error) - } -) - func microcmdAuthDelete() *cli.Command { return &cli.Command{ Name: "delete", @@ -69,16 +60,6 @@ func microcmdAuthList() *cli.Command { } } -// newAuthService creates a service with default functions. -func newAuthService() *authService { - return &authService{ - initDB: initDB, - createAuthSource: auth_model.CreateSource, - updateAuthSource: auth_model.UpdateSource, - getAuthSourceByID: auth_model.GetSourceByID, - } -} - func runListAuth(ctx context.Context, c *cli.Command) error { ctx, cancel := installSignals(ctx) defer cancel() diff --git a/cmd/admin_auth_ldap.go b/cmd/admin_auth_ldap.go index 9af6c331d3..997d6b3a16 100644 --- a/cmd/admin_auth_ldap.go +++ b/cmd/admin_auth_ldap.go @@ -14,6 +14,15 @@ import ( "github.com/urfave/cli/v3" ) +type ( + authService struct { + initDB func(ctx context.Context) error + createAuthSource func(context.Context, *auth.Source) error + updateAuthSource func(context.Context, *auth.Source) error + getAuthSourceByID func(ctx context.Context, id int64) (*auth.Source, error) + } +) + func commonLdapCLIFlags() []cli.Flag { return []cli.Flag{ &cli.StringFlag{ @@ -175,6 +184,16 @@ func microcmdAuthUpdateLdapSimpleAuth() *cli.Command { } } +// newAuthService creates a service with default functions. +func newAuthService() *authService { + return &authService{ + initDB: initDB, + createAuthSource: auth.CreateSource, + updateAuthSource: auth.UpdateSource, + getAuthSourceByID: auth.GetSourceByID, + } +} + // parseAuthSource assigns values on authSource according to command line flags. func parseAuthSource(c *cli.Command, authSource *auth.Source) { if c.IsSet("name") { diff --git a/cmd/admin_auth_oauth.go b/cmd/admin_auth_oauth.go index ef5d9116e3..abdcd5d48a 100644 --- a/cmd/admin_auth_oauth.go +++ b/cmd/admin_auth_oauth.go @@ -86,11 +86,6 @@ func oauthCLIFlags() []cli.Flag { Value: nil, Usage: "Scopes to request when to authenticate against this OAuth2 source", }, - &cli.StringFlag{ - Name: "attribute-ssh-public-key", - Value: "", - Usage: "Claim name providing SSH public keys for this source", - }, &cli.StringFlag{ Name: "required-claim-name", Value: "", @@ -125,10 +120,6 @@ func oauthCLIFlags() []cli.Flag { Name: "group-team-map-removal", Usage: "Activate automatic team membership removal depending on groups", }, - &cli.BoolFlag{ - Name: "allow-username-change", - Usage: "Allow users to change their username", - }, } } @@ -136,7 +127,7 @@ func microcmdAuthAddOauth() *cli.Command { return &cli.Command{ Name: "add-oauth", Usage: "Add new Oauth authentication source", - Action: newAuthService().addOauth, + Action: runAddOauth, Flags: oauthCLIFlags(), } } @@ -145,7 +136,7 @@ func microcmdAuthUpdateOauth() *cli.Command { return &cli.Command{ Name: "update-oauth", Usage: "Update existing Oauth authentication source", - Action: newAuthService().updateOauth, + Action: runUpdateOauth, Flags: append(oauthCLIFlags()[:1], append([]cli.Flag{idFlag()}, oauthCLIFlags()[1:]...)...), } } @@ -172,7 +163,6 @@ func parseOAuth2Config(_ context.Context, c *cli.Command) *oauth2.Source { IconURL: c.String("icon-url"), SkipLocalTwoFA: c.Bool("skip-local-2fa"), Scopes: c.StringSlice("scopes"), - AttributeSSHPublicKey: c.String("attribute-ssh-public-key"), RequiredClaimName: c.String("required-claim-name"), RequiredClaimValue: c.String("required-claim-value"), GroupClaimName: c.String("group-claim-name"), @@ -180,15 +170,14 @@ func parseOAuth2Config(_ context.Context, c *cli.Command) *oauth2.Source { RestrictedGroup: c.String("restricted-group"), GroupTeamMap: c.String("group-team-map"), GroupTeamMapRemoval: c.Bool("group-team-map-removal"), - AllowUsernameChange: c.Bool("allow-username-change"), } } -func (a *authService) addOauth(ctx context.Context, c *cli.Command) error { +func runAddOauth(ctx context.Context, c *cli.Command) error { ctx, cancel := installSignals(ctx) defer cancel() - if err := a.initDB(ctx); err != nil { + if err := initDB(ctx); err != nil { return err } @@ -200,7 +189,7 @@ func (a *authService) addOauth(ctx context.Context, c *cli.Command) error { } } - return a.createAuthSource(ctx, &auth_model.Source{ + return auth_model.CreateSource(ctx, &auth_model.Source{ Type: auth_model.OAuth2, Name: c.String("name"), IsActive: true, @@ -208,7 +197,7 @@ func (a *authService) addOauth(ctx context.Context, c *cli.Command) error { }) } -func (a *authService) updateOauth(ctx context.Context, c *cli.Command) error { +func runUpdateOauth(ctx context.Context, c *cli.Command) error { if !c.IsSet("id") { return errors.New("--id flag is missing") } @@ -216,11 +205,11 @@ func (a *authService) updateOauth(ctx context.Context, c *cli.Command) error { ctx, cancel := installSignals(ctx) defer cancel() - if err := a.initDB(ctx); err != nil { + if err := initDB(ctx); err != nil { return err } - source, err := a.getAuthSourceByID(ctx, c.Int64("id")) + source, err := auth_model.GetSourceByID(ctx, c.Int64("id")) if err != nil { return err } @@ -255,10 +244,6 @@ func (a *authService) updateOauth(ctx context.Context, c *cli.Command) error { oAuth2Config.Scopes = c.StringSlice("scopes") } - if c.IsSet("attribute-ssh-public-key") { - oAuth2Config.AttributeSSHPublicKey = c.String("attribute-ssh-public-key") - } - if c.IsSet("required-claim-name") { oAuth2Config.RequiredClaimName = c.String("required-claim-name") } @@ -282,10 +267,6 @@ func (a *authService) updateOauth(ctx context.Context, c *cli.Command) error { oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal") } - if c.IsSet("allow-username-change") { - oAuth2Config.AllowUsernameChange = c.Bool("allow-username-change") - } - // update custom URL mapping customURLMapping := &oauth2.CustomURLMapping{} @@ -319,5 +300,5 @@ func (a *authService) updateOauth(ctx context.Context, c *cli.Command) error { oAuth2Config.CustomURLMapping = customURLMapping source.Cfg = oAuth2Config - return a.updateAuthSource(ctx, source) + return auth_model.UpdateSource(ctx, source) } diff --git a/cmd/admin_auth_oauth_test.go b/cmd/admin_auth_oauth_test.go deleted file mode 100644 index 3430ad1f56..0000000000 --- a/cmd/admin_auth_oauth_test.go +++ /dev/null @@ -1,706 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package cmd - -import ( - "context" - "testing" - - "forgejo.org/models/auth" - "forgejo.org/modules/test" - "forgejo.org/services/auth/source/oauth2" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/urfave/cli/v3" -) - -func TestAddOauth(t *testing.T) { - // Mock cli functions to do not exit on error - defer test.MockVariableValue(&cli.OsExiter, func(code int) {})() - - // Test cases - cases := []struct { - args []string - source *auth.Source - errMsg string - }{ - // case 0 - { - args: []string{ - "oauth-test", - "--name", "oauth2 (via openidConnect) source full", - "--provider", "openidConnect", - "--key", "client id", - "--secret", "client secret", - "--auto-discover-url", "https://example.com/.well-known/openid-configuration", - "--use-custom-urls", "", - "--custom-tenant-id", "tenant id", - "--custom-auth-url", "https://example.com/auth", - "--custom-token-url", "https://example.com/token", - "--custom-profile-url", "https://example.com/profile", - "--custom-email-url", "https://example.com/email", - "--icon-url", "https://example.com/icon.svg", - "--skip-local-2fa", - "--scopes", "address", - "--scopes", "email", - "--scopes", "phone", - "--scopes", "profile", - "--attribute-ssh-public-key", "ssh_public_key", - "--required-claim-name", "can_access", - "--required-claim-value", "yes", - "--group-claim-name", "groups", - "--admin-group", "admin", - "--restricted-group", "restricted", - "--group-team-map", `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`, - "--group-team-map-removal", - "--allow-username-change", - }, - source: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source full", - IsActive: true, - Cfg: &oauth2.Source{ - Provider: "openidConnect", - ClientID: "client id", - ClientSecret: "client secret", - OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration", - CustomURLMapping: &oauth2.CustomURLMapping{ - AuthURL: "https://example.com/auth", - TokenURL: "https://example.com/token", - ProfileURL: "https://example.com/profile", - EmailURL: "https://example.com/email", - Tenant: "tenant id", - }, - IconURL: "https://example.com/icon.svg", - Scopes: []string{"address", "email", "phone", "profile"}, - AttributeSSHPublicKey: "ssh_public_key", - RequiredClaimName: "can_access", - RequiredClaimValue: "yes", - GroupClaimName: "groups", - AdminGroup: "admin", - GroupTeamMap: `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`, - GroupTeamMapRemoval: true, - RestrictedGroup: "restricted", - SkipLocalTwoFA: true, - AllowUsernameChange: true, - }, - }, - }, - // case 1 - { - args: []string{ - "oauth-test", - "--name", "oauth2 (via openidConnect) source min", - "--provider", "openidConnect", - "--auto-discover-url", "https://example.com/.well-known/openid-configuration", - }, - source: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source min", - IsActive: true, - Cfg: &oauth2.Source{ - Provider: "openidConnect", - OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration", - Scopes: []string{}, - }, - }, - }, - // case 2 - { - args: []string{ - "oauth-test", - "--name", "oauth2 (via openidConnect) source `--use-custom-urls` required for `--custom-*` flags", - "--custom-tenant-id", "tenant id", - "--custom-auth-url", "https://example.com/auth", - "--custom-token-url", "https://example.com/token", - "--custom-profile-url", "https://example.com/profile", - "--custom-email-url", "https://example.com/email", - }, - source: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source `--use-custom-urls` required for `--custom-*` flags", - IsActive: true, - Cfg: &oauth2.Source{ - Scopes: []string{}, - }, - }, - }, - // case 3 - { - args: []string{ - "oauth-test", - "--name", "oauth2 (via openidConnect) source `--scopes` aggregates multiple uses", - "--provider", "openidConnect", - "--auto-discover-url", "https://example.com/.well-known/openid-configuration", - "--scopes", "address", - "--scopes", "email", - "--scopes", "phone", - "--scopes", "profile", - }, - source: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source `--scopes` aggregates multiple uses", - IsActive: true, - Cfg: &oauth2.Source{ - Provider: "openidConnect", - OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration", - Scopes: []string{"address", "email", "phone", "profile"}, - }, - }, - }, - // case 4 - { - args: []string{ - "oauth-test", - "--name", "oauth2 (via openidConnect) source `--scopes` supports commas as separators", - "--provider", "openidConnect", - "--auto-discover-url", "https://example.com/.well-known/openid-configuration", - "--scopes", "address,email,phone,profile", - }, - source: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source `--scopes` supports commas as separators", - IsActive: true, - Cfg: &oauth2.Source{ - Provider: "openidConnect", - OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration", - Scopes: []string{"address", "email", "phone", "profile"}, - }, - }, - }, - // case 5 - { - args: []string{ - "oauth-test", - "--name", "oauth2 (via openidConnect) source", - "--provider", "openidConnect", - }, - errMsg: "invalid Auto Discovery URL: (this must be a valid URL starting with http:// or https://)", - }, - // case 6 - { - args: []string{ - "oauth-test", - "--name", "oauth2 (via openidConnect) source", - "--provider", "openidConnect", - "--auto-discover-url", "example.com", - }, - errMsg: "invalid Auto Discovery URL: example.com (this must be a valid URL starting with http:// or https://)", - }, - } - - for n, c := range cases { - // Mock functions. - var createdAuthSource *auth.Source - service := &authService{ - initDB: func(context.Context) error { - return nil - }, - createAuthSource: func(ctx context.Context, authSource *auth.Source) error { - createdAuthSource = authSource - return nil - }, - updateAuthSource: func(ctx context.Context, authSource *auth.Source) error { - assert.FailNow(t, "should not call updateAuthSource", "case: %d", n) - return nil - }, - getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) { - assert.FailNow(t, "should not call getAuthSourceByID", "case: %d", n) - return nil, nil - }, - } - - // Create a copy of command to test - app := cli.Command{} - app.Flags = microcmdAuthAddOauth().Flags - app.Action = service.addOauth - - // Run it - err := app.Run(t.Context(), c.args) - if c.errMsg != "" { - assert.EqualError(t, err, c.errMsg, "case %d: error should match", n) - } else { - require.NoError(t, err, "case %d: should have no errors", n) - assert.Equal(t, c.source, createdAuthSource, "case %d: wrong authSource", n) - } - } -} - -func TestUpdateOauth(t *testing.T) { - // Mock cli functions to do not exit on error - defer test.MockVariableValue(&cli.OsExiter, func(code int) {})() - - // Test cases - cases := []struct { - args []string - id int64 - existingAuthSource *auth.Source - authSource *auth.Source - errMsg string - }{ - // case 0 - { - args: []string{ - "oauth-test", - "--id", "23", - "--name", "oauth2 (via openidConnect) source full", - "--provider", "openidConnect", - "--key", "client id", - "--secret", "client secret", - "--auto-discover-url", "https://example.com/.well-known/openid-configuration", - "--use-custom-urls", "", - "--custom-tenant-id", "tenant id", - "--custom-auth-url", "https://example.com/auth", - "--custom-token-url", "https://example.com/token", - "--custom-profile-url", "https://example.com/profile", - "--custom-email-url", "https://example.com/email", - "--icon-url", "https://example.com/icon.svg", - "--skip-local-2fa", - "--scopes", "address", - "--scopes", "email", - "--scopes", "phone", - "--scopes", "profile", - "--attribute-ssh-public-key", "ssh_public_key", - "--required-claim-name", "can_access", - "--required-claim-value", "yes", - "--group-claim-name", "groups", - "--admin-group", "admin", - "--restricted-group", "restricted", - "--group-team-map", `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`, - "--group-team-map-removal", - }, - id: 23, - existingAuthSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{}, - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source full", - Cfg: &oauth2.Source{ - Provider: "openidConnect", - ClientID: "client id", - ClientSecret: "client secret", - OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration", - CustomURLMapping: &oauth2.CustomURLMapping{ - AuthURL: "https://example.com/auth", - TokenURL: "https://example.com/token", - ProfileURL: "https://example.com/profile", - EmailURL: "https://example.com/email", - Tenant: "tenant id", - }, - IconURL: "https://example.com/icon.svg", - Scopes: []string{"address", "email", "phone", "profile"}, - AttributeSSHPublicKey: "ssh_public_key", - RequiredClaimName: "can_access", - RequiredClaimValue: "yes", - GroupClaimName: "groups", - AdminGroup: "admin", - GroupTeamMap: `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`, - GroupTeamMapRemoval: true, - RestrictedGroup: "restricted", - // `--skip-local-2fa` is currently ignored. - // SkipLocalTwoFA: true, - }, - }, - }, - // case 1 - { - args: []string{ - "oauth-test", - "--id", "1", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - }, - }, - }, - // case 2 - { - args: []string{ - "oauth-test", - "--id", "1", - "--name", "oauth2 (via openidConnect) source full", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source full", - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - }, - }, - }, - // case 3 - { - args: []string{ - "oauth-test", - "--id", "1", - "--provider", "openidConnect", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - Provider: "openidConnect", - CustomURLMapping: &oauth2.CustomURLMapping{}, - }, - }, - }, - // case 4 - { - args: []string{ - "oauth-test", - "--id", "1", - "--key", "client id", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - ClientID: "client id", - CustomURLMapping: &oauth2.CustomURLMapping{}, - }, - }, - }, - // case 5 - { - args: []string{ - "oauth-test", - "--id", "1", - "--secret", "client secret", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - ClientSecret: "client secret", - CustomURLMapping: &oauth2.CustomURLMapping{}, - }, - }, - }, - // case 6 - { - args: []string{ - "oauth-test", - "--id", "1", - "--auto-discover-url", "https://example.com/.well-known/openid-configuration", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration", - CustomURLMapping: &oauth2.CustomURLMapping{}, - }, - }, - }, - // case 7 - { - args: []string{ - "oauth-test", - "--id", "1", - "--use-custom-urls", "", - "--custom-tenant-id", "tenant id", - "--custom-auth-url", "https://example.com/auth", - "--custom-token-url", "https://example.com/token", - "--custom-profile-url", "https://example.com/profile", - "--custom-email-url", "https://example.com/email", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{ - AuthURL: "https://example.com/auth", - TokenURL: "https://example.com/token", - ProfileURL: "https://example.com/profile", - EmailURL: "https://example.com/email", - Tenant: "tenant id", - }, - }, - }, - }, - // case 8 - { - args: []string{ - "oauth-test", - "--id", "1", - "--name", "oauth2 (via openidConnect) source `--use-custom-urls` required for `--custom-*` flags", - "--custom-tenant-id", "tenant id", - "--custom-auth-url", "https://example.com/auth", - "--custom-token-url", "https://example.com/token", - "--custom-profile-url", "https://example.com/profile", - "--custom-email-url", "https://example.com/email", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source `--use-custom-urls` required for `--custom-*` flags", - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - }, - }, - }, - // case 9 - { - args: []string{ - "oauth-test", - "--id", "1", - "--icon-url", "https://example.com/icon.svg", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - IconURL: "https://example.com/icon.svg", - }, - }, - }, - // case 10 - { - args: []string{ - "oauth-test", - "--id", "1", - "--name", "oauth2 (via openidConnect) source `--skip-local-2fa` is currently ignored", - "--skip-local-2fa", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source `--skip-local-2fa` is currently ignored", - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - // `--skip-local-2fa` is currently ignored. - // SkipLocalTwoFA: true, - }, - }, - }, - // case 11 - { - args: []string{ - "oauth-test", - "--id", "1", - "--name", "oauth2 (via openidConnect) source `--scopes` aggregates multiple uses", - "--scopes", "address", - "--scopes", "email", - "--scopes", "phone", - "--scopes", "profile", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source `--scopes` aggregates multiple uses", - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - Scopes: []string{"address", "email", "phone", "profile"}, - }, - }, - }, - // case 12 - { - args: []string{ - "oauth-test", - "--id", "1", - "--name", "oauth2 (via openidConnect) source `--scopes` supports commas as separators", - "--scopes", "address,email,phone,profile", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Name: "oauth2 (via openidConnect) source `--scopes` supports commas as separators", - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - Scopes: []string{"address", "email", "phone", "profile"}, - }, - }, - }, - // case 13 - { - args: []string{ - "oauth-test", - "--id", "1", - "--attribute-ssh-public-key", "ssh_public_key", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - AttributeSSHPublicKey: "ssh_public_key", - }, - }, - }, - // case 14 - { - args: []string{ - "oauth-test", - "--id", "1", - "--required-claim-name", "can_access", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - RequiredClaimName: "can_access", - }, - }, - }, - // case 15 - { - args: []string{ - "oauth-test", - "--id", "1", - "--required-claim-value", "yes", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - RequiredClaimValue: "yes", - }, - }, - }, - // case 16 - { - args: []string{ - "oauth-test", - "--id", "1", - "--group-claim-name", "groups", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - GroupClaimName: "groups", - }, - }, - }, - // case 17 - { - args: []string{ - "oauth-test", - "--id", "1", - "--admin-group", "admin", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - AdminGroup: "admin", - }, - }, - }, - // case 18 - { - args: []string{ - "oauth-test", - "--id", "1", - "--restricted-group", "restricted", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - RestrictedGroup: "restricted", - }, - }, - }, - // case 19 - { - args: []string{ - "oauth-test", - "--id", "1", - "--group-team-map", `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`, - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - GroupTeamMap: `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`, - }, - }, - }, - // case 20 - { - args: []string{ - "oauth-test", - "--id", "1", - "--group-team-map-removal", - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - GroupTeamMapRemoval: true, - }, - }, - }, - // case 21 - { - args: []string{ - "oauth-test", - "--id", "23", - "--group-team-map-removal=false", - }, - id: 23, - existingAuthSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - GroupTeamMapRemoval: true, - }, - }, - authSource: &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{ - CustomURLMapping: &oauth2.CustomURLMapping{}, - GroupTeamMapRemoval: false, - }, - }, - }, - // case 22 - { - args: []string{ - "oauth-test", - }, - errMsg: "--id flag is missing", - }, - } - - for n, c := range cases { - // Mock functions. - var updatedAuthSource *auth.Source - service := &authService{ - initDB: func(context.Context) error { - return nil - }, - createAuthSource: func(ctx context.Context, authSource *auth.Source) error { - assert.FailNow(t, "should not call createAuthSource", "case: %d", n) - return nil - }, - updateAuthSource: func(ctx context.Context, authSource *auth.Source) error { - updatedAuthSource = authSource - return nil - }, - getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) { - if c.id != 0 { - assert.Equal(t, c.id, id, "case %d: wrong id", n) - } - if c.existingAuthSource != nil { - return c.existingAuthSource, nil - } - return &auth.Source{ - Type: auth.OAuth2, - Cfg: &oauth2.Source{}, - }, nil - }, - } - - // Create a copy of command to test - app := cli.Command{} - app.Flags = microcmdAuthUpdateOauth().Flags - app.Action = service.updateOauth - - // Run it - err := app.Run(t.Context(), c.args) - if c.errMsg != "" { - assert.EqualError(t, err, c.errMsg, "case %d: error should match", n) - } else { - require.NoError(t, err, "case %d: should have no errors", n) - assert.Equal(t, c.authSource, updatedAuthSource, "case %d: wrong authSource", n) - } - } -} diff --git a/cmd/dump.go b/cmd/dump.go index ea141291f5..cb01e74196 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -8,12 +8,11 @@ import ( "context" "errors" "fmt" - "io/fs" + "io" "os" "path" "path/filepath" "strings" - "sync" "time" "forgejo.org/models/db" @@ -24,43 +23,36 @@ import ( "forgejo.org/modules/util" "code.forgejo.org/go-chi/session" - "github.com/mholt/archives" + "github.com/mholt/archiver/v3" "github.com/urfave/cli/v3" ) -func addObject(archiveJobs chan archives.ArchiveAsyncJob, object fs.File, customName string, verbose bool) error { +func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error { if verbose { log.Info("Adding file %s", customName) } - info, err := object.Stat() - if err != nil { - return err - } - - ch := make(chan error) - - archiveJobs <- archives.ArchiveAsyncJob{ - File: archives.FileInfo{ - FileInfo: info, - NameInArchive: customName, - Open: func() (fs.File, error) { - return object, nil - }, + return w.Write(archiver.File{ + FileInfo: archiver.FileInfo{ + FileInfo: info, + CustomName: customName, }, - Result: ch, - } - - return <-ch + ReadCloser: r, + }) } -func addFile(archiveJobs chan archives.ArchiveAsyncJob, filePath, absPath string, verbose bool) error { - file, err := os.Open(absPath) // Closed by archiver +func addFile(w archiver.Writer, filePath, absPath string, verbose bool) error { + file, err := os.Open(absPath) + if err != nil { + return err + } + defer file.Close() + fileInfo, err := file.Stat() if err != nil { return err } - return addObject(archiveJobs, file, filePath, verbose) + return addReader(w, file, fileInfo, filePath, verbose) } func isSubdir(upper, lower string) (bool, error) { @@ -109,54 +101,6 @@ var outputTypeEnum = &outputType{ Default: "zip", } -func getArchiverByType(outType string) (archives.ArchiverAsync, error) { - var archiver archives.ArchiverAsync - switch outType { - case "zip": - archiver = archives.Zip{} - case "tar": - archiver = archives.Tar{} - case "tar.sz": - archiver = archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Sz{}, - } - case "tar.gz": - archiver = archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Gz{}, - } - case "tar.xz": - archiver = archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Xz{}, - } - case "tar.bz2": - archiver = archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Bz2{}, - } - case "tar.br": - archiver = archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Brotli{}, - } - case "tar.lz4": - archiver = archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Lz4{}, - } - case "tar.zst": - archiver = archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Zstd{}, - } - default: - return nil, fmt.Errorf("unsupported output type: %s", outType) - } - return archiver, nil -} - // CmdDump represents the available dump sub-command. func cmdDump() *cli.Command { return &cli.Command{ @@ -310,185 +254,46 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error { return err } - archiveJobs := make(chan archives.ArchiveAsyncJob) - wg := sync.WaitGroup{} - archiver, err := getArchiverByType(outType) + var iface any + if fileName == "-" { + iface, err = archiver.ByExtension(fmt.Sprintf(".%s", outType)) + } else { + iface, err = archiver.ByExtension(fileName) + } if err != nil { fatal("Failed to get archiver for extension: %v", err) } + w, _ := iface.(archiver.Writer) + if err := w.Create(file); err != nil { + fatal("Creating archiver.Writer failed: %v", err) + } + defer w.Close() + if ctx.IsSet("skip-repository") && ctx.Bool("skip-repository") { log.Info("Skipping local repositories") } else { log.Info("Dumping local repositories... %s", setting.RepoRootPath) - wg.Add(1) - go dumpRepos(ctx, archiveJobs, &wg, absFileName, verbose) - } + if err := addRecursiveExclude(w, "repos", setting.RepoRootPath, []string{absFileName}, verbose); err != nil { + fatal("Failed to include repositories: %v", err) + } - wg.Add(1) - go dumpDatabase(ctx, archiveJobs, &wg, verbose) - - if len(setting.CustomConf) > 0 { - wg.Add(1) - go func() { - defer wg.Done() - log.Info("Adding custom configuration file from %s", setting.CustomConf) - if err := addFile(archiveJobs, "app.ini", setting.CustomConf, verbose); err != nil { - fatal("Failed to include specified app.ini: %v", err) + if ctx.IsSet("skip-lfs-data") && ctx.Bool("skip-lfs-data") { + log.Info("Skipping LFS data") + } else if !setting.LFS.StartServer { + log.Info("LFS not enabled - skipping") + } else if err := storage.LFS.IterateObjects("", func(objPath string, object storage.Object) error { + info, err := object.Stat() + if err != nil { + return err } - }() - } - if ctx.IsSet("skip-custom-dir") && ctx.Bool("skip-custom-dir") { - log.Info("Skipping custom directory") - } else { - wg.Add(1) - go dumpCustom(archiveJobs, &wg, absFileName, verbose) - } - - isExist, err := util.IsExist(setting.AppDataPath) - if err != nil { - log.Error("Failed to check if %s exists: %v", setting.AppDataPath, err) - } - if isExist { - log.Info("Packing data directory...%s", setting.AppDataPath) - - wg.Add(1) - go dumpData(ctx, archiveJobs, &wg, absFileName, verbose) - } - - if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") { - log.Info("Skipping attachment data") - } else { - wg.Add(1) - go func() { - defer wg.Done() - if err := storage.Attachments.IterateObjects("", func(objPath string, object storage.Object) error { - return addObject(archiveJobs, object, path.Join("data", "attachments", objPath), verbose) - }); err != nil { - fatal("Failed to dump attachments: %v", err) - } - }() - } - - if ctx.IsSet("skip-package-data") && ctx.Bool("skip-package-data") { - log.Info("Skipping package data") - } else if !setting.Packages.Enabled { - log.Info("Package registry not enabled - skipping") - } else { - wg.Add(1) - go func() { - defer wg.Done() - if err := storage.Packages.IterateObjects("", func(objPath string, object storage.Object) error { - return addObject(archiveJobs, object, path.Join("data", "packages", objPath), verbose) - }); err != nil { - fatal("Failed to dump packages: %v", err) - } - }() - } - - // Doesn't check if LogRootPath exists before processing --skip-log intentionally, - // ensuring that it's clear the dump is skipped whether the directory's initialized - // yet or not. - if ctx.IsSet("skip-log") && ctx.Bool("skip-log") { - log.Info("Skipping log files") - } else { - isExist, err := util.IsExist(setting.Log.RootPath) - if err != nil { - log.Error("Failed to check if %s exists: %v", setting.Log.RootPath, err) - } - if isExist { - wg.Add(1) - go func() { - defer wg.Done() - if err := addRecursiveExclude(archiveJobs, "log", setting.Log.RootPath, []string{absFileName}, verbose); err != nil { - fatal("Failed to include log: %v", err) - } - }() + return addReader(w, object, info, path.Join("data", "lfs", objPath), verbose) + }); err != nil { + fatal("Failed to dump LFS objects: %v", err) } } - // Wait for all jobs to finish before closing the channel - // ArchiveAsync will only return after the channel is closed - go func() { - wg.Wait() - close(archiveJobs) - }() - - if err := archiver.ArchiveAsync(stdCtx, file, archiveJobs); err != nil { - _ = util.Remove(fileName) - - fatal("Archiving failed: %v", err) - } - - if fileName != "-" { - if err := os.Chmod(fileName, 0o600); err != nil { - log.Info("Can't change file access permissions mask to 0600: %v", err) - } - - log.Info("Finished dumping in file %s", fileName) - } else { - log.Info("Finished dumping to stdout") - } - - return nil -} - -func dumpData(ctx *cli.Command, archiveJobs chan archives.ArchiveAsyncJob, wg *sync.WaitGroup, absFileName string, verbose bool) { - defer wg.Done() - - var excludes []string - if setting.SessionConfig.OriginalProvider == "file" { - var opts session.Options - if err := json.Unmarshal([]byte(setting.SessionConfig.ProviderConfig), &opts); err != nil { - fatal("Failed to parse session config: %v", err) - } - excludes = append(excludes, opts.ProviderConfig) - } - - if ctx.IsSet("skip-index") && ctx.Bool("skip-index") { - log.Info("Skipping bleve index data") - excludes = append(excludes, setting.Indexer.RepoPath) - excludes = append(excludes, setting.Indexer.IssuePath) - } - - if ctx.IsSet("skip-repo-archives") && ctx.Bool("skip-repo-archives") { - log.Info("Skipping repository archives data") - excludes = append(excludes, setting.RepoArchive.Storage.Path) - } - - excludes = append(excludes, setting.RepoRootPath) - excludes = append(excludes, setting.LFS.Storage.Path) - excludes = append(excludes, setting.Attachment.Storage.Path) - excludes = append(excludes, setting.Packages.Storage.Path) - excludes = append(excludes, setting.Log.RootPath) - excludes = append(excludes, absFileName) - if err := addRecursiveExclude(archiveJobs, "data", setting.AppDataPath, excludes, verbose); err != nil { - fatal("Failed to include data directory: %v", err) - } -} - -func dumpCustom(archiveJobs chan archives.ArchiveAsyncJob, wg *sync.WaitGroup, absFileName string, verbose bool) { - defer wg.Done() - - customDir, err := os.Stat(setting.CustomPath) - if err == nil && customDir.IsDir() { - if is, _ := isSubdir(setting.AppDataPath, setting.CustomPath); !is { - if err := addRecursiveExclude(archiveJobs, "custom", setting.CustomPath, []string{absFileName}, verbose); err != nil { - fatal("Failed to include custom: %v", err) - } - } else { - log.Info("Custom dir %s is inside data dir %s, skipping", setting.CustomPath, setting.AppDataPath) - } - } else { - log.Info("Custom dir %s does not exist, skipping", setting.CustomPath) - } -} - -func dumpDatabase(ctx *cli.Command, archiveJobs chan archives.ArchiveAsyncJob, wg *sync.WaitGroup, verbose bool) { - defer wg.Done() - - var err error tmpDir := ctx.String("tempdir") if tmpDir == "" { tmpDir, err = os.MkdirTemp("", "forgejo-dump-*") @@ -529,32 +334,139 @@ func dumpDatabase(ctx *cli.Command, archiveJobs chan archives.ArchiveAsyncJob, w fatal("Failed to dump database: %v", err) } - if err := addFile(archiveJobs, "forgejo-db.sql", dbDump.Name(), verbose); err != nil { + if err := addFile(w, "forgejo-db.sql", dbDump.Name(), verbose); err != nil { fatal("Failed to include forgejo-db.sql: %v", err) } -} -func dumpRepos(ctx *cli.Command, archiveJobs chan archives.ArchiveAsyncJob, wg *sync.WaitGroup, absFileName string, verbose bool) { - defer wg.Done() - - if err := addRecursiveExclude(archiveJobs, "repos", setting.RepoRootPath, []string{absFileName}, verbose); err != nil { - fatal("Failed to include repositories: %v", err) + if len(setting.CustomConf) > 0 { + log.Info("Adding custom configuration file from %s", setting.CustomConf) + if err := addFile(w, "app.ini", setting.CustomConf, verbose); err != nil { + fatal("Failed to include specified app.ini: %v", err) + } } - if ctx.IsSet("skip-lfs-data") && ctx.Bool("skip-lfs-data") { - log.Info("Skipping LFS data") - } else if !setting.LFS.StartServer { - log.Info("LFS not enabled - skipping") - } else if err := storage.LFS.IterateObjects("", func(objPath string, object storage.Object) error { - return addObject(archiveJobs, object, path.Join("data", "lfs", objPath), verbose) + if ctx.IsSet("skip-custom-dir") && ctx.Bool("skip-custom-dir") { + log.Info("Skipping custom directory") + } else { + customDir, err := os.Stat(setting.CustomPath) + if err == nil && customDir.IsDir() { + if is, _ := isSubdir(setting.AppDataPath, setting.CustomPath); !is { + if err := addRecursiveExclude(w, "custom", setting.CustomPath, []string{absFileName}, verbose); err != nil { + fatal("Failed to include custom: %v", err) + } + } else { + log.Info("Custom dir %s is inside data dir %s, skipping", setting.CustomPath, setting.AppDataPath) + } + } else { + log.Info("Custom dir %s does not exist, skipping", setting.CustomPath) + } + } + + isExist, err := util.IsExist(setting.AppDataPath) + if err != nil { + log.Error("Failed to check if %s exists: %v", setting.AppDataPath, err) + } + if isExist { + log.Info("Packing data directory...%s", setting.AppDataPath) + + var excludes []string + if setting.SessionConfig.OriginalProvider == "file" { + var opts session.Options + if err = json.Unmarshal([]byte(setting.SessionConfig.ProviderConfig), &opts); err != nil { + return err + } + excludes = append(excludes, opts.ProviderConfig) + } + + if ctx.IsSet("skip-index") && ctx.Bool("skip-index") { + log.Info("Skipping bleve index data") + excludes = append(excludes, setting.Indexer.RepoPath) + excludes = append(excludes, setting.Indexer.IssuePath) + } + + if ctx.IsSet("skip-repo-archives") && ctx.Bool("skip-repo-archives") { + log.Info("Skipping repository archives data") + excludes = append(excludes, setting.RepoArchive.Storage.Path) + } + + excludes = append(excludes, setting.RepoRootPath) + excludes = append(excludes, setting.LFS.Storage.Path) + excludes = append(excludes, setting.Attachment.Storage.Path) + excludes = append(excludes, setting.Packages.Storage.Path) + excludes = append(excludes, setting.Log.RootPath) + excludes = append(excludes, absFileName) + if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil { + fatal("Failed to include data directory: %v", err) + } + } + + if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") { + log.Info("Skipping attachment data") + } else if err := storage.Attachments.IterateObjects("", func(objPath string, object storage.Object) error { + info, err := object.Stat() + if err != nil { + return err + } + + return addReader(w, object, info, path.Join("data", "attachments", objPath), verbose) }); err != nil { - fatal("Failed to dump LFS objects: %v", err) + fatal("Failed to dump attachments: %v", err) } + + if ctx.IsSet("skip-package-data") && ctx.Bool("skip-package-data") { + log.Info("Skipping package data") + } else if !setting.Packages.Enabled { + log.Info("Package registry not enabled - skipping") + } else if err := storage.Packages.IterateObjects("", func(objPath string, object storage.Object) error { + info, err := object.Stat() + if err != nil { + return err + } + + return addReader(w, object, info, path.Join("data", "packages", objPath), verbose) + }); err != nil { + fatal("Failed to dump packages: %v", err) + } + + // Doesn't check if LogRootPath exists before processing --skip-log intentionally, + // ensuring that it's clear the dump is skipped whether the directory's initialized + // yet or not. + if ctx.IsSet("skip-log") && ctx.Bool("skip-log") { + log.Info("Skipping log files") + } else { + isExist, err := util.IsExist(setting.Log.RootPath) + if err != nil { + log.Error("Failed to check if %s exists: %v", setting.Log.RootPath, err) + } + if isExist { + if err := addRecursiveExclude(w, "log", setting.Log.RootPath, []string{absFileName}, verbose); err != nil { + fatal("Failed to include log: %v", err) + } + } + } + + if fileName != "-" { + if err = w.Close(); err != nil { + _ = util.Remove(fileName) + fatal("Failed to save %s: %v", fileName, err) + } + + if err := os.Chmod(fileName, 0o600); err != nil { + log.Info("Can't change file access permissions mask to 0600: %v", err) + } + } + + if fileName != "-" { + log.Info("Finish dumping in file %s", fileName) + } else { + log.Info("Finish dumping to stdout") + } + + return nil } // addRecursiveExclude zips absPath to specified insidePath inside writer excluding excludeAbsPath -// archives.FilesFromDisk doesn't support excluding files, so we have to do it manually -func addRecursiveExclude(archiveJobs chan archives.ArchiveAsyncJob, insidePath, absPath string, excludeAbsPath []string, verbose bool) error { +func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeAbsPath []string, verbose bool) error { absPath, err := filepath.Abs(absPath) if err != nil { return err @@ -579,11 +491,10 @@ func addRecursiveExclude(archiveJobs chan archives.ArchiveAsyncJob, insidePath, } if file.IsDir() { - if err := addFile(archiveJobs, currentInsidePath, currentAbsPath, false); err != nil { + if err := addFile(w, currentInsidePath, currentAbsPath, false); err != nil { return err } - - if err := addRecursiveExclude(archiveJobs, currentInsidePath, currentAbsPath, excludeAbsPath, verbose); err != nil { + if err = addRecursiveExclude(w, currentInsidePath, currentAbsPath, excludeAbsPath, verbose); err != nil { return err } } else { @@ -601,7 +512,7 @@ func addRecursiveExclude(archiveJobs chan archives.ArchiveAsyncJob, insidePath, shouldAdd = targetStat.Mode().IsRegular() } if shouldAdd { - if err := addFile(archiveJobs, currentInsidePath, currentAbsPath, verbose); err != nil { + if err = addFile(w, currentInsidePath, currentAbsPath, verbose); err != nil { return err } } diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go index 7159d55e99..eb89273e7f 100644 --- a/cmd/dump_repo.go +++ b/cmd/dump_repo.go @@ -82,11 +82,6 @@ wiki, issues, labels, releases, release_assets, milestones, pull_requests, comme } func runDumpRepository(stdCtx context.Context, ctx *cli.Command) error { - setupConsoleLogger(log.INFO, log.CanColorStderr, os.Stderr) - - // setting.DisableLoggerInit() - setting.LoadSettings() // cannot access skip_tls_verify settings otherwise - stdCtx, cancel := installSignals(stdCtx) defer cancel() diff --git a/cmd/dump_test.go b/cmd/dump_test.go index 3bdd9d68f8..459386318f 100644 --- a/cmd/dump_test.go +++ b/cmd/dump_test.go @@ -4,32 +4,40 @@ package cmd import ( + "io" "os" "testing" - "github.com/mholt/archives" + "github.com/mholt/archiver/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func mockArchiverAsync(ch chan archives.ArchiveAsyncJob, files *[]string) { - for job := range ch { - *files = append(*files, job.File.NameInArchive) - job.Result <- nil - } +type mockArchiver struct { + addedFiles []string +} + +func (mockArchiver) Create(out io.Writer) error { + return nil +} + +func (m *mockArchiver) Write(f archiver.File) error { + m.addedFiles = append(m.addedFiles, f.Name()) + return nil +} + +func (mockArchiver) Close() error { + return nil } func TestAddRecursiveExclude(t *testing.T) { t.Run("Empty", func(t *testing.T) { - ch := make(chan archives.ArchiveAsyncJob) - var files []string - go mockArchiverAsync(ch, &files) - dir := t.TempDir() + archiver := &mockArchiver{} - err := addRecursiveExclude(ch, "", dir, []string{}, false) + err := addRecursiveExclude(archiver, "", dir, []string{}, false) require.NoError(t, err) - assert.Empty(t, files) + assert.Empty(t, archiver.addedFiles) }) t.Run("Single file", func(t *testing.T) { @@ -38,25 +46,20 @@ func TestAddRecursiveExclude(t *testing.T) { require.NoError(t, err) t.Run("No exclude", func(t *testing.T) { - ch := make(chan archives.ArchiveAsyncJob) - var files []string - go mockArchiverAsync(ch, &files) + archiver := &mockArchiver{} - err := addRecursiveExclude(ch, "", dir, nil, false) + err = addRecursiveExclude(archiver, "", dir, nil, false) require.NoError(t, err) - - assert.Len(t, files, 1) - assert.Contains(t, files, "example") + assert.Len(t, archiver.addedFiles, 1) + assert.Contains(t, archiver.addedFiles, "example") }) t.Run("With exclude", func(t *testing.T) { - ch := make(chan archives.ArchiveAsyncJob) - var files []string - go mockArchiverAsync(ch, &files) + archiver := &mockArchiver{} - err := addRecursiveExclude(ch, "", dir, []string{dir + "/example"}, false) + err = addRecursiveExclude(archiver, "", dir, []string{dir + "/example"}, false) require.NoError(t, err) - assert.Empty(t, files) + assert.Empty(t, archiver.addedFiles) }) }) @@ -70,57 +73,46 @@ func TestAddRecursiveExclude(t *testing.T) { require.NoError(t, err) t.Run("No exclude", func(t *testing.T) { - ch := make(chan archives.ArchiveAsyncJob) - var files []string - go mockArchiverAsync(ch, &files) + archiver := &mockArchiver{} - err := addRecursiveExclude(ch, "", dir, nil, false) + err = addRecursiveExclude(archiver, "", dir, nil, false) require.NoError(t, err) - assert.Len(t, files, 5) - - assert.Contains(t, files, "deep") - assert.Contains(t, files, "deep/nested") - assert.Contains(t, files, "deep/nested/folder") - assert.Contains(t, files, "deep/nested/folder/example") - assert.Contains(t, files, "deep/nested/folder/another-file") + assert.Len(t, archiver.addedFiles, 5) + assert.Contains(t, archiver.addedFiles, "deep") + assert.Contains(t, archiver.addedFiles, "deep/nested") + assert.Contains(t, archiver.addedFiles, "deep/nested/folder") + assert.Contains(t, archiver.addedFiles, "deep/nested/folder/example") + assert.Contains(t, archiver.addedFiles, "deep/nested/folder/another-file") }) t.Run("Exclude first directory", func(t *testing.T) { - ch := make(chan archives.ArchiveAsyncJob) - var files []string - go mockArchiverAsync(ch, &files) + archiver := &mockArchiver{} - err := addRecursiveExclude(ch, "", dir, []string{dir + "/deep"}, false) + err = addRecursiveExclude(archiver, "", dir, []string{dir + "/deep"}, false) require.NoError(t, err) - assert.Empty(t, files) + assert.Empty(t, archiver.addedFiles) }) t.Run("Exclude nested directory", func(t *testing.T) { - ch := make(chan archives.ArchiveAsyncJob) - var files []string - go mockArchiverAsync(ch, &files) + archiver := &mockArchiver{} - err := addRecursiveExclude(ch, "", dir, []string{dir + "/deep/nested/folder"}, false) + err = addRecursiveExclude(archiver, "", dir, []string{dir + "/deep/nested/folder"}, false) require.NoError(t, err) - assert.Len(t, files, 2) - - assert.Contains(t, files, "deep") - assert.Contains(t, files, "deep/nested") + assert.Len(t, archiver.addedFiles, 2) + assert.Contains(t, archiver.addedFiles, "deep") + assert.Contains(t, archiver.addedFiles, "deep/nested") }) t.Run("Exclude file", func(t *testing.T) { - ch := make(chan archives.ArchiveAsyncJob) - var files []string - go mockArchiverAsync(ch, &files) + archiver := &mockArchiver{} - err := addRecursiveExclude(ch, "", dir, []string{dir + "/deep/nested/folder/example"}, false) + err = addRecursiveExclude(archiver, "", dir, []string{dir + "/deep/nested/folder/example"}, false) require.NoError(t, err) - assert.Len(t, files, 4) - - assert.Contains(t, files, "deep") - assert.Contains(t, files, "deep/nested") - assert.Contains(t, files, "deep/nested/folder") - assert.Contains(t, files, "deep/nested/folder/another-file") + assert.Len(t, archiver.addedFiles, 4) + assert.Contains(t, archiver.addedFiles, "deep") + assert.Contains(t, archiver.addedFiles, "deep/nested") + assert.Contains(t, archiver.addedFiles, "deep/nested/folder") + assert.Contains(t, archiver.addedFiles, "deep/nested/folder/another-file") }) }) } diff --git a/cmd/hook.go b/cmd/hook.go index 7378dc21ad..909cdfdf84 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -231,6 +231,8 @@ Forgejo or set your environment appropriately.`, "") } } + supportProcReceive := git.CheckGitVersionAtLeast("2.29") == nil + for scanner.Scan() { // TODO: support news feeds for wiki if isWiki { @@ -248,25 +250,31 @@ Forgejo or set your environment appropriately.`, "") total++ lastline++ - // All references should be checked because permission check was delayed. - oldCommitIDs[count] = oldCommitID - newCommitIDs[count] = newCommitID - refFullNames[count] = refFullName - count++ - fmt.Fprint(out, "*") + // If the ref is a branch or tag, check if it's protected + // if supportProcReceive all ref should be checked because + // permission check was delayed + if supportProcReceive || refFullName.IsBranch() || refFullName.IsTag() { + oldCommitIDs[count] = oldCommitID + newCommitIDs[count] = newCommitID + refFullNames[count] = refFullName + count++ + fmt.Fprint(out, "*") - if count >= hookBatchSize { - fmt.Fprintf(out, " Checking %d references\n", count) + if count >= hookBatchSize { + fmt.Fprintf(out, " Checking %d references\n", count) - hookOptions.OldCommitIDs = oldCommitIDs - hookOptions.NewCommitIDs = newCommitIDs - hookOptions.RefFullNames = refFullNames - extra := private.HookPreReceive(ctx, username, reponame, hookOptions) - if extra.HasError() { - return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error) + hookOptions.OldCommitIDs = oldCommitIDs + hookOptions.NewCommitIDs = newCommitIDs + hookOptions.RefFullNames = refFullNames + extra := private.HookPreReceive(ctx, username, reponame, hookOptions) + if extra.HasError() { + return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error) + } + count = 0 + lastline = 0 } - count = 0 - lastline = 0 + } else { + fmt.Fprint(out, ".") } if lastline >= hookBatchSize { fmt.Fprint(out, "\n") @@ -505,6 +513,10 @@ Forgejo or set your environment appropriately.`, "") return nil } + if git.CheckGitVersionAtLeast("2.29") != nil { + return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.") + } + reader := bufio.NewReader(os.Stdin) repoUser := os.Getenv(repo_module.EnvRepoUsername) repoName := os.Getenv(repo_module.EnvRepoName) diff --git a/cmd/manager_logging.go b/cmd/manager_logging.go index c18bfa919b..c543afe872 100644 --- a/cmd/manager_logging.go +++ b/cmd/manager_logging.go @@ -44,11 +44,6 @@ func defaultLoggingFlags() []cli.Flag { Aliases: []string{"e"}, Usage: "Matching expression for the logger", }, - &cli.StringFlag{ - Name: "exclusion", - Aliases: []string{"x"}, - Usage: "Exclusion for the logger", - }, &cli.StringFlag{ Name: "prefix", Aliases: []string{"p"}, @@ -291,9 +286,6 @@ func commonAddLogger(ctx context.Context, c *cli.Command, mode string, vals map[ if len(c.String("expression")) > 0 { vals["expression"] = c.String("expression") } - if len(c.String("exclusion")) > 0 { - vals["exclusion"] = c.String("exclusion") - } if len(c.String("prefix")) > 0 { vals["prefix"] = c.String("prefix") } diff --git a/cmd/serv.go b/cmd/serv.go index 0e0551d297..1fac2d13f5 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -88,14 +88,6 @@ var ( alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`) ) -func sshLog(ctx context.Context, level log.Level, message string) error { - if testing.Testing() || setting.InternalToken == "" { - return nil - } - - return private.SSHLog(ctx, level, message) -} - // fail prints message to stdout, it's mainly used for git serv and git hook commands. // The output will be passed to git client and shown to user. func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error { @@ -120,7 +112,10 @@ func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error logMsg = userMessage + ". " + logMsg } } - _ = sshLog(ctx, log.ERROR, logMsg) + // Don't send an log if this is done in a test and no InternalToken is set. + if !testing.Testing() || setting.InternalToken != "" { + _ = private.SSHLog(ctx, true, logMsg) + } } return cli.Exit("", 1) } @@ -198,10 +193,12 @@ func runServ(ctx context.Context, c *cli.Command) error { } if len(words) < 2 { - // for AGit Flow - if cmd == "ssh_info" { - fmt.Print(`{"type":"agit","version":1}`) - return nil + if git.CheckGitVersionAtLeast("2.29") == nil { + // for AGit Flow + if cmd == "ssh_info" { + fmt.Print(`{"type":"agit","version":1}`) + return nil + } } return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd) } diff --git a/contrib/coverage-helper.sh b/contrib/coverage-helper.sh deleted file mode 100755 index ec9f5469ea..0000000000 --- a/contrib/coverage-helper.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -set -e -#set -x -PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: ' - -# -# Those must be explicitly required and are excluded from the full list of packages because they -# would interfere with the testing fixtures. -# -excluded+='forgejo.org/models/migrations|' # must be run before database specific tests -excluded+='forgejo.org/models/forgejo_migrations|' # must be run before database specific tests -excluded+='forgejo.org/tests/integration/migration-test|' # must be run before database specific tests -excluded+='forgejo.org/tests|' # only tests, no coverage to get there -excluded+='forgejo.org/tests/e2e|' # JavaScript is not in scope here and if it adds coverage it should not be counted -excluded+='FAKETERMINATOR' # do not modify - -: ${COVERAGEDIR:=$(pwd)/coverage/data} -: ${GO:=$(go env GOROOT)/bin/go} - -DEFAULT_TEST_PACKAGES=$($GO list ./... | grep -E -v "$excluded") - -COVERED_PACKAGES=$($GO list ./...) -COVERED_PACKAGES=$(echo $COVERED_PACKAGES | sed -e 's/ /,/g') - -function run_test() { - local package="$1" - if echo "$package" | grep --quiet --fixed-string ".."; then - echo "$package contains a suspicious .." - return 1 - fi - - local coverage="$COVERAGEDIR/$COVERAGE_TEST_DATABASE/$package" - rm -fr $coverage - mkdir -p $coverage - - # - # -race cannot be used because it requires -covermode atomic which is - # different from the end-to-end tests and would cause issues wen merging - # - $GO test -timeout=20m -tags='sqlite sqlite_unlock_notify' -cover $package -coverpkg $COVERED_PACKAGES $COVERAGE_TEST_ARGS -args -test.gocoverdir=$coverage |& grep -v 'warning: no packages being tested depend on matches for pattern' -} - -function test_packages() { - for package in ${@:-$DEFAULT_TEST_PACKAGES}; do - run_test $package - done -} - -"$@" diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 6c8c85b87c..1b8d4c6697 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -449,9 +449,6 @@ INTERNAL_TOKEN = ;; How long to remember that a user is logged in before requiring relogin (in days) ;LOGIN_REMEMBER_DAYS = 31 ;; -;; Require 2FA globally for none|all|admin. -;GLOBAL_TWO_FACTOR_REQUIREMENT = none -;; ;; Name of cookie used to store authentication information. ;COOKIE_REMEMBER_NAME = gitea_incredible ;; @@ -595,10 +592,13 @@ LEVEL = Info ;BUFFER_LEN = 10000 ;; ;; Sub logger modes, a single comma means use default MODE above, empty means disable it -;LOGGER_ACCESS_MODE= -;LOGGER_ROUTER_MODE=, -;LOGGER_XORM_MODE=, -;LOGGER_SSH_MODE= ;; SSH logs from ssh git request +;logger.access.MODE= +;logger.router.MODE=, +;logger.xorm.MODE=, +;; +;; Collect SSH logs (Creates log from ssh git request) +;; +;ENABLE_SSH_LOG = false ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; @@ -631,7 +631,6 @@ LEVEL = Info ;LEVEL= ;FLAGS = stdflags or journald ;EXPRESSION = -;EXCLUSION = ;PREFIX = ;COLORIZE = false ;; @@ -1586,11 +1585,6 @@ LEVEL = Info ;; If enabled it will be possible for users to report abusive content (new actions are added in the UI and /report_abuse route will be enabled) and a new Moderation section will be added to Admin settings where the reports can be reviewed. ;ENABLED = false -;; How long to keep resolved abuse reports for. -;; Applies to reports that have been marked as ignored or handled -;; Can be 1 hour, 7 days etc -;KEEP_RESOLVED_REPORTS_FOR = 0 - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[openid] @@ -1773,9 +1767,6 @@ LEVEL = Info ;; Use PASSWD = `your password` for quoting if you use special characters in the password. ;PASSWD = ;; -;; Alternative location to specify mailer password. You cannot specify both this and PASSWD, and must pick one -;PASSWD_URI = file:/etc/forgejo/mailer_passwd -;; ;; Send mails only in plain text, without HTML alternative ;SEND_AS_PLAIN_TEXT = false ;; @@ -1828,9 +1819,6 @@ LEVEL = Info ;; Password of the receiving account ;PASSWORD = ;; -;; Alternative location to specify password of the receiving account. You cannot specify both this and PASSWORD, and must pick one -;PASSWORD_URI = file:/etc/forgejo/email_incoming_password -;; ;; Whether the IMAP server uses TLS. ;USE_TLS = false ;; diff --git a/eslint.config.mjs b/eslint.config.mjs index 83a6b6bee1..28cfa80089 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -153,7 +153,7 @@ export default tseslint.config( '@stylistic/quotes': [2, 'single', { avoidEscape: true, - allowTemplateLiterals: 'always', + allowTemplateLiterals: true, }], '@stylistic/rest-spread-spacing': [2, 'never'], @@ -799,7 +799,6 @@ export default tseslint.config( 'unicorn/prefer-array-some': [2], 'unicorn/prefer-at': [0], 'unicorn/prefer-blob-reading-methods': [2], - 'unicorn/prefer-classlist-toggle': [2], 'unicorn/prefer-code-point': [0], 'unicorn/prefer-date-now': [2], 'unicorn/prefer-default-parameters': [0], diff --git a/go.mod b/go.mod index fcb20601e4..bb2be827eb 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module forgejo.org -go 1.24.0 +go 1.24 -toolchain go1.24.7 +toolchain go1.24.4 require ( code.forgejo.org/f3/gof3/v3 v3.11.0 @@ -10,7 +10,6 @@ require ( code.forgejo.org/forgejo/go-rpmutils v1.0.0 code.forgejo.org/forgejo/levelqueue v1.0.0 code.forgejo.org/forgejo/reply v1.0.2 - code.forgejo.org/forgejo/runner/v11 v11.0.0 code.forgejo.org/go-chi/binding v1.0.1 code.forgejo.org/go-chi/cache v1.0.1 code.forgejo.org/go-chi/captcha v1.0.2 @@ -25,11 +24,11 @@ require ( github.com/ProtonMail/go-crypto v1.3.0 github.com/PuerkitoBio/goquery v1.10.3 github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 - github.com/alecthomas/chroma/v2 v2.20.0 + github.com/alecthomas/chroma/v2 v2.18.0 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blevesearch/bleve/v2 v2.5.2 github.com/buildkite/terminal-to-html/v3 v3.16.8 - github.com/caddyserver/certmagic v0.24.0 + github.com/caddyserver/certmagic v0.23.0 github.com/chi-middleware/proxy v1.1.1 github.com/djherbis/buffer v1.2.0 github.com/djherbis/nio/v3 v3.0.1 @@ -41,44 +40,46 @@ require ( github.com/fsnotify/fsnotify v1.9.0 github.com/gliderlabs/ssh v0.3.8 github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 - github.com/go-ap/jsonld v0.0.0-20250905102310-8480b0fe24d9 - github.com/go-chi/chi/v5 v5.2.3 - github.com/go-chi/cors v1.2.2 + github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 + github.com/go-chi/chi/v5 v5.2.2 + github.com/go-chi/cors v1.2.1 github.com/go-co-op/gocron v1.37.0 github.com/go-enry/go-enry/v2 v2.9.2 + github.com/go-git/go-git/v5 v5.13.2 github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-openapi/spec v0.21.0 github.com/go-sql-driver/mysql v1.9.3 - github.com/go-webauthn/webauthn v0.13.4 + github.com/go-webauthn/webauthn v0.13.0 github.com/gobwas/glob v0.2.3 github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 - github.com/golang-jwt/jwt/v5 v5.3.0 + github.com/golang-jwt/jwt/v5 v5.2.2 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/google/go-github/v64 v64.0.0 - github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 + github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e github.com/google/uuid v1.6.0 github.com/gorilla/feeds v1.2.0 github.com/gorilla/sessions v1.4.0 github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/huandu/xstrings v1.5.0 - github.com/inbucket/html2text v0.9.0 - github.com/jhillyerd/enmime/v2 v2.2.0 + github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 + github.com/jhillyerd/enmime/v2 v2.1.0 github.com/json-iterator/go v1.1.12 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/klauspost/compress v1.18.0 - github.com/klauspost/cpuid/v2 v2.2.11 + github.com/klauspost/cpuid/v2 v2.2.10 github.com/lib/pq v1.10.9 github.com/markbates/goth v1.80.0 github.com/mattn/go-isatty v0.0.20 - github.com/mattn/go-sqlite3 v1.14.32 - github.com/meilisearch/meilisearch-go v0.34.0 - github.com/mholt/archives v0.1.3 + github.com/mattn/go-sqlite3 v1.14.28 + github.com/meilisearch/meilisearch-go v0.31.0 + github.com/mholt/archiver/v3 v3.5.1 github.com/microcosm-cc/bluemonday v1.0.27 - github.com/minio/minio-go/v7 v7.0.95 + github.com/minio/minio-go/v7 v7.0.94 github.com/msteinert/pam/v2 v2.1.0 - github.com/niklasfasching/go-org v1.9.1 + github.com/nektos/act v0.2.52 + github.com/niklasfasching/go-org v1.8.0 github.com/olivere/elastic/v7 v7.0.32 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 @@ -88,27 +89,27 @@ require ( github.com/robfig/cron/v3 v3.0.1 github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 github.com/sergi/go-diff v1.4.0 - github.com/stretchr/testify v1.11.1 + github.com/stretchr/testify v1.10.0 github.com/syndtr/goleveldb v1.0.0 - github.com/ulikunitz/xz v0.5.15 - github.com/urfave/cli/v3 v3.4.1 + github.com/ulikunitz/xz v0.5.12 + github.com/urfave/cli/v3 v3.3.3 github.com/valyala/fastjson v1.6.4 github.com/yohcop/openid-go v1.0.1 - github.com/yuin/goldmark v1.7.13 + github.com/yuin/goldmark v1.7.12 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc gitlab.com/gitlab-org/api/client-go v0.130.1 - go.uber.org/mock v0.6.0 - go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.42.0 - golang.org/x/image v0.31.0 - golang.org/x/net v0.44.0 - golang.org/x/oauth2 v0.31.0 - golang.org/x/sync v0.17.0 - golang.org/x/sys v0.36.0 - golang.org/x/text v0.29.0 - google.golang.org/protobuf v1.36.9 + go.uber.org/mock v0.5.2 + golang.org/x/crypto v0.39.0 + golang.org/x/image v0.27.0 + golang.org/x/net v0.41.0 + golang.org/x/oauth2 v0.30.0 + golang.org/x/sync v0.15.0 + golang.org/x/sys v0.33.0 + golang.org/x/text v0.26.0 + google.golang.org/protobuf v1.36.4 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.67.0 + gopkg.in/yaml.v3 v3.0.1 mvdan.cc/xurls/v2 v2.5.0 xorm.io/builder v0.3.13 xorm.io/xorm v1.3.9 @@ -116,13 +117,12 @@ require ( require ( cloud.google.com/go/compute/metadata v0.6.0 // indirect - dario.cat/mergo v1.0.2 // indirect + 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/Microsoft/go-winio v0.6.2 // indirect github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect - github.com/STARRY-S/zip v0.2.1 // indirect - github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -145,40 +145,35 @@ require ( github.com/blevesearch/zapx/v14 v14.4.2 // indirect github.com/blevesearch/zapx/v15 v15.4.2 // indirect github.com/blevesearch/zapx/v16 v16.2.4 // indirect - github.com/bmatcuk/doublestar/v4 v4.8.0 // indirect - github.com/bodgit/plumbing v1.3.0 // indirect - github.com/bodgit/sevenzip v1.6.0 // indirect - github.com/bodgit/windows v1.0.1 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect github.com/caddyserver/zerossl v0.1.3 // indirect github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudflare/circl v1.6.1 // indirect - github.com/cyphar/filepath-securejoin v0.4.1 // 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.5 // indirect github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/fatih/color v1.18.0 // indirect - github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/fxamacker/cbor/v2 v2.8.0 // indirect github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-enry/go-oniguruma v1.2.1 // indirect github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect - github.com/go-git/go-git/v5 v5.16.2 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-openapi/jsonpointer v0.21.1 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.1 // indirect - github.com/go-webauthn/x v0.1.23 // indirect + github.com/go-webauthn/x v0.1.21 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect - github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect @@ -188,38 +183,31 @@ require ( github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect - github.com/libdns/libdns v1.0.0 // indirect + github.com/libdns/libdns v1.0.0-beta.1 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/markbates/going v1.0.3 // indirect - github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/mattn/go-shellwords v1.0.12 // indirect github.com/mholt/acmez/v3 v3.1.2 // indirect github.com/miekg/dns v1.1.63 // indirect - github.com/mikelolasagasti/xz v1.0.1 // indirect - github.com/minio/crc64nvme v1.0.2 // indirect + github.com/minio/crc64nvme v1.0.1 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/minlz v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect github.com/mschoch/smat v0.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/nwaples/rardecode/v2 v2.1.0 // indirect - github.com/olekukonko/errors v1.1.0 // indirect - github.com/olekukonko/ll v0.0.9 // indirect - github.com/olekukonko/tablewriter v1.0.7 // indirect + github.com/nwaples/rardecode v1.1.3 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect - github.com/philhofer/fwd v1.2.0 // indirect + github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -227,34 +215,35 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/rhysd/actionlint v1.7.7 // indirect + github.com/rhysd/actionlint v1.6.27 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rs/xid v1.6.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skeema/knownhosts v1.3.1 // indirect - github.com/sorairolake/lzip-go v0.3.5 // indirect + github.com/skeema/knownhosts v1.3.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/tinylib/msgp v1.3.0 // 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/zeebo/assert v1.3.0 // indirect github.com/zeebo/blake3 v0.2.4 // indirect - go.etcd.io/bbolt v1.4.3 // indirect + go.etcd.io/bbolt v1.4.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect - go4.org v0.0.0-20230225012048-214862532bf5 // indirect - golang.org/x/mod v0.27.0 // indirect - golang.org/x/time v0.13.0 // indirect - golang.org/x/tools v0.36.0 // indirect + golang.org/x/mod v0.25.0 // indirect + golang.org/x/time v0.11.0 // indirect + golang.org/x/tools v0.34.0 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 +replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.28.0 + replace github.com/mholt/archiver/v3 => code.forgejo.org/forgejo/archiver/v3 v3.5.1 replace github.com/gliderlabs/ssh => code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616 diff --git a/go.sum b/go.sum index 63af64f9ca..639880e2ce 100644 --- a/go.sum +++ b/go.sum @@ -1,25 +1,13 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= code.forgejo.org/f3/gof3/v3 v3.11.0 h1:f/xToKwqTgxG6PYxvewywjDQyCcyHEEJ6sZqUitFsAE= code.forgejo.org/f3/gof3/v3 v3.11.0/go.mod h1:4FaRUNSQGBiD1M0DuB0yNv+Z2wMtlOeckgygHSSq4KQ= 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.28.0 h1:96njNC7C1YNyjWq5OWvLZMF/nw0PMthzIA8Nwbnn7jo= +code.forgejo.org/forgejo/act v1.28.0/go.mod h1:dFuiwAmD5vyrzecysHB2kL/GM3wRpoVPl+WdbCTC8Bs= +code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEjb3jaYYtmSE= +code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= code.forgejo.org/forgejo/go-rpmutils v1.0.0 h1:RZGGeKt70p/WaIEL97pyT6uiiEIoN8/aLmS5Z6WmX0M= code.forgejo.org/forgejo/go-rpmutils v1.0.0/go.mod h1:cg+VbgLXfrDPza9T+kBsMb3TVmmzPN4XseT6gDGLSUk= code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:RArF5AsF9LH4nEoJxqRxcP5r8hhRfWcId84G82YbqzA= @@ -28,8 +16,6 @@ code.forgejo.org/forgejo/levelqueue v1.0.0 h1:9krYpU6BM+j/1Ntj6m+VCAIu0UNnne1/Uf code.forgejo.org/forgejo/levelqueue v1.0.0/go.mod h1:fmG6zhVuqim2rxSFOoasgXO8V2W/k9U31VVYqLIRLhQ= code.forgejo.org/forgejo/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCdgFuQ= code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U= -code.forgejo.org/forgejo/runner/v11 v11.0.0 h1:PDChRbwPzoflwP05QHn8YyvRDvnU5yVq/X3sdZojXr8= -code.forgejo.org/forgejo/runner/v11 v11.0.0/go.mod h1:ZJokNf9nZItjsfSjC/9zHbUvf5LXYUi+On+1Bg/pO3g= code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616 h1:kEZL84+02jY9RxXM4zHBWZ3Fml0B09cmP1LGkDsCfIA= code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= code.forgejo.org/go-chi/binding v1.0.1 h1:coKNI+X1NzRN7X85LlrpvBRqk0TXpJ+ja28vusQWEuY= @@ -48,9 +34,8 @@ codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 h1:TXbikPqa7YRtf codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570/go.mod h1:IIAjsijsd8q1isWX8MACefDEgTQslQ4stk2AeeTt3kM= connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= -dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= -dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= @@ -63,8 +48,6 @@ github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= @@ -74,22 +57,21 @@ github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiU github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y= github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg= github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0= -github.com/STARRY-S/zip v0.2.1 h1:pWBd4tuSGm3wtpoqRZZ2EAwOmcHK6XFf7bU9qcJXyFg= -github.com/STARRY-S/zip v0.2.1/go.mod h1:xNvshLODWtC4EJ702g7cTYn13G53o1+X9BWnPFpcWV4= github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 h1:cSXom2MoKJ9KPPw29RoZtHvUETY4F4n/kXl8m9btnQ0= github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2/go.mod h1:JitQWJ8JuV4Y87l8VsHiiwhb3cgdyn68mX40s7NT6PA= 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.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw= -github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA= +github.com/alecthomas/chroma/v2 v2.18.0 h1:6h53Q4hW83SuF+jcsp7CVhLsMozzvQvO8HBbKQW+gn4= +github.com/alecthomas/chroma/v2 v2.18.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= -github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg= -github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 h1:8PmGpDEZl9yDpcdEr6Odf23feCxK3LNUNMxjXg41pZQ= -github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= @@ -141,14 +123,6 @@ github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFx github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw= github.com/blevesearch/zapx/v16 v16.2.4 h1:tGgfvleXTAkwsD5mEzgM3zCS/7pgocTCnO1oyAUjlww= github.com/blevesearch/zapx/v16 v16.2.4/go.mod h1:Rti/REtuuMmzwsI8/C/qIzRaEoSK/wiFYw5e5ctUKKs= -github.com/bmatcuk/doublestar/v4 v4.8.0 h1:DSXtrypQddoug1459viM9X9D3dp1Z7993fw36I2kNcQ= -github.com/bmatcuk/doublestar/v4 v4.8.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= -github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= -github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A= -github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc= -github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= -github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -160,11 +134,10 @@ 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.8 h1:QN/daUob6cmK8GcdKnwn9+YTlPr1vNj+oeAIiJK6fPc= github.com/buildkite/terminal-to-html/v3 v3.16.8/go.mod h1:+k1KVKROZocrTLsEQ9PEf9A+8+X8uaVV5iO1ZIOwKYM= -github.com/caddyserver/certmagic v0.24.0 h1:EfXTWpxHAUKgDfOj6MHImJN8Jm4AMFfMT6ITuKhrDF0= -github.com/caddyserver/certmagic v0.24.0/go.mod h1:xPT7dC1DuHHnS2yuEQCEyks+b89sUkMENh8dJF+InLE= +github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU= +github.com/caddyserver/certmagic v0.23.0/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4= github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI= github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -174,18 +147,14 @@ github.com/chi-middleware/proxy v1.1.1/go.mod h1:jQwMEJct2tz9VmtCELxvnXoMfa+SOdi github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= -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.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= -github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +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= @@ -204,6 +173,7 @@ github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55k github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +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= github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= @@ -211,8 +181,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.3 h1:XVUp6qW3BIkmM3/1EkrHpa6bL56APOynfXcZEmIgOhs= github.com/editorconfig/editorconfig-core-go/v2 v2.6.3/go.mod h1:ThHVc+hqbUsmE1wmK/MASpQEhCleWu1JDJDNhUOMy0c= -github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= -github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= +github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM= +github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= 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= @@ -222,10 +192,8 @@ github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTe github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY= github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -234,22 +202,21 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= -github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= +github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 h1:j2TrkUG/NATGi/EQS+MvEoF79CxiRUmT16ErFroNcKI= github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9/go.mod h1:cJ9Ye0ZNSMN7RzZDBRY3E+8M3Bpf/R1JX22Ir9yX6WI= github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 h1:I2nuhyVI/48VXoRCCZR2hYBgnSXa+EuDJf/VyX06TC0= github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7/go.mod h1:5x8a6P/dhmMGFxWLcyYlyOuJ2lRNaHGhRv+yu8BaTSI= +github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw= github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA= -github.com/go-ap/jsonld v0.0.0-20250905102310-8480b0fe24d9 h1:gaBrU/E+usPHIafDIC2EwvZbehvgAEuu78Jk0zjxw5w= -github.com/go-ap/jsonld v0.0.0-20250905102310-8480b0fe24d9/go.mod h1:4h93IBxgfnE/DEleMLgJ/XCeu/RtQ+MUh3ucANseeXA= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= -github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= -github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE= -github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= +github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= +github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= +github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0= github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY= github.com/go-enry/go-enry/v2 v2.9.2 h1:giOQAtCgBX08kosrX818DCQJTCNtKwoPBGu0qb6nKTY= @@ -264,10 +231,8 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= 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.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM= -github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= -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-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0= +github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= @@ -285,10 +250,10 @@ github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI6 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-webauthn/webauthn v0.13.4 h1:q68qusWPcqHbg9STSxBLBHnsKaLxNO0RnVKaAqMuAuQ= -github.com/go-webauthn/webauthn v0.13.4/go.mod h1:MglN6OH9ECxvhDqoq1wMoF6P6JRYDiQpC9nc5OomQmI= -github.com/go-webauthn/x v0.1.23 h1:9lEO0s+g8iTyz5Vszlg/rXTGrx3CjcD0RZQ1GPZCaxI= -github.com/go-webauthn/x v0.1.23/go.mod h1:AJd3hI7NfEp/4fI6T4CHD753u91l510lglU7/NMN6+E= +github.com/go-webauthn/webauthn v0.13.0 h1:cJIL1/1l+22UekVhipziAaSgESJxokYkowUqAIsWs0Y= +github.com/go-webauthn/webauthn v0.13.0/go.mod h1:Oy9o2o79dbLKRPZWWgRIOdtBGAhKnDIaBp2PFkICRHs= +github.com/go-webauthn/x v0.1.21 h1:nFbckQxudvHEJn2uy1VEi713MeSpApoAv9eRqsb9AdQ= +github.com/go-webauthn/x v0.1.21/go.mod h1:sEYohtg1zL4An1TXIUIQ5csdmoO+WO0R4R2pGKaHYKA= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= @@ -300,26 +265,16 @@ github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7w github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0= github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= -github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -329,13 +284,11 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -353,20 +306,13 @@ github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 h1:xhMrHhTJ6zxu3gA4enFM9MLn9AY7613teCdFnlUVbSQ= -github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= @@ -381,19 +327,12 @@ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kX github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= @@ -401,32 +340,30 @@ github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSo github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= -github.com/inbucket/html2text v0.9.0 h1:ULJmVcBEMAcmLE+/rN815KG1Fx6+a4HhbUxiDiN+qks= -github.com/inbucket/html2text v0.9.0/go.mod h1:QDaumzl+/OzlSVbNohhmg+yAy5pKjUjzCKW2BMvztKE= +github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA= +github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jhillyerd/enmime/v2 v2.2.0 h1:Pe35MB96eZK5Q0XjlvPftOgWypQpd1gcbfJKAt7rsB8= -github.com/jhillyerd/enmime/v2 v2.2.0/go.mod h1:SOBXlCemjhiV2DvHhAKnJiWrtJGS/Ffuw4Iy7NjBTaI= +github.com/jhillyerd/enmime/v2 v2.1.0 h1:c8Qwi5Xq5EdtMN6byQWoZ/8I2RMTo6OJ7Xay+s1oPO0= +github.com/jhillyerd/enmime/v2 v2.1.0/go.mod h1:EJ74dcRbBcqHSP2TBu08XRoy6y3Yx0cevwb1YkGMEmQ= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU= -github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -443,8 +380,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libdns/libdns v1.0.0 h1:IvYaz07JNz6jUQ4h/fv2R4sVnRnm77J/aOuC9B+TQTA= -github.com/libdns/libdns v1.0.0/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= +github.com/libdns/libdns v1.0.0-beta.1 h1:KIf4wLfsrEpXpZ3vmc/poM8zCATXT2klbdPe6hyOBjQ= +github.com/libdns/libdns v1.0.0-beta.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= @@ -452,36 +389,30 @@ github.com/markbates/going v1.0.3 h1:mY45T5TvW+Xz5A6jY7lf4+NLg9D8+iuStIHyR7M8qsE github.com/markbates/going v1.0.3/go.mod h1:fQiT6v6yQar9UD6bd/D4Z5Afbk9J6BBVBtLiyY4gp2o= github.com/markbates/goth v1.80.0 h1:NnvatczZDzOs1hn9Ug+dVYf2Viwwkp/ZDX5K+GLjan8= github.com/markbates/goth v1.80.0/go.mod h1:4/GYHo+W6NWisrMPZnq0Yr2Q70UntNLn7KXEFhrIdAY= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= -github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= -github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= -github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/meilisearch/meilisearch-go v0.34.0 h1:P+Ohdx4/PCxXaoI5wNi0LMwPkuiNrF/kGIzBrKYS4tw= -github.com/meilisearch/meilisearch-go v0.34.0/go.mod h1:cUVJZ2zMqTvvwIMEEAdsWH+zrHsrLpAw6gm8Lt1MXK0= +github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= +github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/meilisearch/meilisearch-go v0.31.0 h1:yZRhY1qJqdH8h6GFZALGtkDLyj8f9v5aJpsNMyrUmnY= +github.com/meilisearch/meilisearch-go v0.31.0/go.mod h1:aNtyuwurDg/ggxQIcKqWH6G9g2ptc8GyY7PLY4zMn/g= github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc= github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= -github.com/mholt/archives v0.1.3 h1:aEAaOtNra78G+TvV5ohmXrJOAzf++dIlYeDW3N9q458= -github.com/mholt/archives v0.1.3/go.mod h1:LUCGp++/IbV/I0Xq4SzcIR6uwgeh2yjnQWamjRQfLTU= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= -github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0= -github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc= -github.com/minio/crc64nvme v1.0.2 h1:6uO1UxGAD+kwqWWp7mBFsi5gAse66C4NXO8cmcVculg= -github.com/minio/crc64nvme v1.0.2/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg= +github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY= +github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.95 h1:ywOUPg+PebTMTzn9VDsoFJy32ZuARN9zhB+K3IYEvYU= -github.com/minio/minio-go/v7 v7.0.95/go.mod h1:wOOX3uxS334vImCNRVyIDdXX9OsXDm89ToynKgqUKlo= -github.com/minio/minlz v1.0.0 h1:Kj7aJZ1//LlTP1DM8Jm7lNKvvJS2m74gyyXXn3+uJWQ= -github.com/minio/minlz v1.0.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= +github.com/minio/minio-go/v7 v7.0.94 h1:1ZoksIKPyaSt64AVOyaQvhDOgVC3MfZsWM6mZXRUGtM= +github.com/minio/minio-go/v7 v7.0.94/go.mod h1:71t2CqDt3ThzESgZUlU1rBN54mksGGlkLcFgguDnnAc= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -497,19 +428,16 @@ github.com/msteinert/pam/v2 v2.1.0 h1:er5F9TKV5nGFuTt12ubtqPHEUdeBwReP7vd3wovidG github.com/msteinert/pam/v2 v2.1.0/go.mod h1:KT28NNIcDFf3PcBmNI2mIGO4zZJ+9RSs/At2PB3IDVc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/niklasfasching/go-org v1.9.1 h1:/3s4uTPOF06pImGa2Yvlp24yKXZoTYM+nsIlMzfpg/0= -github.com/niklasfasching/go-org v1.9.1/go.mod h1:ZAGFFkWvUQcpazmi/8nHqwvARpr1xpb+Es67oUGX/48= -github.com/nwaples/rardecode/v2 v2.1.0 h1:JQl9ZoBPDy+nIZGb1mx8+anfHp/LV3NE2MjMiv0ct/U= -github.com/nwaples/rardecode/v2 v2.1.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= +github.com/niklasfasching/go-org v1.8.0 h1:WyGLaajLLp8JbQzkmapZ1y0MOzKuKV47HkZRloi+HGY= +github.com/niklasfasching/go-org v1.8.0/go.mod h1:e2A9zJs7cdONrEGs3gvxCcaAEpwwPNPG7csDpXckMNg= +github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= +github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= -github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= -github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI= -github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g= -github.com/olekukonko/tablewriter v1.0.7 h1:HCC2e3MM+2g72M81ZcJU11uciw6z/p82aEnm4/ySDGw= -github.com/olekukonko/tablewriter v1.0.7/go.mod h1:H428M+HzoUXC6JU2Abj9IT9ooRmdq9CxuDmKMtrOCMs= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E= github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -527,8 +455,9 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= -github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= -github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= @@ -543,7 +472,6 @@ github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= @@ -554,21 +482,19 @@ github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhi github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rhysd/actionlint v1.7.7 h1:0KgkoNTrYY7vmOCs9BW2AHxLvvpoY9nEUzgBHiPUr0k= -github.com/rhysd/actionlint v1.7.7/go.mod h1:AE6I6vJEkNaIfWqC2GNE5spIJNhxf8NCtLEKU4NnUXg= +github.com/rhysd/actionlint v1.6.27 h1:xxwe8YmveBcC8lydW6GoHMGmB6H/MTqUU60F2p10wjw= +github.com/rhysd/actionlint v1.6.27/go.mod h1:m2nFUjAnOrxCMXuOMz9evYBRCLUsMnKY2IJl/N5umbk= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= @@ -577,10 +503,8 @@ github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepq 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.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= -github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= -github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu0Cwg= -github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk= +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/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -595,23 +519,26 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww= github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= -github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli/v3 v3.4.1 h1:1M9UOCy5bLmGnuu1yn3t3CB4rG79Rtoxuv1sPhnm6qM= -github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= +github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= +github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I= +github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js= @@ -619,8 +546,8 @@ github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBz github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= -github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= +github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY= +github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= @@ -631,32 +558,22 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= gitlab.com/gitlab-org/api/client-go v0.130.1 h1:1xF5C5Zq3sFeNg3PzS2z63oqrxifne3n/OnbI7nptRc= gitlab.com/gitlab-org/api/client-go v0.130.1/go.mod h1:ZhSxLAWadqP6J9lMh40IAZOlOxBLPRh7yFOXR/bMJWM= -go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= -go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= +go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= -go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= +go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= -go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= -go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= @@ -666,59 +583,23 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= 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-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.31.0 h1:mLChjE2MV6g1S7oqbXC0/UcKijjm5fnJLUYKIYrLESA= -golang.org/x/image v0.31.0/go.mod h1:R9ec5Lcp96v9FTF+ajwaH3uGxPH4fKfHHAVbUILxghA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w= +golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= -golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -731,21 +612,12 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= -golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo= -golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -753,25 +625,15 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -783,6 +645,7 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -790,8 +653,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -801,12 +664,9 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -816,88 +676,31 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= -golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= -golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= +google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -925,11 +728,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= @@ -952,9 +750,6 @@ modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8= mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo= xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU= diff --git a/models/actions/artifact.go b/models/actions/artifact.go index 492e3f6cea..10cd3868a1 100644 --- a/models/actions/artifact.go +++ b/models/actions/artifact.go @@ -108,7 +108,6 @@ func UpdateArtifactByID(ctx context.Context, id int64, art *ActionArtifact) erro type FindArtifactsOptions struct { db.ListOptions - ID int64 RepoID int64 RunID int64 ArtifactName string @@ -117,9 +116,6 @@ type FindArtifactsOptions struct { func (opts FindArtifactsOptions) ToConds() builder.Cond { cond := builder.NewCond() - if opts.ID > 0 { - cond = cond.And(builder.Eq{"id": opts.ID}) - } if opts.RepoID > 0 { cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) } @@ -136,13 +132,6 @@ func (opts FindArtifactsOptions) ToConds() builder.Cond { return cond } -var _ db.FindOptionsOrder = FindArtifactsOptions{} - -// ToOrders implements db.FindOptionsOrder, to have a stable order -func (opts FindArtifactsOptions) ToOrders() string { - return "id" -} - // ActionArtifactMeta is the meta data of an artifact type ActionArtifactMeta struct { ArtifactName string diff --git a/models/actions/main_test.go b/models/actions/main_test.go index f551d39671..2eb923d9d0 100644 --- a/models/actions/main_test.go +++ b/models/actions/main_test.go @@ -15,10 +15,6 @@ func TestMain(m *testing.M) { "action_runner.yml", "repository.yml", "action_runner_token.yml", - "user.yml", - "action_run.yml", - "action_run_job.yml", - "action_task.yml", }, }) } diff --git a/models/actions/run.go b/models/actions/run.go index b5f79a0cb3..69592120e9 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -21,7 +21,7 @@ import ( "forgejo.org/modules/util" webhook_module "forgejo.org/modules/webhook" - "code.forgejo.org/forgejo/runner/v11/act/jobparser" + "github.com/nektos/act/pkg/jobparser" "xorm.io/builder" ) @@ -309,26 +309,15 @@ func GetLatestRunForBranchAndWorkflow(ctx context.Context, repoID int64, branch, } func GetRunByID(ctx context.Context, id int64) (*ActionRun, error) { - run, has, err := GetRunByIDWithHas(ctx, id) + var run ActionRun + has, err := db.GetEngine(ctx).Where("id=?", id).Get(&run) if err != nil { return nil, err } else if !has { return nil, fmt.Errorf("run with id %d: %w", id, util.ErrNotExist) } - return run, nil -} - -func GetRunByIDWithHas(ctx context.Context, id int64) (*ActionRun, bool, error) { - var run ActionRun - has, err := db.GetEngine(ctx).Where("id=?", id).Get(&run) - if err != nil { - return nil, false, err - } else if !has { - return nil, false, nil - } - - return &run, true, nil + return &run, nil } func GetRunByIndex(ctx context.Context, repoID, index int64) (*ActionRun, error) { diff --git a/models/actions/run_job.go b/models/actions/run_job.go index edd1170072..1fadb4b7c7 100644 --- a/models/actions/run_job.go +++ b/models/actions/run_job.go @@ -44,38 +44,6 @@ func init() { db.RegisterModel(new(ActionRunJob)) } -func (job *ActionRunJob) HTMLURL(ctx context.Context) (string, error) { - if job.Run == nil || job.Run.Repo == nil { - return "", fmt.Errorf("action_run_job: load run and repo before accessing HTMLURL") - } - - // Find the "index" of the currently selected job... kinda ugly that the URL uses the index rather than some other - // unique identifier of the job which could actually be stored upon it. But hard to change that now. - allJobs, err := GetRunJobsByRunID(ctx, job.RunID) - if err != nil { - return "", err - } - jobIndex := -1 - for i, otherJob := range allJobs { - if job.ID == otherJob.ID { - jobIndex = i - break - } - } - if jobIndex == -1 { - return "", fmt.Errorf("action_run_job: unable to find job on run: %d", job.ID) - } - - attempt := job.Attempt - // If a job has never been fetched by a runner yet, it will have attempt 0 -- but this attempt will never have a - // valid UI since attempt is incremented to 1 if it is picked up by a runner. - if attempt == 0 { - attempt = 1 - } - - return fmt.Sprintf("%s/actions/runs/%d/jobs/%d/attempt/%d", job.Run.Repo.HTMLURL(), job.Run.Index, jobIndex, attempt), nil -} - func (job *ActionRunJob) Duration() time.Duration { return calculateDuration(job.Started, job.Stopped, job.Status) } diff --git a/models/actions/run_job_test.go b/models/actions/run_job_test.go index 6abdb2bf5c..50a4ba10d8 100644 --- a/models/actions/run_job_test.go +++ b/models/actions/run_job_test.go @@ -3,14 +3,9 @@ package actions import ( - "fmt" "testing" - "forgejo.org/models/db" - "forgejo.org/models/unittest" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestActionRunJob_ItRunsOn(t *testing.T) { @@ -32,41 +27,3 @@ func TestActionRunJob_ItRunsOn(t *testing.T) { assert.False(t, actionJob.ItRunsOn(agentLabels)) } - -func TestActionRunJob_HTMLURL(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - tests := []struct { - id int64 - expected string - }{ - { - id: 192, - expected: "https://try.gitea.io/user5/repo4/actions/runs/187/jobs/0/attempt/1", - }, - { - id: 393, - expected: "https://try.gitea.io/user2/repo1/actions/runs/187/jobs/1/attempt/1", - }, - { - id: 394, - expected: "https://try.gitea.io/user2/repo1/actions/runs/187/jobs/2/attempt/2", - }, - } - - for _, tt := range tests { - t.Run(fmt.Sprintf("id=%d", tt.id), func(t *testing.T) { - var job ActionRunJob - has, err := db.GetEngine(t.Context()).Where("id=?", tt.id).Get(&job) - require.NoError(t, err) - require.True(t, has, "load ActionRunJob from fixture") - - err = job.LoadAttributes(t.Context()) - require.NoError(t, err) - - url, err := job.HTMLURL(t.Context()) - require.NoError(t, err) - assert.Equal(t, tt.expected, url) - }) - } -} diff --git a/models/actions/task.go b/models/actions/task.go index 6e77db1b18..93369db7e8 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -17,8 +17,8 @@ import ( "forgejo.org/modules/timeutil" "forgejo.org/modules/util" - "code.forgejo.org/forgejo/runner/v11/act/jobparser" lru "github.com/hashicorp/golang-lru/v2" + "github.com/nektos/act/pkg/jobparser" "xorm.io/builder" ) @@ -148,21 +148,6 @@ func (task *ActionTask) GenerateToken() (err error) { return err } -// Retrieve all the attempts from the same job as the target `ActionTask`. Limited fields are queried to avoid loading -// the LogIndexes blob when not needed. -func (task *ActionTask) GetAllAttempts(ctx context.Context) ([]*ActionTask, error) { - var attempts []*ActionTask - err := db.GetEngine(ctx). - Cols("id", "attempt", "status", "started"). - Where("job_id=?", task.JobID). - Desc("attempt"). - Find(&attempts) - if err != nil { - return nil, err - } - return attempts, nil -} - func GetTaskByID(ctx context.Context, id int64) (*ActionTask, error) { var task ActionTask has, err := db.GetEngine(ctx).Where("id=?", id).Get(&task) @@ -175,18 +160,6 @@ func GetTaskByID(ctx context.Context, id int64) (*ActionTask, error) { return &task, nil } -func GetTaskByJobAttempt(ctx context.Context, jobID, attempt int64) (*ActionTask, error) { - var task ActionTask - has, err := db.GetEngine(ctx).Where("job_id=?", jobID).Where("attempt=?", attempt).Get(&task) - if err != nil { - return nil, err - } else if !has { - return nil, fmt.Errorf("task with job_id %d and attempt %d: %w", jobID, attempt, util.ErrNotExist) - } - - return &task, nil -} - func GetRunningTaskByToken(ctx context.Context, token string) (*ActionTask, error) { errNotExist := fmt.Errorf("task with token %q: %w", token, util.ErrNotExist) if token == "" { @@ -302,7 +275,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask } var workflowJob *jobparser.Job - if gots, err := jobparser.Parse(job.WorkflowPayload, false); err != nil { + if gots, err := jobparser.Parse(job.WorkflowPayload); err != nil { return nil, false, fmt.Errorf("parse workflow of job %d: %w", job.ID, err) } else if len(gots) != 1 { return nil, false, fmt.Errorf("workflow of job %d: not single workflow", job.ID) diff --git a/models/actions/task_test.go b/models/actions/task_test.go deleted file mode 100644 index 73aff17a85..0000000000 --- a/models/actions/task_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package actions - -import ( - "testing" - - "forgejo.org/models/db" - "forgejo.org/models/unittest" - "forgejo.org/modules/timeutil" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestActionTask_GetAllAttempts(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - var task ActionTask - has, err := db.GetEngine(t.Context()).Where("id=?", 47).Get(&task) - require.NoError(t, err) - require.True(t, has, "load ActionTask from fixture") - - allAttempts, err := task.GetAllAttempts(t.Context()) - require.NoError(t, err) - require.Len(t, allAttempts, 3) - assert.EqualValues(t, 47, allAttempts[0].ID, "ordered by attempt, 1") - assert.EqualValues(t, 53, allAttempts[1].ID, "ordered by attempt, 2") - assert.EqualValues(t, 52, allAttempts[2].ID, "ordered by attempt, 3") - - // GetAllAttempts doesn't populate all fields; so check expected fields from one of the records - assert.EqualValues(t, 3, allAttempts[0].Attempt, "read Attempt field") - assert.Equal(t, StatusRunning, allAttempts[0].Status, "read Status field") - assert.Equal(t, timeutil.TimeStamp(1683636528), allAttempts[0].Started, "read Started field") -} - -func TestActionTask_GetTaskByJobAttempt(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - task, err := GetTaskByJobAttempt(t.Context(), 192, 2) - require.NoError(t, err) - assert.EqualValues(t, 192, task.JobID) - assert.EqualValues(t, 2, task.Attempt) - - _, err = GetTaskByJobAttempt(t.Context(), 192, 100) - assert.ErrorContains(t, err, "task with job_id 192 and attempt 100: resource does not exist") -} diff --git a/models/activities/action.go b/models/activities/action.go index 5067109545..f928ad6784 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -26,7 +26,6 @@ import ( "forgejo.org/modules/base" "forgejo.org/modules/container" "forgejo.org/modules/git" - "forgejo.org/modules/json" "forgejo.org/modules/log" "forgejo.org/modules/setting" "forgejo.org/modules/structs" @@ -387,21 +386,8 @@ func (a *Action) IsIssueEvent() bool { // GetIssueInfos returns a list of associated information with the action. func (a *Action) GetIssueInfos() []string { - // Previously multiple pieces of data used to be encoded into a.Content by pipe-separating them, but this doesn't - // work well if some of the user-entered pieces of content (issue titles, comments, etc.) contain pipes. The newer - // storage format is to json-encode a string array, which we check for and prefer... then fallback to assuming old. - var ret []string - if strings.HasPrefix(a.Content, "[") && strings.HasSuffix(a.Content, "]") { - ret = make([]string, 0, 3) - err := json.Unmarshal([]byte(a.Content), &ret) - if err != nil { - log.Error("GetIssueInfos json decoding error: %v", err) - } - } else { - ret = strings.SplitN(a.Content, "|", 3) - } - // make sure it always returns 3 elements, because there are some access to the a[1] and a[2] without checking the length + ret := strings.SplitN(a.Content, "|", 3) for len(ret) < 3 { ret = append(ret, "") } @@ -784,9 +770,7 @@ func DeleteIssueActions(ctx context.Context, repoID, issueID, issueIndex int64) _, err := e.Where("repo_id = ?", repoID). In("op_type", ActionCreateIssue, ActionCreatePullRequest). - Where(builder.Or( - builder.Like{"content", strconv.FormatInt(issueIndex, 10) + "|%"}, // "IssueIndex|content..." - builder.Like{"content", "[\"" + strconv.FormatInt(issueIndex, 10) + "\"%"})). // JSON, ["IssueIndex"... + Where("content LIKE ?", strconv.FormatInt(issueIndex, 10)+"|%"). // "IssueIndex|content..." Delete(&Action{}) return err } diff --git a/models/activities/action_test.go b/models/activities/action_test.go index 6911733a09..161d05bbfa 100644 --- a/models/activities/action_test.go +++ b/models/activities/action_test.go @@ -308,69 +308,14 @@ func TestDeleteIssueActions(t *testing.T) { }) require.NoError(t, err) err = db.Insert(db.DefaultContext, &activities_model.Action{ - OpType: activities_model.ActionCreateIssue, - RepoID: issue.RepoID, - // Older Content format... + OpType: activities_model.ActionCreateIssue, + RepoID: issue.RepoID, Content: fmt.Sprintf("%d|content...", issue.Index), }) require.NoError(t, err) - err = db.Insert(db.DefaultContext, &activities_model.Action{ - OpType: activities_model.ActionCreateIssue, - RepoID: issue.RepoID, - // JSON-encoded Content format... - Content: fmt.Sprintf("[\"%d\",\"content...\"]", issue.Index), - }) - require.NoError(t, err) // assert that the actions exist, then delete them - unittest.AssertCount(t, &activities_model.Action{}, 3) + unittest.AssertCount(t, &activities_model.Action{}, 2) require.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index)) unittest.AssertCount(t, &activities_model.Action{}, 0) } - -func TestGetIssueInfos(t *testing.T) { - tt := []struct { - content string - field1 string - field2 string - field3 string - }{ - { - content: "4|", - field1: "4", - }, - { - content: "2|docs: Add README w/ template sections", - field1: "2", - field2: "docs: Add README w/ template sections", - }, - { - content: "2|docs: Add README w/ template sections|Some comment...", - field1: "2", - field2: "docs: Add README w/ template sections", - field3: "Some comment...", - }, - { - content: "[\"4\"]", - field1: "4", - }, - { - content: "[\"2\", \"docs: Add README w/ | template sections\"]", - field1: "2", - field2: "docs: Add README w/ | template sections", - }, - { - content: "[\"2\", \"docs: Add README w/ | template sections\", \"Some | comment...\"]", - field1: "2", - field2: "docs: Add README w/ | template sections", - field3: "Some | comment...", - }, - } - for _, test := range tt { - action := &activities_model.Action{Content: test.content} - issueInfos := action.GetIssueInfos() - assert.Equal(t, test.field1, issueInfos[0]) - assert.Equal(t, test.field2, issueInfos[1]) - assert.Equal(t, test.field3, issueInfos[2]) - } -} diff --git a/models/asymkey/gpg_key_object_verification.go b/models/asymkey/gpg_key_object_verification.go index 10567dcd4f..745ed04869 100644 --- a/models/asymkey/gpg_key_object_verification.go +++ b/models/asymkey/gpg_key_object_verification.go @@ -36,7 +36,6 @@ type ObjectVerification struct { TrustStatus string } -// llu:TrKeys const ( // BadSignature is used as the reason when the signature has a KeyID that is in the db // but no key that has that ID verifies the signature. This is a suspicious failure. diff --git a/models/asymkey/main_test.go b/models/asymkey/main_test.go index aa13a93f0a..316e8f1d54 100644 --- a/models/asymkey/main_test.go +++ b/models/asymkey/main_test.go @@ -15,6 +15,8 @@ func TestMain(m *testing.M) { "gpg_key.yml", "public_key.yml", "TestParseCommitWithSSHSignature/public_key.yml", + "deploy_key.yml", + "gpg_key_import.yml", "user.yml", "email_address.yml", }, diff --git a/models/db/engine.go b/models/db/engine.go index 42b9150696..05a119b08d 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -15,7 +15,6 @@ import ( "strings" "time" - "forgejo.org/modules/container" "forgejo.org/modules/log" "forgejo.org/modules/setting" @@ -386,15 +385,6 @@ func (TracingHook) BeforeProcess(c *contexts.ContextHook) (context.Context, erro } func (TracingHook) AfterProcess(c *contexts.ContextHook) error { - if c.Result != nil { - if rowsAffected, err := c.Result.RowsAffected(); err == nil { - trace.Logf(c.Ctx, "rows affected", "%d", rowsAffected) - } - if lastID, err := c.Result.LastInsertId(); err == nil { - trace.Logf(c.Ctx, "last insert id", "%d", lastID) - } - } - c.Ctx.Value(sqlTask{}).(*trace.Task).End() return nil } @@ -448,12 +438,3 @@ func GetMasterEngine(x Engine) (*xorm.Engine, error) { return engine, nil } - -// GetTableNames returns the table name of all registered models. -func GetTableNames() container.Set[string] { - names := make(container.Set[string]) - for _, table := range tables { - names.Add(x.TableName(table)) - } - return names -} diff --git a/models/db/index.go b/models/db/index.go index c069f0febd..4c15dbe8a1 100644 --- a/models/db/index.go +++ b/models/db/index.go @@ -72,19 +72,14 @@ func postgresGetNextResourceIndex(ctx context.Context, tableName string, groupID } func mysqlGetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { - res, err := GetEngine(ctx).Query(fmt.Sprintf("INSERT INTO %s (group_id, max_index) "+ - "VALUES (?,1) ON DUPLICATE KEY UPDATE max_index = max_index+1 /*M!100500 RETURNING max_index */", - tableName), groupID) - if err != nil { + if _, err := GetEngine(ctx).Exec(fmt.Sprintf("INSERT INTO %s (group_id, max_index) "+ + "VALUES (?,1) ON DUPLICATE KEY UPDATE max_index = max_index+1", + tableName), groupID); err != nil { return 0, err } - if len(res) > 0 { - return strconv.ParseInt(string(res[0]["max_index"]), 10, 64) - } - var idx int64 - _, err = GetEngine(ctx).SQL(fmt.Sprintf("SELECT max_index FROM %s WHERE group_id = ?", tableName), groupID).Get(&idx) + _, err := GetEngine(ctx).SQL(fmt.Sprintf("SELECT max_index FROM %s WHERE group_id = ?", tableName), groupID).Get(&idx) if err != nil { return 0, err } diff --git a/models/db/table_names_test.go b/models/db/table_names_test.go deleted file mode 100644 index 176ce9905d..0000000000 --- a/models/db/table_names_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package db - -import ( - "slices" - "testing" - - "forgejo.org/modules/test" - - "github.com/stretchr/testify/assert" -) - -func TestGetTableNames(t *testing.T) { - t.Run("Simple", func(t *testing.T) { - defer test.MockVariableValue(&tables, []any{new(GPGKey)})() - - assert.Equal(t, []string{"gpg_key"}, GetTableNames().Values()) - }) - - t.Run("Multiple tables", func(t *testing.T) { - defer test.MockVariableValue(&tables, []any{new(GPGKey), new(User), new(BlockedUser)})() - - tableNames := GetTableNames().Values() - slices.Sort(tableNames) - - assert.Equal(t, []string{"forgejo_blocked_user", "gpg_key", "user"}, tableNames) - }) -} - -type GPGKey struct{} - -type User struct{} - -type BlockedUser struct{} - -func (*BlockedUser) TableName() string { - return "forgejo_blocked_user" -} diff --git a/models/error.go b/models/error.go index 99c8ded766..ebaa8a135d 100644 --- a/models/error.go +++ b/models/error.go @@ -121,7 +121,6 @@ type ErrInvalidCloneAddr struct { IsInvalidPath bool IsProtocolInvalid bool IsPermissionDenied bool - HasCredentials bool LocalPath bool } @@ -144,9 +143,6 @@ func (err *ErrInvalidCloneAddr) Error() string { if err.IsURLError { return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url is invalid", err.Host) } - if err.HasCredentials { - return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url contains credentials", err.Host) - } return fmt.Sprintf("migration/cloning from '%s' is not allowed", err.Host) } diff --git a/models/fixtures/action_artifact.yml b/models/fixtures/action_artifact.yml index a591719aee..2c51c11ebd 100644 --- a/models/fixtures/action_artifact.yml +++ b/models/fixtures/action_artifact.yml @@ -57,7 +57,7 @@ run_id: 792 runner_id: 1 repo_id: 4 - owner_id: 5 + owner_id: 1 commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 storage_path: "27/5/1730330775594233150.chunk" file_size: 1024 diff --git a/models/fixtures/action_run_job.yml b/models/fixtures/action_run_job.yml index 911e99c076..702c6bc832 100644 --- a/models/fixtures/action_run_job.yml +++ b/models/fixtures/action_run_job.yml @@ -106,7 +106,7 @@ commit_sha: 985f0301dba5e7b34be866819cd15ad3d8f508ee is_fork_pull_request: 0 name: job_2 - attempt: 2 + attempt: 1 job_id: job_2 task_id: 47 status: 5 @@ -128,18 +128,3 @@ runs_on: '["fedora"]' started: 1683636528 stopped: 1683636626 -- - id: 396 - run_id: 794 - repo_id: 4 - owner_id: 1 - commit_sha: 985f0301dba5e7b34be866819cd15ad3d8f508ee - is_fork_pull_request: 0 - name: job_2 - attempt: 0 - job_id: job_2 - task_id: null - status: 5 - runs_on: '["fedora"]' - started: 1683636528 - stopped: 1683636626 diff --git a/models/fixtures/action_task.yml b/models/fixtures/action_task.yml index e5fa35f0b3..506a47d8a0 100644 --- a/models/fixtures/action_task.yml +++ b/models/fixtures/action_task.yml @@ -117,43 +117,3 @@ log_length: 707 log_size: 90179 log_expired: 0 -- - id: 52 - job_id: 192 - attempt: 1 - runner_id: 1 - status: 1 # success - started: 1683636528 - stopped: 1683636626 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784223 - token_salt: ffffffffff - token_last_eight: ffffffff - log_filename: artifact-test2/2f/47.log - log_in_storage: 1 - log_length: 707 - log_size: 90179 - log_expired: 0 -- - id: 53 - job_id: 192 - attempt: 2 - runner_id: 1 - status: 1 # success - started: 1683636528 - stopped: 1683636626 - repo_id: 4 - owner_id: 1 - commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 - is_fork_pull_request: 0 - token_hash: b8d3962425466b6709b9ac51446f93260c54afe8e7b6d3686e34f991fb8a8953822b0deed86fe41a103f34bc48dbc4784224 - token_salt: ffffffffff - token_last_eight: ffffffff - log_filename: artifact-test2/2f/47.log - log_in_storage: 1 - log_length: 707 - log_size: 90179 - log_expired: 0 diff --git a/models/fixtures/action_variable.yml b/models/fixtures/action_variable.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/action_variable.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/deploy_key.yml b/models/fixtures/deploy_key.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/deploy_key.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/external_login_user.yml b/models/fixtures/external_login_user.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/external_login_user.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/federated_user.yml b/models/fixtures/federated_user.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/federated_user.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/federation_host.yml b/models/fixtures/federation_host.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/federation_host.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/gpg_key_import.yml b/models/fixtures/gpg_key_import.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/gpg_key_import.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/label.yml b/models/fixtures/label.yml index 84c2a7f418..acfac74968 100644 --- a/models/fixtures/label.yml +++ b/models/fixtures/label.yml @@ -3,7 +3,6 @@ repo_id: 1 org_id: 0 name: label1 - description: 'First label' color: '#abcdef' exclusive: false num_issues: 2 @@ -108,26 +107,3 @@ num_issues: 0 num_closed_issues: 0 archived_unix: 0 - -- - id: 11 - repo_id: 3 - org_id: 0 - name: " /'?&" - description: "Malicious label ' " - color: '#000000' - exclusive: true - num_issues: 0 - num_closed_issues: 0 - archived_unix: 0 - -- - id: 12 - repo_id: 3 - org_id: 0 - name: 'archived label<>' - color: '#000000' - exclusive: false - num_issues: 0 - num_closed_issues: 0 - archived_unix: 2991092130 diff --git a/models/fixtures/login_source.yml b/models/fixtures/login_source.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/login_source.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/protected_branch.yml b/models/fixtures/protected_branch.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/protected_branch.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/pull_auto_merge.yml b/models/fixtures/pull_auto_merge.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/pull_auto_merge.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/push_mirror.yml b/models/fixtures/push_mirror.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/push_mirror.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/repo_archiver.yml b/models/fixtures/repo_archiver.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/repo_archiver.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/repo_indexer_status.yml b/models/fixtures/repo_indexer_status.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/repo_indexer_status.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/repo_redirect.yml b/models/fixtures/repo_redirect.yml index 82d365c600..8850c8d780 100644 --- a/models/fixtures/repo_redirect.yml +++ b/models/fixtures/repo_redirect.yml @@ -3,9 +3,3 @@ owner_id: 2 lower_name: oldrepo1 redirect_repo_id: 1 - -- - id: 2 - owner_id: 17 - lower_name: oldrepo24 - redirect_repo_id: 24 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 2f104eed65..c383fa43ac 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -32,7 +32,7 @@ created_unix: 1731254961 updated_unix: 1731254961 topics: '[]' - + - id: 2 owner_id: 2 diff --git a/models/fixtures/secret.yml b/models/fixtures/secret.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/secret.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/fixtures/user_redirect.yml b/models/fixtures/user_redirect.yml index 2f7a523c0c..f471e94511 100644 --- a/models/fixtures/user_redirect.yml +++ b/models/fixtures/user_redirect.yml @@ -3,15 +3,3 @@ lower_name: olduser1 redirect_user_id: 1 created_unix: 1730000000 - -- - id: 2 - lower_name: oldorg22 - redirect_user_id: 22 - created_unix: 1730000000 - -- - id: 3 - lower_name: oldorg23 - redirect_user_id: 23 - created_unix: 1730000000 diff --git a/models/forgejo_migrations/main_test.go b/models/forgejo_migrations/main_test.go index 2246e327f0..031fe8090d 100644 --- a/models/forgejo_migrations/main_test.go +++ b/models/forgejo_migrations/main_test.go @@ -1,7 +1,7 @@ // Copyright 2023 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "testing" diff --git a/models/forgejo_migrations/migrate.go b/models/forgejo_migrations/migrate.go index 71fcf16e7a..94469b7371 100644 --- a/models/forgejo_migrations/migrate.go +++ b/models/forgejo_migrations/migrate.go @@ -1,7 +1,7 @@ // Copyright 2023 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "context" @@ -111,14 +111,6 @@ var migrations = []*Migration{ NewMigration("Noop because of https://codeberg.org/forgejo/forgejo/issues/8373", NoopAddIndexToActionRunStopped), // v35 -> v36 NewMigration("Fix wiki unit default permission", FixWikiUnitDefaultPermission), - // v36 -> v37 - NewMigration("Add `branch_filter` to `push_mirror` table", AddPushMirrorBranchFilter), - // v37 -> v38 - NewMigration("Add `resolved_unix` column to `abuse_report` table", AddResolvedUnixToAbuseReport), - // v38 -> v39 - NewMigration("Migrate `data` column of `secret` table to store keying material", MigrateActionSecretsToKeying), - // v39 -> v40 - NewMigration("Add index for release sha1", AddIndexForReleaseSha1), } // GetCurrentDBVersion returns the current Forgejo database version. diff --git a/models/forgejo_migrations/migrate_test.go b/models/forgejo_migrations/migrate_test.go index 9d16c9fe1c..20653929a3 100644 --- a/models/forgejo_migrations/migrate_test.go +++ b/models/forgejo_migrations/migrate_test.go @@ -1,7 +1,7 @@ // Copyright 2023 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "testing" diff --git a/models/forgejo_migrations/v13.go b/models/forgejo_migrations/v13.go index ba4183885e..614f68249d 100644 --- a/models/forgejo_migrations/v13.go +++ b/models/forgejo_migrations/v13.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v14.go b/models/forgejo_migrations/v14.go index 65b857d343..53f1ef2223 100644 --- a/models/forgejo_migrations/v14.go +++ b/models/forgejo_migrations/v14.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "forgejo.org/models/migrations/base" diff --git a/models/forgejo_migrations/v15.go b/models/forgejo_migrations/v15.go index a63199ab19..5e5588dd05 100644 --- a/models/forgejo_migrations/v15.go +++ b/models/forgejo_migrations/v15.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "time" diff --git a/models/forgejo_migrations/v16.go b/models/forgejo_migrations/v16.go index a7d4d5d590..f80bfc5268 100644 --- a/models/forgejo_migrations/v16.go +++ b/models/forgejo_migrations/v16.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v17.go b/models/forgejo_migrations/v17.go index 8ef6f2c681..d6e2983d00 100644 --- a/models/forgejo_migrations/v17.go +++ b/models/forgejo_migrations/v17.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v18.go b/models/forgejo_migrations/v18.go index e39b0cbf10..e6c1493f0e 100644 --- a/models/forgejo_migrations/v18.go +++ b/models/forgejo_migrations/v18.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v19.go b/models/forgejo_migrations/v19.go index 43d279dcb0..69b7746eb1 100644 --- a/models/forgejo_migrations/v19.go +++ b/models/forgejo_migrations/v19.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v1_20/v1.go b/models/forgejo_migrations/v1_20/v1.go index f0cb125557..72beaf23de 100644 --- a/models/forgejo_migrations/v1_20/v1.go +++ b/models/forgejo_migrations/v1_20/v1.go @@ -1,7 +1,7 @@ // Copyright 2023 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_v1_20 +package forgejo_v1_20 //nolint:revive import ( "forgejo.org/modules/timeutil" diff --git a/models/forgejo_migrations/v1_20/v2.go b/models/forgejo_migrations/v1_20/v2.go index 3f79ac3801..39f3b58924 100644 --- a/models/forgejo_migrations/v1_20/v2.go +++ b/models/forgejo_migrations/v1_20/v2.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -package forgejo_v1_20 +package forgejo_v1_20 //nolint:revive import ( "xorm.io/xorm" diff --git a/models/forgejo_migrations/v1_20/v3.go b/models/forgejo_migrations/v1_20/v3.go index 49530df556..cce227e6eb 100644 --- a/models/forgejo_migrations/v1_20/v3.go +++ b/models/forgejo_migrations/v1_20/v3.go @@ -1,7 +1,7 @@ // Copyright 2023 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_v1_20 +package forgejo_v1_20 //nolint:revive import ( "forgejo.org/modules/timeutil" diff --git a/models/forgejo_migrations/v1_22/main_test.go b/models/forgejo_migrations/v1_22/main_test.go index d6a5bdacee..03c4c5272c 100644 --- a/models/forgejo_migrations/v1_22/main_test.go +++ b/models/forgejo_migrations/v1_22/main_test.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "testing" diff --git a/models/forgejo_migrations/v1_22/v10.go b/models/forgejo_migrations/v1_22/v10.go index cf45abdd24..819800ae71 100644 --- a/models/forgejo_migrations/v1_22/v10.go +++ b/models/forgejo_migrations/v1_22/v10.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "xorm.io/xorm" diff --git a/models/forgejo_migrations/v1_22/v11.go b/models/forgejo_migrations/v1_22/v11.go index f0f92bd04c..17bb592379 100644 --- a/models/forgejo_migrations/v1_22/v11.go +++ b/models/forgejo_migrations/v1_22/v11.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/forgejo_migrations/v1_22/v12.go b/models/forgejo_migrations/v1_22/v12.go index 51354bd3c2..6822524705 100644 --- a/models/forgejo_migrations/v1_22/v12.go +++ b/models/forgejo_migrations/v1_22/v12.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v1_22/v4.go b/models/forgejo_migrations/v1_22/v4.go index 499d377bb4..f1195f5f66 100644 --- a/models/forgejo_migrations/v1_22/v4.go +++ b/models/forgejo_migrations/v1_22/v4.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "xorm.io/xorm" diff --git a/models/forgejo_migrations/v1_22/v5.go b/models/forgejo_migrations/v1_22/v5.go index 1671d3eed2..55f9fe1338 100644 --- a/models/forgejo_migrations/v1_22/v5.go +++ b/models/forgejo_migrations/v1_22/v5.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "xorm.io/xorm" diff --git a/models/forgejo_migrations/v1_22/v6.go b/models/forgejo_migrations/v1_22/v6.go index 072f8e6a15..1a4874872c 100644 --- a/models/forgejo_migrations/v1_22/v6.go +++ b/models/forgejo_migrations/v1_22/v6.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "xorm.io/xorm" diff --git a/models/forgejo_migrations/v1_22/v7.go b/models/forgejo_migrations/v1_22/v7.go index e7f6eb412b..b42dd1af67 100644 --- a/models/forgejo_migrations/v1_22/v7.go +++ b/models/forgejo_migrations/v1_22/v7.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "xorm.io/xorm" diff --git a/models/forgejo_migrations/v1_22/v8.go b/models/forgejo_migrations/v1_22/v8.go index f23b00d2ad..2d3c0c594b 100644 --- a/models/forgejo_migrations/v1_22/v8.go +++ b/models/forgejo_migrations/v1_22/v8.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "strings" diff --git a/models/forgejo_migrations/v1_22/v8_test.go b/models/forgejo_migrations/v1_22/v8_test.go index 5117dd2dfb..baaba7290f 100644 --- a/models/forgejo_migrations/v1_22/v8_test.go +++ b/models/forgejo_migrations/v1_22/v8_test.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "testing" diff --git a/models/forgejo_migrations/v1_22/v9.go b/models/forgejo_migrations/v1_22/v9.go index e3cdea97f2..34c2844c39 100644 --- a/models/forgejo_migrations/v1_22/v9.go +++ b/models/forgejo_migrations/v1_22/v9.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v20.go b/models/forgejo_migrations/v20.go index 91c7b8e911..8ca9e91f73 100644 --- a/models/forgejo_migrations/v20.go +++ b/models/forgejo_migrations/v20.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v21.go b/models/forgejo_migrations/v21.go index 61d7950c5a..53f141b2ab 100644 --- a/models/forgejo_migrations/v21.go +++ b/models/forgejo_migrations/v21.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v22.go b/models/forgejo_migrations/v22.go index 8078591da6..eeb738799c 100644 --- a/models/forgejo_migrations/v22.go +++ b/models/forgejo_migrations/v22.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v23.go b/models/forgejo_migrations/v23.go index a79a4f3d6e..20a916a716 100644 --- a/models/forgejo_migrations/v23.go +++ b/models/forgejo_migrations/v23.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v24.go b/models/forgejo_migrations/v24.go index 084a57e1ce..ebfb5fc1c4 100644 --- a/models/forgejo_migrations/v24.go +++ b/models/forgejo_migrations/v24.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v25.go b/models/forgejo_migrations/v25.go index 56cde499a3..8e3032a40c 100644 --- a/models/forgejo_migrations/v25.go +++ b/models/forgejo_migrations/v25.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "context" diff --git a/models/forgejo_migrations/v25_test.go b/models/forgejo_migrations/v25_test.go index 68e71da012..e7402fd021 100644 --- a/models/forgejo_migrations/v25_test.go +++ b/models/forgejo_migrations/v25_test.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "testing" diff --git a/models/forgejo_migrations/v26.go b/models/forgejo_migrations/v26.go index a0c47799c2..3292d93ffd 100644 --- a/models/forgejo_migrations/v26.go +++ b/models/forgejo_migrations/v26.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v27.go b/models/forgejo_migrations/v27.go index 9cfbc64370..2efa3485a8 100644 --- a/models/forgejo_migrations/v27.go +++ b/models/forgejo_migrations/v27.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: GPL-3.0-or-later -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "forgejo.org/modules/timeutil" diff --git a/models/forgejo_migrations/v28.go b/models/forgejo_migrations/v28.go index 19f0dcd862..cba888d2ec 100644 --- a/models/forgejo_migrations/v28.go +++ b/models/forgejo_migrations/v28.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v29.go b/models/forgejo_migrations/v29.go index 92eb05e8b3..d0c2f723ae 100644 --- a/models/forgejo_migrations/v29.go +++ b/models/forgejo_migrations/v29.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "database/sql" diff --git a/models/forgejo_migrations/v30.go b/models/forgejo_migrations/v30.go index 05a1dff898..6c41a55316 100644 --- a/models/forgejo_migrations/v30.go +++ b/models/forgejo_migrations/v30.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "time" diff --git a/models/forgejo_migrations/v30_test.go b/models/forgejo_migrations/v30_test.go index 152fddeb47..f826dab815 100644 --- a/models/forgejo_migrations/v30_test.go +++ b/models/forgejo_migrations/v30_test.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. // SPDX-License-Identifier: GPL-3.0-or-later -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "testing" diff --git a/models/forgejo_migrations/v31.go b/models/forgejo_migrations/v31.go index 23397c7c13..fdcab21b1a 100644 --- a/models/forgejo_migrations/v31.go +++ b/models/forgejo_migrations/v31.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. // SPDX-License-Identifier: GPL-3.0-or-later -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "xorm.io/xorm" diff --git a/models/forgejo_migrations/v31_test.go b/models/forgejo_migrations/v31_test.go index 6d1690aae0..5b4aac2a60 100644 --- a/models/forgejo_migrations/v31_test.go +++ b/models/forgejo_migrations/v31_test.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. // SPDX-License-Identifier: GPL-3.0-or-later -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "testing" diff --git a/models/forgejo_migrations/v32.go b/models/forgejo_migrations/v32.go index ce3f855694..2460003597 100644 --- a/models/forgejo_migrations/v32.go +++ b/models/forgejo_migrations/v32.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: GPL-3.0-or-later -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "encoding/xml" diff --git a/models/forgejo_migrations/v32_test.go b/models/forgejo_migrations/v32_test.go index 24cda891bc..cd33de2608 100644 --- a/models/forgejo_migrations/v32_test.go +++ b/models/forgejo_migrations/v32_test.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: GPL-3.0-or-later -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "bytes" diff --git a/models/forgejo_migrations/v33.go b/models/forgejo_migrations/v33.go index b9ea8efe47..272035fc23 100644 --- a/models/forgejo_migrations/v33.go +++ b/models/forgejo_migrations/v33.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "fmt" diff --git a/models/forgejo_migrations/v33_test.go b/models/forgejo_migrations/v33_test.go index 1d3298da15..664c704bbc 100644 --- a/models/forgejo_migrations/v33_test.go +++ b/models/forgejo_migrations/v33_test.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. // SPDX-License-Identifier: GPL-3.0-or-later -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "testing" diff --git a/models/forgejo_migrations/v34.go b/models/forgejo_migrations/v34.go index d193d799e7..9e958b934f 100644 --- a/models/forgejo_migrations/v34.go +++ b/models/forgejo_migrations/v34.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: GPL-3.0-or-later -package forgejo_migrations +package forgejo_migrations //nolint:revive import "xorm.io/xorm" diff --git a/models/forgejo_migrations/v35.go b/models/forgejo_migrations/v35.go index 9b389fcc12..ca412d7951 100644 --- a/models/forgejo_migrations/v35.go +++ b/models/forgejo_migrations/v35.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: GPL-3.0-or-later -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "xorm.io/xorm" diff --git a/models/forgejo_migrations/v36.go b/models/forgejo_migrations/v36.go index 1a798147cf..019c177a08 100644 --- a/models/forgejo_migrations/v36.go +++ b/models/forgejo_migrations/v36.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: GPL-3.0-or-later -package forgejo_migrations +package forgejo_migrations //nolint:revive import ( "xorm.io/xorm" diff --git a/models/forgejo_migrations/v37.go b/models/forgejo_migrations/v37.go deleted file mode 100644 index 89358991af..0000000000 --- a/models/forgejo_migrations/v37.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package forgejo_migrations - -import ( - "xorm.io/xorm" -) - -func AddPushMirrorBranchFilter(x *xorm.Engine) error { - type PushMirror struct { - ID int64 `xorm:"pk autoincr"` - BranchFilter string `xorm:"VARCHAR(255)"` - } - return x.Sync2(new(PushMirror)) -} diff --git a/models/forgejo_migrations/v38.go b/models/forgejo_migrations/v38.go deleted file mode 100644 index 24240f15a0..0000000000 --- a/models/forgejo_migrations/v38.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package forgejo_migrations - -import ( - "forgejo.org/modules/timeutil" - - "xorm.io/xorm" -) - -func AddResolvedUnixToAbuseReport(x *xorm.Engine) error { - type AbuseReport struct { - ID int64 `xorm:"pk autoincr"` - ResolvedUnix timeutil.TimeStamp `xorm:"DEFAULT NULL"` - } - - return x.Sync(&AbuseReport{}) -} diff --git a/models/forgejo_migrations/v39.go b/models/forgejo_migrations/v39.go deleted file mode 100644 index 9af1c250b3..0000000000 --- a/models/forgejo_migrations/v39.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package forgejo_migrations - -import ( - "context" - "fmt" - - "forgejo.org/models/db" - secret_model "forgejo.org/models/secret" - "forgejo.org/modules/log" - "forgejo.org/modules/secret" - "forgejo.org/modules/setting" - - "xorm.io/xorm" - "xorm.io/xorm/schemas" -) - -func MigrateActionSecretsToKeying(x *xorm.Engine) error { - return db.WithTx(db.DefaultContext, func(ctx context.Context) error { - sess := db.GetEngine(ctx) - - switch x.Dialect().URI().DBType { - case schemas.MYSQL: - if _, err := sess.Exec("ALTER TABLE `secret` MODIFY `data` BLOB"); err != nil { - return err - } - case schemas.SQLITE: - if _, err := sess.Exec("ALTER TABLE `secret` RENAME COLUMN `data` TO `data_backup`"); err != nil { - return err - } - if _, err := sess.Exec("ALTER TABLE `secret` ADD COLUMN `data` BLOB"); err != nil { - return err - } - if _, err := sess.Exec("UPDATE `secret` SET `data` = `data_backup`"); err != nil { - return err - } - if _, err := sess.Exec("ALTER TABLE `secret` DROP COLUMN `data_backup`"); err != nil { - return err - } - case schemas.POSTGRES: - if _, err := sess.Exec("ALTER TABLE `secret` ALTER COLUMN `data` SET DATA TYPE bytea USING data::text::bytea"); err != nil { - return err - } - } - - oldEncryptionKey := setting.SecretKey - - messages := make([]string, 0, 100) - ids := make([]int64, 0, 100) - - err := db.Iterate(ctx, nil, func(ctx context.Context, bean *secret_model.Secret) error { - secretBytes, err := secret.DecryptSecret(oldEncryptionKey, string(bean.Data)) - if err != nil { - messages = append(messages, fmt.Sprintf("secret.id=%d, secret.name=%q, secret.repo_id=%d, secret.owner_id=%d: secret.DecryptSecret(): %v", bean.ID, bean.Name, bean.RepoID, bean.OwnerID, err)) - ids = append(ids, bean.ID) - return nil - } - - bean.SetSecret(secretBytes) - _, err = sess.Cols("data").ID(bean.ID).Update(bean) - return err - }) - - if err == nil { - if len(ids) > 0 { - log.Error("Forgejo migration[37]: The following action secrets were found to be corrupted and removed from the database.") - for _, message := range messages { - log.Error("Forgejo migration[37]: %s", message) - } - - _, err = sess.In("id", ids).NoAutoCondition().NoAutoTime().Delete(&secret_model.Secret{}) - } - } - return err - }) -} diff --git a/models/forgejo_migrations/v39_test.go b/models/forgejo_migrations/v39_test.go deleted file mode 100644 index 42934d912f..0000000000 --- a/models/forgejo_migrations/v39_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package forgejo_migrations - -import ( - "testing" - - migration_tests "forgejo.org/models/migrations/test" - "forgejo.org/models/secret" - "forgejo.org/modules/keying" - "forgejo.org/modules/timeutil" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_MigrateActionSecretToKeying(t *testing.T) { - type Secret struct { - ID int64 - OwnerID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL"` - RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"` - Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"` - Data string `xorm:"LONGTEXT"` // encrypted data - CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` - } - - // Prepare and load the testing database - x, deferable := migration_tests.PrepareTestEnv(t, 0, new(Secret)) - defer deferable() - if x == nil || t.Failed() { - return - } - - cnt, err := x.Table("secret").Count() - require.NoError(t, err) - assert.EqualValues(t, 2, cnt) - - require.NoError(t, MigrateActionSecretsToKeying(x)) - - cnt, err = x.Table("secret").Count() - require.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var secret secret.Secret - _, err = x.Table("secret").ID(1).Get(&secret) - require.NoError(t, err) - - secretBytes, err := keying.DeriveKey(keying.ContextActionSecret).Decrypt(secret.Data, keying.ColumnAndID("data", secret.ID)) - require.NoError(t, err) - assert.Equal(t, []byte("A deep dark secret"), secretBytes) -} diff --git a/models/forgejo_migrations/v40.go b/models/forgejo_migrations/v40.go deleted file mode 100644 index 11e8fbd85e..0000000000 --- a/models/forgejo_migrations/v40.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forgejo_migrations - -import "xorm.io/xorm" - -func AddIndexForReleaseSha1(x *xorm.Engine) error { - type Release struct { - Sha1 string `xorm:"INDEX VARCHAR(64)"` - } - return x.Sync(new(Release)) -} diff --git a/models/issues/action_aggregator.go b/models/issues/action_aggregator.go index c4632fd4dd..d3643adeef 100644 --- a/models/issues/action_aggregator.go +++ b/models/issues/action_aggregator.go @@ -4,7 +4,6 @@ package issues import ( - "context" "slices" "forgejo.org/models/organization" @@ -375,10 +374,3 @@ func (t *RequestReviewTarget) Type() string { } return "team" } - -func (t *RequestReviewTarget) Link(ctx context.Context) string { - if t.User != nil { - return t.User.HomeLink() - } - return t.Team.Link(ctx) -} diff --git a/models/issues/action_aggregator_test.go b/models/issues/action_aggregator_test.go deleted file mode 100644 index 1962596d2d..0000000000 --- a/models/issues/action_aggregator_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package issues - -import ( - "testing" - - "forgejo.org/models/db" - org_model "forgejo.org/models/organization" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" - - "github.com/stretchr/testify/assert" -) - -func TestRequestReviewTarget(t *testing.T) { - unittest.PrepareTestEnv(t) - - target := RequestReviewTarget{User: &user_model.User{ID: 1, Name: "user1"}} - assert.Equal(t, int64(1), target.ID()) - assert.Equal(t, "user1", target.Name()) - assert.Equal(t, "user", target.Type()) - assert.Equal(t, "/user1", target.Link(db.DefaultContext)) - - target = RequestReviewTarget{Team: &org_model.Team{ID: 2, Name: "Collaborators", OrgID: 3}} - assert.Equal(t, int64(2), target.ID()) - assert.Equal(t, "Collaborators", target.Name()) - assert.Equal(t, "team", target.Type()) - assert.Equal(t, "/org/org3/teams/Collaborators", target.Link(db.DefaultContext)) - - target = RequestReviewTarget{Team: org_model.NewGhostTeam()} - assert.Equal(t, int64(-1), target.ID()) - assert.Equal(t, "Ghost team", target.Name()) - assert.Equal(t, "team", target.Type()) - assert.Empty(t, target.Link(db.DefaultContext)) -} diff --git a/models/issues/comment.go b/models/issues/comment.go index 6afd1623f3..523a6ba9b9 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -795,15 +795,16 @@ func (c *Comment) LoadPushCommits(ctx context.Context) (err error) { } c.OldCommit = data.CommitIDs[0] c.NewCommit = data.CommitIDs[1] - } + } else { + gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, c.Issue.Repo) + if err != nil { + return err + } + defer closer.Close() - gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, c.Issue.Repo) - if err != nil { - return err + c.Commits = git_model.ParseCommitsWithStatus(ctx, gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo) + c.CommitsNum = int64(len(c.Commits)) } - defer closer.Close() - c.Commits = git_model.ParseCommitsWithStatus(ctx, gitRepo.GetCommitsFromIDs(data.CommitIDs, c.IsForcePush), c.Issue.Repo) - c.CommitsNum = int64(len(c.Commits)) return err } diff --git a/models/issues/issue.go b/models/issues/issue.go index 14848e4c98..5edebb4105 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -237,7 +237,7 @@ func (issue *Issue) LoadPullRequest(ctx context.Context) (err error) { return nil } -func (issue *Issue) LoadComments(ctx context.Context) (err error) { +func (issue *Issue) loadComments(ctx context.Context) (err error) { return issue.loadCommentsByType(ctx, CommentTypeUndefined) } @@ -341,7 +341,7 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { return err } - if err = issue.LoadComments(ctx); err != nil { + if err = issue.loadComments(ctx); err != nil { return err } @@ -469,8 +469,6 @@ func (issue *Issue) GetLastEventTimestamp() timeutil.TimeStamp { } // GetLastEventLabel returns the localization label for the current issue. -// -//llu:returnsTrKey func (issue *Issue) GetLastEventLabel() string { if issue.IsClosed { if issue.IsPull && issue.PullRequest.HasMerged { @@ -496,8 +494,6 @@ func (issue *Issue) GetLastComment(ctx context.Context) (*Comment, error) { } // GetLastEventLabelFake returns the localization label for the current issue without providing a link in the username. -// -//llu:returnsTrKey func (issue *Issue) GetLastEventLabelFake() string { if issue.IsClosed { if issue.IsPull && issue.PullRequest.HasMerged { diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index 529f0c15d4..91a69c26a7 100644 --- a/models/issues/issue_search.go +++ b/models/issues/issue_search.go @@ -48,9 +48,7 @@ type IssuesOptions struct { //nolint UpdatedBeforeUnix int64 // prioritize issues from this repo PriorityRepoID int64 - // if this issue index (not ID) exists and matches the filters, *and* priorityrepo sort is used, show it first - PriorityIssueIndex int64 - IsArchived optional.Option[bool] + IsArchived optional.Option[bool] // If combined with AllPublic, then private as well as public issues // that matches the criteria will be returned, if AllPublic is false @@ -62,7 +60,7 @@ type IssuesOptions struct { //nolint // applySorts sort an issues-related session based on the provided // sortType string -func applySorts(sess *xorm.Session, sortType string, priorityRepoID, priorityIssueIndex int64) { +func applySorts(sess *xorm.Session, sortType string, priorityRepoID int64) { switch sortType { case "oldest": sess.Asc("issue.created_unix").Asc("issue.id") @@ -99,11 +97,8 @@ func applySorts(sess *xorm.Session, sortType string, priorityRepoID, priorityIss case "priorityrepo": sess.OrderBy("CASE "+ "WHEN issue.repo_id = ? THEN 1 "+ - "ELSE 2 END ASC", priorityRepoID) - if priorityIssueIndex != 0 { - sess.OrderBy("issue.index = ? DESC", priorityIssueIndex) - } - sess.Desc("issue.created_unix"). + "ELSE 2 END ASC", priorityRepoID). + Desc("issue.created_unix"). Desc("issue.id") case "project-column-sorting": sess.Asc("project_issue.sorting").Desc("issue.created_unix").Desc("issue.id") @@ -475,7 +470,7 @@ func Issues(ctx context.Context, opts *IssuesOptions) (IssueList, error) { Join("INNER", "repository", "`issue`.repo_id = `repository`.id") applyLimit(sess, opts) applyConditions(sess, opts) - applySorts(sess, opts.SortType, opts.PriorityRepoID, opts.PriorityIssueIndex) + applySorts(sess, opts.SortType, opts.PriorityRepoID) issues := IssueList{} if err := sess.Find(&issues); err != nil { @@ -499,7 +494,7 @@ func IssueIDs(ctx context.Context, opts *IssuesOptions, otherConds ...builder.Co } applyLimit(sess, opts) - applySorts(sess, opts.SortType, opts.PriorityRepoID, opts.PriorityIssueIndex) + applySorts(sess, opts.SortType, opts.PriorityRepoID) var res []int64 total, err := sess.Select("`issue`.id").Table(&Issue{}).FindAndCount(&res) diff --git a/models/issues/moderation.go b/models/issues/moderation.go index 9afb711d65..921f770d4d 100644 --- a/models/issues/moderation.go +++ b/models/issues/moderation.go @@ -5,7 +5,6 @@ package issues import ( "context" - "strconv" "forgejo.org/models/moderation" "forgejo.org/modules/json" @@ -25,21 +24,6 @@ type IssueData struct { UpdatedUnix timeutil.TimeStamp } -// Implements GetFieldsMap() from ShadowCopyData interface, returning a list of pairs -// to be used when rendering the shadow copy for admins reviewing the corresponding abuse report(s). -func (cd IssueData) GetFieldsMap() []moderation.ShadowCopyField { - return []moderation.ShadowCopyField{ - {Key: "RepoID", Value: strconv.FormatInt(cd.RepoID, 10)}, - {Key: "Index", Value: strconv.FormatInt(cd.Index, 10)}, - {Key: "PosterID", Value: strconv.FormatInt(cd.PosterID, 10)}, - {Key: "Title", Value: cd.Title}, - {Key: "Content", Value: cd.Content}, - {Key: "ContentVersion", Value: strconv.Itoa(cd.ContentVersion)}, - {Key: "CreatedUnix", Value: cd.CreatedUnix.AsLocalTime().String()}, - {Key: "UpdatedUnix", Value: cd.UpdatedUnix.AsLocalTime().String()}, - } -} - // newIssueData creates a trimmed down issue to be used just to create a JSON structure // (keeping only the fields relevant for moderation purposes) func newIssueData(issue *Issue) IssueData { @@ -47,8 +31,8 @@ func newIssueData(issue *Issue) IssueData { RepoID: issue.RepoID, Index: issue.Index, PosterID: issue.PosterID, - Title: issue.Title, Content: issue.Content, + Title: issue.Title, ContentVersion: issue.ContentVersion, CreatedUnix: issue.CreatedUnix, UpdatedUnix: issue.UpdatedUnix, @@ -66,19 +50,6 @@ type CommentData struct { UpdatedUnix timeutil.TimeStamp } -// Implements GetFieldsMap() from ShadowCopyData interface, returning a list of pairs -// to be used when rendering the shadow copy for admins reviewing the corresponding abuse report(s). -func (cd CommentData) GetFieldsMap() []moderation.ShadowCopyField { - return []moderation.ShadowCopyField{ - {Key: "PosterID", Value: strconv.FormatInt(cd.PosterID, 10)}, - {Key: "IssueID", Value: strconv.FormatInt(cd.IssueID, 10)}, - {Key: "Content", Value: cd.Content}, - {Key: "ContentVersion", Value: strconv.Itoa(cd.ContentVersion)}, - {Key: "CreatedUnix", Value: cd.CreatedUnix.AsLocalTime().String()}, - {Key: "UpdatedUnix", Value: cd.UpdatedUnix.AsLocalTime().String()}, - } -} - // newCommentData creates a trimmed down comment to be used just to create a JSON structure // (keeping only the fields relevant for moderation purposes) func newCommentData(comment *Comment) CommentData { diff --git a/models/issues/moderation_test.go b/models/issues/moderation_test.go deleted file mode 100644 index adb07bd63a..0000000000 --- a/models/issues/moderation_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package issues_test - -import ( - "testing" - - "forgejo.org/models/issues" - "forgejo.org/models/moderation" - "forgejo.org/modules/timeutil" - - "github.com/stretchr/testify/assert" -) - -const ( - tsCreated timeutil.TimeStamp = timeutil.TimeStamp(1753093500) // 2025-07-21 10:25:00 UTC - tsUpdated timeutil.TimeStamp = timeutil.TimeStamp(1753093525) // 2025-07-21 10:25:25 UTC -) - -func testShadowCopyField(t *testing.T, scField moderation.ShadowCopyField, key, value string) { - assert.Equal(t, key, scField.Key) - assert.Equal(t, value, scField.Value) -} - -func TestIssueDataGetFieldsMap(t *testing.T) { - id := issues.IssueData{ - RepoID: 2001, - Index: 2, - PosterID: 1002, - Title: "Professional marketing services", - Content: "Visit my website at promote-your-business.biz for a list of available services.", - ContentVersion: 0, - CreatedUnix: tsCreated, - UpdatedUnix: tsUpdated, - } - scFields := id.GetFieldsMap() - - if assert.Len(t, scFields, 8) { - testShadowCopyField(t, scFields[0], "RepoID", "2001") - testShadowCopyField(t, scFields[1], "Index", "2") - testShadowCopyField(t, scFields[2], "PosterID", "1002") - testShadowCopyField(t, scFields[3], "Title", "Professional marketing services") - testShadowCopyField(t, scFields[4], "Content", "Visit my website at promote-your-business.biz for a list of available services.") - testShadowCopyField(t, scFields[5], "ContentVersion", "0") - testShadowCopyField(t, scFields[6], "CreatedUnix", tsCreated.AsLocalTime().String()) - testShadowCopyField(t, scFields[7], "UpdatedUnix", tsUpdated.AsLocalTime().String()) - } -} - -func TestCommentDataGetFieldsMap(t *testing.T) { - cd := issues.CommentData{ - PosterID: 1002, - IssueID: 3001, - Content: "Check out [alexsmith/website](/alexsmith/website)", - ContentVersion: 0, - CreatedUnix: tsCreated, - UpdatedUnix: tsUpdated, - } - scFields := cd.GetFieldsMap() - - if assert.Len(t, scFields, 6) { - testShadowCopyField(t, scFields[0], "PosterID", "1002") - testShadowCopyField(t, scFields[1], "IssueID", "3001") - testShadowCopyField(t, scFields[2], "Content", "Check out [alexsmith/website](/alexsmith/website)") - testShadowCopyField(t, scFields[3], "ContentVersion", "0") - testShadowCopyField(t, scFields[4], "CreatedUnix", tsCreated.AsLocalTime().String()) - testShadowCopyField(t, scFields[5], "UpdatedUnix", tsUpdated.AsLocalTime().String()) - } -} diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go index ddb813cf44..8fc0491026 100644 --- a/models/issues/pull_list.go +++ b/models/issues/pull_list.go @@ -149,7 +149,7 @@ func PullRequests(ctx context.Context, baseRepoID int64, opts *PullRequestsOptio } findSession := listPullRequestStatement(ctx, baseRepoID, opts) - applySorts(findSession, opts.SortType, 0, 0) + applySorts(findSession, opts.SortType, 0) findSession = db.SetSessionPagination(findSession, opts) prs := make([]*PullRequest, 0, opts.PageSize) found := findSession.Find(&prs) diff --git a/models/migrations/fixtures/Test_MigrateActionSecretToKeying/secret.yml b/models/migrations/fixtures/Test_MigrateActionSecretToKeying/secret.yml deleted file mode 100644 index 908b428321..0000000000 --- a/models/migrations/fixtures/Test_MigrateActionSecretToKeying/secret.yml +++ /dev/null @@ -1,14 +0,0 @@ -- - id: 1 - owner_id: 2 - repo_id: 1 - name: SECRET_1 - data: 02458e5f341b2d5081a31283559843b6b7543ab98ed213d2b15b5cef94385fa348afa7e0875122e9 - created_unix: 1753556968 -- - id: 2 - owner_id: 2 - repo_id: 1 - name: BADBAD - data: badbad - created_unix: 1753556968 diff --git a/models/migrations/test/tests.go b/models/migrations/test/tests.go index 6be3b3c2fc..c1f0caf19b 100644 --- a/models/migrations/test/tests.go +++ b/models/migrations/test/tests.go @@ -95,8 +95,7 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu t.Logf("initializing fixtures from: %s", fixturesDir) if err := unittest.InitFixtures( unittest.FixturesOptions{ - Dir: fixturesDir, - SkipCleanRegistedModels: true, + Dir: fixturesDir, }, x); err != nil { t.Errorf("error whilst initializing fixtures from %s: %v", fixturesDir, err) return x, deferFn diff --git a/models/migrations/v1_10/v100.go b/models/migrations/v1_10/v100.go index 1742bea296..5d2fd8e244 100644 --- a/models/migrations/v1_10/v100.go +++ b/models/migrations/v1_10/v100.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import ( "net/url" diff --git a/models/migrations/v1_10/v101.go b/models/migrations/v1_10/v101.go index 6c8dfe2486..f023a2a0e7 100644 --- a/models/migrations/v1_10/v101.go +++ b/models/migrations/v1_10/v101.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_10/v88.go b/models/migrations/v1_10/v88.go index eb8e81c19e..7e86ac364f 100644 --- a/models/migrations/v1_10/v88.go +++ b/models/migrations/v1_10/v88.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import ( "crypto/sha1" diff --git a/models/migrations/v1_10/v89.go b/models/migrations/v1_10/v89.go index 0df2a6e17b..d5f27ffdc6 100644 --- a/models/migrations/v1_10/v89.go +++ b/models/migrations/v1_10/v89.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_10/v90.go b/models/migrations/v1_10/v90.go index 5521a97e32..295d4b1c1b 100644 --- a/models/migrations/v1_10/v90.go +++ b/models/migrations/v1_10/v90.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_10/v91.go b/models/migrations/v1_10/v91.go index 08db6c2742..48cac2de70 100644 --- a/models/migrations/v1_10/v91.go +++ b/models/migrations/v1_10/v91.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_10/v92.go b/models/migrations/v1_10/v92.go index b6c04a9234..9080108594 100644 --- a/models/migrations/v1_10/v92.go +++ b/models/migrations/v1_10/v92.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import ( "xorm.io/builder" diff --git a/models/migrations/v1_10/v93.go b/models/migrations/v1_10/v93.go index c131be9a8d..ee59a8db39 100644 --- a/models/migrations/v1_10/v93.go +++ b/models/migrations/v1_10/v93.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_10/v94.go b/models/migrations/v1_10/v94.go index 13b7d7b303..c131af162b 100644 --- a/models/migrations/v1_10/v94.go +++ b/models/migrations/v1_10/v94.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_10/v95.go b/models/migrations/v1_10/v95.go index 86b52026bf..3b1f67fd9c 100644 --- a/models/migrations/v1_10/v95.go +++ b/models/migrations/v1_10/v95.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_10/v96.go b/models/migrations/v1_10/v96.go index bcbd618b49..3bfb770f24 100644 --- a/models/migrations/v1_10/v96.go +++ b/models/migrations/v1_10/v96.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import ( "path/filepath" diff --git a/models/migrations/v1_10/v97.go b/models/migrations/v1_10/v97.go index 5872bb63e5..dee45b32e3 100644 --- a/models/migrations/v1_10/v97.go +++ b/models/migrations/v1_10/v97.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_10/v98.go b/models/migrations/v1_10/v98.go index d21c326459..bdd9aed089 100644 --- a/models/migrations/v1_10/v98.go +++ b/models/migrations/v1_10/v98.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_10/v99.go b/models/migrations/v1_10/v99.go index addae66be9..7f287b77aa 100644 --- a/models/migrations/v1_10/v99.go +++ b/models/migrations/v1_10/v99.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_10 +package v1_10 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_11/v102.go b/models/migrations/v1_11/v102.go index 15f0c83c36..a585d9c423 100644 --- a/models/migrations/v1_11/v102.go +++ b/models/migrations/v1_11/v102.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_11/v103.go b/models/migrations/v1_11/v103.go index a515710160..53527dac58 100644 --- a/models/migrations/v1_11/v103.go +++ b/models/migrations/v1_11/v103.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_11/v104.go b/models/migrations/v1_11/v104.go index 7461f0cda3..af3578ca4a 100644 --- a/models/migrations/v1_11/v104.go +++ b/models/migrations/v1_11/v104.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_11/v105.go b/models/migrations/v1_11/v105.go index d86973a0f6..b91340c30a 100644 --- a/models/migrations/v1_11/v105.go +++ b/models/migrations/v1_11/v105.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_11/v106.go b/models/migrations/v1_11/v106.go index edffe18683..ecb11cdd1e 100644 --- a/models/migrations/v1_11/v106.go +++ b/models/migrations/v1_11/v106.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_11/v107.go b/models/migrations/v1_11/v107.go index a158e3bb50..f0bfe5862c 100644 --- a/models/migrations/v1_11/v107.go +++ b/models/migrations/v1_11/v107.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_11/v108.go b/models/migrations/v1_11/v108.go index 8f14504ceb..a85096234d 100644 --- a/models/migrations/v1_11/v108.go +++ b/models/migrations/v1_11/v108.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_11/v109.go b/models/migrations/v1_11/v109.go index f7616aec7b..ea565ccda3 100644 --- a/models/migrations/v1_11/v109.go +++ b/models/migrations/v1_11/v109.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_11/v110.go b/models/migrations/v1_11/v110.go index e94a738f67..fce9be847e 100644 --- a/models/migrations/v1_11/v110.go +++ b/models/migrations/v1_11/v110.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_11/v111.go b/models/migrations/v1_11/v111.go index 6f531e4858..cc3dc0d545 100644 --- a/models/migrations/v1_11/v111.go +++ b/models/migrations/v1_11/v111.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "fmt" diff --git a/models/migrations/v1_11/v112.go b/models/migrations/v1_11/v112.go index 22054e6f68..6112ab51a5 100644 --- a/models/migrations/v1_11/v112.go +++ b/models/migrations/v1_11/v112.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "fmt" diff --git a/models/migrations/v1_11/v113.go b/models/migrations/v1_11/v113.go index a4d54f66fb..dea344a44f 100644 --- a/models/migrations/v1_11/v113.go +++ b/models/migrations/v1_11/v113.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "fmt" diff --git a/models/migrations/v1_11/v114.go b/models/migrations/v1_11/v114.go index 9467a8a90c..95adcee989 100644 --- a/models/migrations/v1_11/v114.go +++ b/models/migrations/v1_11/v114.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "net/url" diff --git a/models/migrations/v1_11/v115.go b/models/migrations/v1_11/v115.go index 65094df93d..3d4b41017b 100644 --- a/models/migrations/v1_11/v115.go +++ b/models/migrations/v1_11/v115.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "crypto/md5" diff --git a/models/migrations/v1_11/v116.go b/models/migrations/v1_11/v116.go index 729fbad18b..85aa76c1e0 100644 --- a/models/migrations/v1_11/v116.go +++ b/models/migrations/v1_11/v116.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_11 +package v1_11 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_12/v117.go b/models/migrations/v1_12/v117.go index 73b58ca34b..8eadcdef2b 100644 --- a/models/migrations/v1_12/v117.go +++ b/models/migrations/v1_12/v117.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_12/v118.go b/models/migrations/v1_12/v118.go index e8b4249743..eb022dc5e4 100644 --- a/models/migrations/v1_12/v118.go +++ b/models/migrations/v1_12/v118.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_12/v119.go b/models/migrations/v1_12/v119.go index b4bf29a935..60bfe6a57d 100644 --- a/models/migrations/v1_12/v119.go +++ b/models/migrations/v1_12/v119.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_12/v120.go b/models/migrations/v1_12/v120.go index 14d515f5a7..3f7ed8d373 100644 --- a/models/migrations/v1_12/v120.go +++ b/models/migrations/v1_12/v120.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_12/v121.go b/models/migrations/v1_12/v121.go index a28ae4e1c9..175ec9164d 100644 --- a/models/migrations/v1_12/v121.go +++ b/models/migrations/v1_12/v121.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_12/v122.go b/models/migrations/v1_12/v122.go index bc1b175f6a..6e31d863a1 100644 --- a/models/migrations/v1_12/v122.go +++ b/models/migrations/v1_12/v122.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_12/v123.go b/models/migrations/v1_12/v123.go index 52b10bb850..b0c3af07a3 100644 --- a/models/migrations/v1_12/v123.go +++ b/models/migrations/v1_12/v123.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_12/v124.go b/models/migrations/v1_12/v124.go index 9a93f436d4..d2ba03ffe0 100644 --- a/models/migrations/v1_12/v124.go +++ b/models/migrations/v1_12/v124.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_12/v125.go b/models/migrations/v1_12/v125.go index 7f582ecff5..ec4ffaab25 100644 --- a/models/migrations/v1_12/v125.go +++ b/models/migrations/v1_12/v125.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "fmt" diff --git a/models/migrations/v1_12/v126.go b/models/migrations/v1_12/v126.go index 64fd7f7478..ca9ec3aa3f 100644 --- a/models/migrations/v1_12/v126.go +++ b/models/migrations/v1_12/v126.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "xorm.io/builder" diff --git a/models/migrations/v1_12/v127.go b/models/migrations/v1_12/v127.go index f686fa617c..11a4042973 100644 --- a/models/migrations/v1_12/v127.go +++ b/models/migrations/v1_12/v127.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "fmt" diff --git a/models/migrations/v1_12/v128.go b/models/migrations/v1_12/v128.go index 8fca974616..6d7307f470 100644 --- a/models/migrations/v1_12/v128.go +++ b/models/migrations/v1_12/v128.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "fmt" diff --git a/models/migrations/v1_12/v129.go b/models/migrations/v1_12/v129.go index 3e4d3aca68..cf228242b9 100644 --- a/models/migrations/v1_12/v129.go +++ b/models/migrations/v1_12/v129.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_12/v130.go b/models/migrations/v1_12/v130.go index 383ef47492..bfa856796a 100644 --- a/models/migrations/v1_12/v130.go +++ b/models/migrations/v1_12/v130.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "forgejo.org/modules/json" diff --git a/models/migrations/v1_12/v131.go b/models/migrations/v1_12/v131.go index 1266c2f185..5184bc3590 100644 --- a/models/migrations/v1_12/v131.go +++ b/models/migrations/v1_12/v131.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "fmt" diff --git a/models/migrations/v1_12/v132.go b/models/migrations/v1_12/v132.go index 8b1ae6db93..3b2b28f7ab 100644 --- a/models/migrations/v1_12/v132.go +++ b/models/migrations/v1_12/v132.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "fmt" diff --git a/models/migrations/v1_12/v133.go b/models/migrations/v1_12/v133.go index 69e20597d8..c9087fc8c1 100644 --- a/models/migrations/v1_12/v133.go +++ b/models/migrations/v1_12/v133.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_12/v134.go b/models/migrations/v1_12/v134.go index 1fabdcae96..bba996fd40 100644 --- a/models/migrations/v1_12/v134.go +++ b/models/migrations/v1_12/v134.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "fmt" diff --git a/models/migrations/v1_12/v135.go b/models/migrations/v1_12/v135.go index 5df0ad7fc4..8898011df5 100644 --- a/models/migrations/v1_12/v135.go +++ b/models/migrations/v1_12/v135.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "fmt" diff --git a/models/migrations/v1_12/v136.go b/models/migrations/v1_12/v136.go index 7d246a82be..e2557ae002 100644 --- a/models/migrations/v1_12/v136.go +++ b/models/migrations/v1_12/v136.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "fmt" diff --git a/models/migrations/v1_12/v137.go b/models/migrations/v1_12/v137.go index 9d38483488..0d86b72010 100644 --- a/models/migrations/v1_12/v137.go +++ b/models/migrations/v1_12/v137.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_12/v138.go b/models/migrations/v1_12/v138.go index 4485adeb2d..8c8d353f40 100644 --- a/models/migrations/v1_12/v138.go +++ b/models/migrations/v1_12/v138.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "fmt" diff --git a/models/migrations/v1_12/v139.go b/models/migrations/v1_12/v139.go index 51e57b984a..cd7963524e 100644 --- a/models/migrations/v1_12/v139.go +++ b/models/migrations/v1_12/v139.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_12 +package v1_12 //nolint import ( "forgejo.org/modules/setting" diff --git a/models/migrations/v1_13/v140.go b/models/migrations/v1_13/v140.go index 5bb612c098..d74f808e9f 100644 --- a/models/migrations/v1_13/v140.go +++ b/models/migrations/v1_13/v140.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "fmt" diff --git a/models/migrations/v1_13/v141.go b/models/migrations/v1_13/v141.go index b54bc1727c..ae211e0e44 100644 --- a/models/migrations/v1_13/v141.go +++ b/models/migrations/v1_13/v141.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "fmt" diff --git a/models/migrations/v1_13/v142.go b/models/migrations/v1_13/v142.go index 8939f6f2f8..7490e0f3b4 100644 --- a/models/migrations/v1_13/v142.go +++ b/models/migrations/v1_13/v142.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "forgejo.org/modules/log" diff --git a/models/migrations/v1_13/v143.go b/models/migrations/v1_13/v143.go index 6a8da8b06d..1f9120e2ba 100644 --- a/models/migrations/v1_13/v143.go +++ b/models/migrations/v1_13/v143.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "forgejo.org/modules/log" diff --git a/models/migrations/v1_13/v144.go b/models/migrations/v1_13/v144.go index f138338514..7e801eab8a 100644 --- a/models/migrations/v1_13/v144.go +++ b/models/migrations/v1_13/v144.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "forgejo.org/modules/log" diff --git a/models/migrations/v1_13/v145.go b/models/migrations/v1_13/v145.go index f7d3895c84..a01f577ed1 100644 --- a/models/migrations/v1_13/v145.go +++ b/models/migrations/v1_13/v145.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "fmt" diff --git a/models/migrations/v1_13/v146.go b/models/migrations/v1_13/v146.go index e6a476a288..a1b54ee3aa 100644 --- a/models/migrations/v1_13/v146.go +++ b/models/migrations/v1_13/v146.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_13/v147.go b/models/migrations/v1_13/v147.go index 831ef5842a..cc57504c74 100644 --- a/models/migrations/v1_13/v147.go +++ b/models/migrations/v1_13/v147.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_13/v148.go b/models/migrations/v1_13/v148.go index d276db3d61..7bb8ab700b 100644 --- a/models/migrations/v1_13/v148.go +++ b/models/migrations/v1_13/v148.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_13/v149.go b/models/migrations/v1_13/v149.go index c1bfe8b09e..3a0c5909d5 100644 --- a/models/migrations/v1_13/v149.go +++ b/models/migrations/v1_13/v149.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "fmt" diff --git a/models/migrations/v1_13/v150.go b/models/migrations/v1_13/v150.go index 471a531024..be14fd130c 100644 --- a/models/migrations/v1_13/v150.go +++ b/models/migrations/v1_13/v150.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_13/v151.go b/models/migrations/v1_13/v151.go index 691b86062d..ff584fff67 100644 --- a/models/migrations/v1_13/v151.go +++ b/models/migrations/v1_13/v151.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "context" diff --git a/models/migrations/v1_13/v152.go b/models/migrations/v1_13/v152.go index 648e26446f..502c82a40d 100644 --- a/models/migrations/v1_13/v152.go +++ b/models/migrations/v1_13/v152.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_13/v153.go b/models/migrations/v1_13/v153.go index e5462fc162..0b2dd3eb62 100644 --- a/models/migrations/v1_13/v153.go +++ b/models/migrations/v1_13/v153.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_13/v154.go b/models/migrations/v1_13/v154.go index 89dc7821b2..cf31190781 100644 --- a/models/migrations/v1_13/v154.go +++ b/models/migrations/v1_13/v154.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_13 +package v1_13 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_14/main_test.go b/models/migrations/v1_14/main_test.go index 57cf995be1..c01faedc35 100644 --- a/models/migrations/v1_14/main_test.go +++ b/models/migrations/v1_14/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "testing" diff --git a/models/migrations/v1_14/v155.go b/models/migrations/v1_14/v155.go index 505a9ae033..e814f59938 100644 --- a/models/migrations/v1_14/v155.go +++ b/models/migrations/v1_14/v155.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "fmt" diff --git a/models/migrations/v1_14/v156.go b/models/migrations/v1_14/v156.go index 7bbd9f4c85..b6dc91a054 100644 --- a/models/migrations/v1_14/v156.go +++ b/models/migrations/v1_14/v156.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "fmt" diff --git a/models/migrations/v1_14/v157.go b/models/migrations/v1_14/v157.go index ba69f71130..7187278d29 100644 --- a/models/migrations/v1_14/v157.go +++ b/models/migrations/v1_14/v157.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_14/v158.go b/models/migrations/v1_14/v158.go index 2ab3c8a1f0..3fa27cfecd 100644 --- a/models/migrations/v1_14/v158.go +++ b/models/migrations/v1_14/v158.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "errors" diff --git a/models/migrations/v1_14/v159.go b/models/migrations/v1_14/v159.go index 4e921ea1c6..fdd7e12449 100644 --- a/models/migrations/v1_14/v159.go +++ b/models/migrations/v1_14/v159.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_14/v160.go b/models/migrations/v1_14/v160.go index 73f3798954..4dea91b514 100644 --- a/models/migrations/v1_14/v160.go +++ b/models/migrations/v1_14/v160.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_14/v161.go b/models/migrations/v1_14/v161.go index 9c850ad0c2..6e904cfab6 100644 --- a/models/migrations/v1_14/v161.go +++ b/models/migrations/v1_14/v161.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "context" diff --git a/models/migrations/v1_14/v162.go b/models/migrations/v1_14/v162.go index ead63f16f4..5d6d7c2e3f 100644 --- a/models/migrations/v1_14/v162.go +++ b/models/migrations/v1_14/v162.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_14/v163.go b/models/migrations/v1_14/v163.go index 06ac36cbc7..60fc98c0a4 100644 --- a/models/migrations/v1_14/v163.go +++ b/models/migrations/v1_14/v163.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_14/v164.go b/models/migrations/v1_14/v164.go index d2fd9b8464..54f6951427 100644 --- a/models/migrations/v1_14/v164.go +++ b/models/migrations/v1_14/v164.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "fmt" diff --git a/models/migrations/v1_14/v165.go b/models/migrations/v1_14/v165.go index 90fd2b1e46..9315e44197 100644 --- a/models/migrations/v1_14/v165.go +++ b/models/migrations/v1_14/v165.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_14/v166.go b/models/migrations/v1_14/v166.go index 4c106bd7da..e5731582fd 100644 --- a/models/migrations/v1_14/v166.go +++ b/models/migrations/v1_14/v166.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "crypto/sha256" diff --git a/models/migrations/v1_14/v167.go b/models/migrations/v1_14/v167.go index d77bbc401e..9d416f6a32 100644 --- a/models/migrations/v1_14/v167.go +++ b/models/migrations/v1_14/v167.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "fmt" diff --git a/models/migrations/v1_14/v168.go b/models/migrations/v1_14/v168.go index aa93eec19b..a30a8859f7 100644 --- a/models/migrations/v1_14/v168.go +++ b/models/migrations/v1_14/v168.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_14/v169.go b/models/migrations/v1_14/v169.go index 4f9df0d96f..5b81bb58b1 100644 --- a/models/migrations/v1_14/v169.go +++ b/models/migrations/v1_14/v169.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_14/v170.go b/models/migrations/v1_14/v170.go index a2ff4623e1..7b6498a3e9 100644 --- a/models/migrations/v1_14/v170.go +++ b/models/migrations/v1_14/v170.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "fmt" diff --git a/models/migrations/v1_14/v171.go b/models/migrations/v1_14/v171.go index 7b200e960a..51a35a02ad 100644 --- a/models/migrations/v1_14/v171.go +++ b/models/migrations/v1_14/v171.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "fmt" diff --git a/models/migrations/v1_14/v172.go b/models/migrations/v1_14/v172.go index c410d393f1..d49b70f5ad 100644 --- a/models/migrations/v1_14/v172.go +++ b/models/migrations/v1_14/v172.go @@ -1,7 +1,7 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_14/v173.go b/models/migrations/v1_14/v173.go index 7752fbe966..2d9eee9197 100644 --- a/models/migrations/v1_14/v173.go +++ b/models/migrations/v1_14/v173.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "fmt" diff --git a/models/migrations/v1_14/v174.go b/models/migrations/v1_14/v174.go index 4049e43070..c839e15db8 100644 --- a/models/migrations/v1_14/v174.go +++ b/models/migrations/v1_14/v174.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "fmt" diff --git a/models/migrations/v1_14/v175.go b/models/migrations/v1_14/v175.go index 49fa17d046..3cda5772a0 100644 --- a/models/migrations/v1_14/v175.go +++ b/models/migrations/v1_14/v175.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "fmt" diff --git a/models/migrations/v1_14/v176.go b/models/migrations/v1_14/v176.go index ef5dce9a02..1ed49f75fa 100644 --- a/models/migrations/v1_14/v176.go +++ b/models/migrations/v1_14/v176.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_14/v176_test.go b/models/migrations/v1_14/v176_test.go index d56b3e0470..d88ff207e7 100644 --- a/models/migrations/v1_14/v176_test.go +++ b/models/migrations/v1_14/v176_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "testing" diff --git a/models/migrations/v1_14/v177.go b/models/migrations/v1_14/v177.go index 96676bf8d9..6e1838f369 100644 --- a/models/migrations/v1_14/v177.go +++ b/models/migrations/v1_14/v177.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "fmt" diff --git a/models/migrations/v1_14/v177_test.go b/models/migrations/v1_14/v177_test.go index 0e0a67fd33..bffc6f92e3 100644 --- a/models/migrations/v1_14/v177_test.go +++ b/models/migrations/v1_14/v177_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_14 +package v1_14 //nolint import ( "testing" diff --git a/models/migrations/v1_15/main_test.go b/models/migrations/v1_15/main_test.go index 4cf6d6f695..6c04d3f5ee 100644 --- a/models/migrations/v1_15/main_test.go +++ b/models/migrations/v1_15/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "testing" diff --git a/models/migrations/v1_15/v178.go b/models/migrations/v1_15/v178.go index ca3a5c262e..6d236eb049 100644 --- a/models/migrations/v1_15/v178.go +++ b/models/migrations/v1_15/v178.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_15/v179.go b/models/migrations/v1_15/v179.go index ce514cc4a9..b990583303 100644 --- a/models/migrations/v1_15/v179.go +++ b/models/migrations/v1_15/v179.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_15/v180.go b/models/migrations/v1_15/v180.go index 0b68c3ceb7..02fbd57cdb 100644 --- a/models/migrations/v1_15/v180.go +++ b/models/migrations/v1_15/v180.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "forgejo.org/modules/json" diff --git a/models/migrations/v1_15/v181.go b/models/migrations/v1_15/v181.go index fb1d3d7a75..2185ed0213 100644 --- a/models/migrations/v1_15/v181.go +++ b/models/migrations/v1_15/v181.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "strings" diff --git a/models/migrations/v1_15/v181_test.go b/models/migrations/v1_15/v181_test.go index 8196f751e5..4154e0b1e9 100644 --- a/models/migrations/v1_15/v181_test.go +++ b/models/migrations/v1_15/v181_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "strings" diff --git a/models/migrations/v1_15/v182.go b/models/migrations/v1_15/v182.go index f53ff11df9..9ca500c0f9 100644 --- a/models/migrations/v1_15/v182.go +++ b/models/migrations/v1_15/v182.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_15/v182_test.go b/models/migrations/v1_15/v182_test.go index 2baf90d06a..6865cafac4 100644 --- a/models/migrations/v1_15/v182_test.go +++ b/models/migrations/v1_15/v182_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "testing" diff --git a/models/migrations/v1_15/v183.go b/models/migrations/v1_15/v183.go index 5684e35699..aaad64c220 100644 --- a/models/migrations/v1_15/v183.go +++ b/models/migrations/v1_15/v183.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "fmt" diff --git a/models/migrations/v1_15/v184.go b/models/migrations/v1_15/v184.go index fbe0dcd780..41b64d4743 100644 --- a/models/migrations/v1_15/v184.go +++ b/models/migrations/v1_15/v184.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "context" diff --git a/models/migrations/v1_15/v185.go b/models/migrations/v1_15/v185.go index 60af59edca..e5878ec193 100644 --- a/models/migrations/v1_15/v185.go +++ b/models/migrations/v1_15/v185.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_15/v186.go b/models/migrations/v1_15/v186.go index 55d3199335..ad75822de5 100644 --- a/models/migrations/v1_15/v186.go +++ b/models/migrations/v1_15/v186.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_15/v187.go b/models/migrations/v1_15/v187.go index fabef14779..b573fc52ef 100644 --- a/models/migrations/v1_15/v187.go +++ b/models/migrations/v1_15/v187.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_15/v188.go b/models/migrations/v1_15/v188.go index 4494e6ff05..71e45cab0e 100644 --- a/models/migrations/v1_15/v188.go +++ b/models/migrations/v1_15/v188.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_15 +package v1_15 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_16/main_test.go b/models/migrations/v1_16/main_test.go index 8c0a043be6..6f891f3e94 100644 --- a/models/migrations/v1_16/main_test.go +++ b/models/migrations/v1_16/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "testing" diff --git a/models/migrations/v1_16/v189.go b/models/migrations/v1_16/v189.go index 19bfcb2423..1ee72d9c39 100644 --- a/models/migrations/v1_16/v189.go +++ b/models/migrations/v1_16/v189.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "encoding/binary" diff --git a/models/migrations/v1_16/v189_test.go b/models/migrations/v1_16/v189_test.go index 9d74462a92..90b721d5f1 100644 --- a/models/migrations/v1_16/v189_test.go +++ b/models/migrations/v1_16/v189_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "testing" diff --git a/models/migrations/v1_16/v190.go b/models/migrations/v1_16/v190.go index 1eb6b6ddb4..5953802849 100644 --- a/models/migrations/v1_16/v190.go +++ b/models/migrations/v1_16/v190.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "fmt" diff --git a/models/migrations/v1_16/v191.go b/models/migrations/v1_16/v191.go index 427476b70b..567f88d6d1 100644 --- a/models/migrations/v1_16/v191.go +++ b/models/migrations/v1_16/v191.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "forgejo.org/modules/setting" diff --git a/models/migrations/v1_16/v192.go b/models/migrations/v1_16/v192.go index 31e8c36346..731b9fb43a 100644 --- a/models/migrations/v1_16/v192.go +++ b/models/migrations/v1_16/v192.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_16/v193.go b/models/migrations/v1_16/v193.go index a5af2de380..8d3ce7a558 100644 --- a/models/migrations/v1_16/v193.go +++ b/models/migrations/v1_16/v193.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_16/v193_test.go b/models/migrations/v1_16/v193_test.go index bf8d8a7dc6..8260acf32d 100644 --- a/models/migrations/v1_16/v193_test.go +++ b/models/migrations/v1_16/v193_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "testing" diff --git a/models/migrations/v1_16/v194.go b/models/migrations/v1_16/v194.go index 2e4ed8340e..6aa13c50cf 100644 --- a/models/migrations/v1_16/v194.go +++ b/models/migrations/v1_16/v194.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "fmt" diff --git a/models/migrations/v1_16/v195.go b/models/migrations/v1_16/v195.go index 4fd42b7bd2..6d7e94141e 100644 --- a/models/migrations/v1_16/v195.go +++ b/models/migrations/v1_16/v195.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "fmt" diff --git a/models/migrations/v1_16/v195_test.go b/models/migrations/v1_16/v195_test.go index 1fc7b51f3c..71234a6fb3 100644 --- a/models/migrations/v1_16/v195_test.go +++ b/models/migrations/v1_16/v195_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "testing" diff --git a/models/migrations/v1_16/v196.go b/models/migrations/v1_16/v196.go index 6c9caa100f..7cbafc61e5 100644 --- a/models/migrations/v1_16/v196.go +++ b/models/migrations/v1_16/v196.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "fmt" diff --git a/models/migrations/v1_16/v197.go b/models/migrations/v1_16/v197.go index 862bdfdcbd..97888b2847 100644 --- a/models/migrations/v1_16/v197.go +++ b/models/migrations/v1_16/v197.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_16/v198.go b/models/migrations/v1_16/v198.go index 5d3043eb46..8b3c73addc 100644 --- a/models/migrations/v1_16/v198.go +++ b/models/migrations/v1_16/v198.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "fmt" diff --git a/models/migrations/v1_16/v199.go b/models/migrations/v1_16/v199.go index 4020352f2b..6adcf890af 100644 --- a/models/migrations/v1_16/v199.go +++ b/models/migrations/v1_16/v199.go @@ -1,6 +1,6 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint // We used to use a table `remote_version` to store information for updater, now we use `AppState`, so this migration task is a no-op now. diff --git a/models/migrations/v1_16/v200.go b/models/migrations/v1_16/v200.go index de57fad8fe..c08c20e51d 100644 --- a/models/migrations/v1_16/v200.go +++ b/models/migrations/v1_16/v200.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "fmt" diff --git a/models/migrations/v1_16/v201.go b/models/migrations/v1_16/v201.go index 2c43698b0c..35e0c9f2fb 100644 --- a/models/migrations/v1_16/v201.go +++ b/models/migrations/v1_16/v201.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_16/v202.go b/models/migrations/v1_16/v202.go index d8c8fdcadc..6ba36152f1 100644 --- a/models/migrations/v1_16/v202.go +++ b/models/migrations/v1_16/v202.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "fmt" diff --git a/models/migrations/v1_16/v203.go b/models/migrations/v1_16/v203.go index c3241cba57..e8e6b52453 100644 --- a/models/migrations/v1_16/v203.go +++ b/models/migrations/v1_16/v203.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_16/v204.go b/models/migrations/v1_16/v204.go index 4d375307e7..ece03e1305 100644 --- a/models/migrations/v1_16/v204.go +++ b/models/migrations/v1_16/v204.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_16/v205.go b/models/migrations/v1_16/v205.go index cb452dfd7f..a064b9830d 100644 --- a/models/migrations/v1_16/v205.go +++ b/models/migrations/v1_16/v205.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_16/v206.go b/models/migrations/v1_16/v206.go index 01a9c386eb..581a7d76e9 100644 --- a/models/migrations/v1_16/v206.go +++ b/models/migrations/v1_16/v206.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "fmt" diff --git a/models/migrations/v1_16/v207.go b/models/migrations/v1_16/v207.go index 19126ead1f..91208f066c 100644 --- a/models/migrations/v1_16/v207.go +++ b/models/migrations/v1_16/v207.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_16/v208.go b/models/migrations/v1_16/v208.go index fb643324f4..1a11ef096a 100644 --- a/models/migrations/v1_16/v208.go +++ b/models/migrations/v1_16/v208.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_16/v209.go b/models/migrations/v1_16/v209.go index 230838647b..be3100e02a 100644 --- a/models/migrations/v1_16/v209.go +++ b/models/migrations/v1_16/v209.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_16/v210.go b/models/migrations/v1_16/v210.go index f48ab11db6..375a008e18 100644 --- a/models/migrations/v1_16/v210.go +++ b/models/migrations/v1_16/v210.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "crypto/ecdh" diff --git a/models/migrations/v1_16/v210_test.go b/models/migrations/v1_16/v210_test.go index 8454920aa0..f6423a5821 100644 --- a/models/migrations/v1_16/v210_test.go +++ b/models/migrations/v1_16/v210_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_16 +package v1_16 //nolint import ( "encoding/hex" diff --git a/models/migrations/v1_17/main_test.go b/models/migrations/v1_17/main_test.go index 166860b3b1..0a8e05ab5f 100644 --- a/models/migrations/v1_17/main_test.go +++ b/models/migrations/v1_17/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "testing" diff --git a/models/migrations/v1_17/v211.go b/models/migrations/v1_17/v211.go index 517cf19388..9b72c8610b 100644 --- a/models/migrations/v1_17/v211.go +++ b/models/migrations/v1_17/v211.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_17/v212.go b/models/migrations/v1_17/v212.go index 23868c0bb2..2337adcc80 100644 --- a/models/migrations/v1_17/v212.go +++ b/models/migrations/v1_17/v212.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_17/v213.go b/models/migrations/v1_17/v213.go index b2bbdf7279..bb3f466e52 100644 --- a/models/migrations/v1_17/v213.go +++ b/models/migrations/v1_17/v213.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_17/v214.go b/models/migrations/v1_17/v214.go index 1925324f0f..2268164919 100644 --- a/models/migrations/v1_17/v214.go +++ b/models/migrations/v1_17/v214.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_17/v215.go b/models/migrations/v1_17/v215.go index 431103c98e..5aae798562 100644 --- a/models/migrations/v1_17/v215.go +++ b/models/migrations/v1_17/v215.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "forgejo.org/models/pull" diff --git a/models/migrations/v1_17/v216.go b/models/migrations/v1_17/v216.go index 37aeacb6fc..268f472a42 100644 --- a/models/migrations/v1_17/v216.go +++ b/models/migrations/v1_17/v216.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint // This migration added non-ideal indices to the action table which on larger datasets slowed things down // it has been superseded by v218.go diff --git a/models/migrations/v1_17/v217.go b/models/migrations/v1_17/v217.go index fef48b7a5b..5f096d4824 100644 --- a/models/migrations/v1_17/v217.go +++ b/models/migrations/v1_17/v217.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "forgejo.org/modules/setting" diff --git a/models/migrations/v1_17/v218.go b/models/migrations/v1_17/v218.go index 412d124286..5e3dcd0841 100644 --- a/models/migrations/v1_17/v218.go +++ b/models/migrations/v1_17/v218.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "forgejo.org/modules/setting" diff --git a/models/migrations/v1_17/v219.go b/models/migrations/v1_17/v219.go index 7ca6a26be6..e90656090f 100644 --- a/models/migrations/v1_17/v219.go +++ b/models/migrations/v1_17/v219.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "time" diff --git a/models/migrations/v1_17/v220.go b/models/migrations/v1_17/v220.go index 4e010e5b76..61bbf19725 100644 --- a/models/migrations/v1_17/v220.go +++ b/models/migrations/v1_17/v220.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( packages_model "forgejo.org/models/packages" diff --git a/models/migrations/v1_17/v221.go b/models/migrations/v1_17/v221.go index 3ef34e3f06..84e9a238af 100644 --- a/models/migrations/v1_17/v221.go +++ b/models/migrations/v1_17/v221.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "encoding/base32" diff --git a/models/migrations/v1_17/v221_test.go b/models/migrations/v1_17/v221_test.go index a9c47136b2..02607d6b32 100644 --- a/models/migrations/v1_17/v221_test.go +++ b/models/migrations/v1_17/v221_test.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "encoding/base32" diff --git a/models/migrations/v1_17/v222.go b/models/migrations/v1_17/v222.go index 873769881e..ae910cbcb6 100644 --- a/models/migrations/v1_17/v222.go +++ b/models/migrations/v1_17/v222.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "context" diff --git a/models/migrations/v1_17/v223.go b/models/migrations/v1_17/v223.go index 4f5d34d841..7d92dcf5ae 100644 --- a/models/migrations/v1_17/v223.go +++ b/models/migrations/v1_17/v223.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 +package v1_17 //nolint import ( "context" diff --git a/models/migrations/v1_18/main_test.go b/models/migrations/v1_18/main_test.go index 0c20934cea..33f5c51222 100644 --- a/models/migrations/v1_18/main_test.go +++ b/models/migrations/v1_18/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 +package v1_18 //nolint import ( "testing" diff --git a/models/migrations/v1_18/v224.go b/models/migrations/v1_18/v224.go index 6dc12020ea..f3d522b91a 100644 --- a/models/migrations/v1_18/v224.go +++ b/models/migrations/v1_18/v224.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 +package v1_18 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_18/v225.go b/models/migrations/v1_18/v225.go index 266eccfff8..86bcb1323d 100644 --- a/models/migrations/v1_18/v225.go +++ b/models/migrations/v1_18/v225.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 +package v1_18 //nolint import ( "forgejo.org/modules/setting" diff --git a/models/migrations/v1_18/v226.go b/models/migrations/v1_18/v226.go index 8ed9761476..f87e24b11d 100644 --- a/models/migrations/v1_18/v226.go +++ b/models/migrations/v1_18/v226.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 +package v1_18 //nolint import ( "xorm.io/builder" diff --git a/models/migrations/v1_18/v227.go b/models/migrations/v1_18/v227.go index d39a010159..b6250fb76c 100644 --- a/models/migrations/v1_18/v227.go +++ b/models/migrations/v1_18/v227.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 +package v1_18 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_18/v228.go b/models/migrations/v1_18/v228.go index 3f5b69734d..1161c8a4c9 100644 --- a/models/migrations/v1_18/v228.go +++ b/models/migrations/v1_18/v228.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 +package v1_18 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_18/v229.go b/models/migrations/v1_18/v229.go index 00d794725f..f96dde9840 100644 --- a/models/migrations/v1_18/v229.go +++ b/models/migrations/v1_18/v229.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 +package v1_18 //nolint import ( "fmt" diff --git a/models/migrations/v1_18/v229_test.go b/models/migrations/v1_18/v229_test.go index 903a60c851..ac5e726a79 100644 --- a/models/migrations/v1_18/v229_test.go +++ b/models/migrations/v1_18/v229_test.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 +package v1_18 //nolint import ( "testing" diff --git a/models/migrations/v1_18/v230.go b/models/migrations/v1_18/v230.go index 078fce7643..ea5b4d02e1 100644 --- a/models/migrations/v1_18/v230.go +++ b/models/migrations/v1_18/v230.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 +package v1_18 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_18/v230_test.go b/models/migrations/v1_18/v230_test.go index da31b0dc9b..7dd6675673 100644 --- a/models/migrations/v1_18/v230_test.go +++ b/models/migrations/v1_18/v230_test.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 +package v1_18 //nolint import ( "testing" diff --git a/models/migrations/v1_19/main_test.go b/models/migrations/v1_19/main_test.go index 9d1c3a57ea..7c56926f4c 100644 --- a/models/migrations/v1_19/main_test.go +++ b/models/migrations/v1_19/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "testing" diff --git a/models/migrations/v1_19/v231.go b/models/migrations/v1_19/v231.go index 8ef1e4e743..79e46132f0 100644 --- a/models/migrations/v1_19/v231.go +++ b/models/migrations/v1_19/v231.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_19/v232.go b/models/migrations/v1_19/v232.go index 2aab2cf830..7fb4a5ac8d 100644 --- a/models/migrations/v1_19/v232.go +++ b/models/migrations/v1_19/v232.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "forgejo.org/modules/setting" diff --git a/models/migrations/v1_19/v233.go b/models/migrations/v1_19/v233.go index e62e8a9356..191afd4868 100644 --- a/models/migrations/v1_19/v233.go +++ b/models/migrations/v1_19/v233.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "fmt" diff --git a/models/migrations/v1_19/v233_test.go b/models/migrations/v1_19/v233_test.go index 3d5eac9887..4dc35d1e27 100644 --- a/models/migrations/v1_19/v233_test.go +++ b/models/migrations/v1_19/v233_test.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "testing" diff --git a/models/migrations/v1_19/v234.go b/models/migrations/v1_19/v234.go index e00b1cc2b6..c610a423dd 100644 --- a/models/migrations/v1_19/v234.go +++ b/models/migrations/v1_19/v234.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_19/v235.go b/models/migrations/v1_19/v235.go index 297d90f65a..3715de3920 100644 --- a/models/migrations/v1_19/v235.go +++ b/models/migrations/v1_19/v235.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_19/v236.go b/models/migrations/v1_19/v236.go index c453f95e04..fa01a6ab80 100644 --- a/models/migrations/v1_19/v236.go +++ b/models/migrations/v1_19/v236.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_19/v237.go b/models/migrations/v1_19/v237.go index cf30226ccd..b23c765aa5 100644 --- a/models/migrations/v1_19/v237.go +++ b/models/migrations/v1_19/v237.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_19/v238.go b/models/migrations/v1_19/v238.go index b257315319..7c912a8341 100644 --- a/models/migrations/v1_19/v238.go +++ b/models/migrations/v1_19/v238.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_19/v239.go b/models/migrations/v1_19/v239.go index 8f4a65be95..10076f2401 100644 --- a/models/migrations/v1_19/v239.go +++ b/models/migrations/v1_19/v239.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_19/v240.go b/models/migrations/v1_19/v240.go index c49ce2f49a..4ca5becede 100644 --- a/models/migrations/v1_19/v240.go +++ b/models/migrations/v1_19/v240.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "forgejo.org/models/db" diff --git a/models/migrations/v1_19/v241.go b/models/migrations/v1_19/v241.go index e35801a057..a617d6fd2f 100644 --- a/models/migrations/v1_19/v241.go +++ b/models/migrations/v1_19/v241.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_19/v242.go b/models/migrations/v1_19/v242.go index 87ca9cf214..bbf227ef77 100644 --- a/models/migrations/v1_19/v242.go +++ b/models/migrations/v1_19/v242.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "forgejo.org/modules/setting" diff --git a/models/migrations/v1_19/v243.go b/models/migrations/v1_19/v243.go index 9c3f372594..55bbfafb2f 100644 --- a/models/migrations/v1_19/v243.go +++ b/models/migrations/v1_19/v243.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 +package v1_19 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_20/main_test.go b/models/migrations/v1_20/main_test.go index ee5eec5ef6..f870dca429 100644 --- a/models/migrations/v1_20/main_test.go +++ b/models/migrations/v1_20/main_test.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "testing" diff --git a/models/migrations/v1_20/v244.go b/models/migrations/v1_20/v244.go index 76cdccaca5..977566ad7d 100644 --- a/models/migrations/v1_20/v244.go +++ b/models/migrations/v1_20/v244.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_20/v245.go b/models/migrations/v1_20/v245.go index 5e034568c4..7e6585388b 100644 --- a/models/migrations/v1_20/v245.go +++ b/models/migrations/v1_20/v245.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "context" diff --git a/models/migrations/v1_20/v246.go b/models/migrations/v1_20/v246.go index 22bf723404..e6340ef079 100644 --- a/models/migrations/v1_20/v246.go +++ b/models/migrations/v1_20/v246.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_20/v247.go b/models/migrations/v1_20/v247.go index 056699d744..9ed810a623 100644 --- a/models/migrations/v1_20/v247.go +++ b/models/migrations/v1_20/v247.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "forgejo.org/modules/log" diff --git a/models/migrations/v1_20/v248.go b/models/migrations/v1_20/v248.go index 4f2091e4bc..40555210e7 100644 --- a/models/migrations/v1_20/v248.go +++ b/models/migrations/v1_20/v248.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_20/v249.go b/models/migrations/v1_20/v249.go index 0aebb2a343..d2b096bf58 100644 --- a/models/migrations/v1_20/v249.go +++ b/models/migrations/v1_20/v249.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_20/v250.go b/models/migrations/v1_20/v250.go index e12223691f..cfcde2fc9b 100644 --- a/models/migrations/v1_20/v250.go +++ b/models/migrations/v1_20/v250.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "strings" diff --git a/models/migrations/v1_20/v251.go b/models/migrations/v1_20/v251.go index 7d2d259df6..c8665ba7eb 100644 --- a/models/migrations/v1_20/v251.go +++ b/models/migrations/v1_20/v251.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "forgejo.org/modules/log" diff --git a/models/migrations/v1_20/v252.go b/models/migrations/v1_20/v252.go index 435cce7ebe..bb85c78309 100644 --- a/models/migrations/v1_20/v252.go +++ b/models/migrations/v1_20/v252.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "forgejo.org/modules/log" diff --git a/models/migrations/v1_20/v253.go b/models/migrations/v1_20/v253.go index 73354fd485..5f4057e9d9 100644 --- a/models/migrations/v1_20/v253.go +++ b/models/migrations/v1_20/v253.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "forgejo.org/modules/log" diff --git a/models/migrations/v1_20/v254.go b/models/migrations/v1_20/v254.go index 9cdbfb3916..1e26979a5b 100644 --- a/models/migrations/v1_20/v254.go +++ b/models/migrations/v1_20/v254.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_20/v255.go b/models/migrations/v1_20/v255.go index baa3c4b6d8..49b0ecf220 100644 --- a/models/migrations/v1_20/v255.go +++ b/models/migrations/v1_20/v255.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_20/v256.go b/models/migrations/v1_20/v256.go index 7b84c1e154..822153b93e 100644 --- a/models/migrations/v1_20/v256.go +++ b/models/migrations/v1_20/v256.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_20/v257.go b/models/migrations/v1_20/v257.go index 8045909dba..70f229d73f 100644 --- a/models/migrations/v1_20/v257.go +++ b/models/migrations/v1_20/v257.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_20/v258.go b/models/migrations/v1_20/v258.go index 1d3faffdae..47174ce805 100644 --- a/models/migrations/v1_20/v258.go +++ b/models/migrations/v1_20/v258.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_20/v259.go b/models/migrations/v1_20/v259.go index 9b2b68263e..f10b94fa9c 100644 --- a/models/migrations/v1_20/v259.go +++ b/models/migrations/v1_20/v259.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "fmt" diff --git a/models/migrations/v1_20/v259_test.go b/models/migrations/v1_20/v259_test.go index b41b6c7995..32e4aa3050 100644 --- a/models/migrations/v1_20/v259_test.go +++ b/models/migrations/v1_20/v259_test.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 +package v1_20 //nolint import ( "sort" diff --git a/models/migrations/v1_21/main_test.go b/models/migrations/v1_21/main_test.go index 3f10a39a94..7104887afb 100644 --- a/models/migrations/v1_21/main_test.go +++ b/models/migrations/v1_21/main_test.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "testing" diff --git a/models/migrations/v1_21/v260.go b/models/migrations/v1_21/v260.go index b73b53bd61..245f3011ab 100644 --- a/models/migrations/v1_21/v260.go +++ b/models/migrations/v1_21/v260.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index 83a4927704..743bef152d 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_21/v262.go b/models/migrations/v1_21/v262.go index 6e88e29b9d..23e900572a 100644 --- a/models/migrations/v1_21/v262.go +++ b/models/migrations/v1_21/v262.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_21/v263.go b/models/migrations/v1_21/v263.go index 55c418bde0..2c7cbadf0d 100644 --- a/models/migrations/v1_21/v263.go +++ b/models/migrations/v1_21/v263.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "fmt" diff --git a/models/migrations/v1_21/v264.go b/models/migrations/v1_21/v264.go index acd2c9bb48..5615600072 100644 --- a/models/migrations/v1_21/v264.go +++ b/models/migrations/v1_21/v264.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "context" diff --git a/models/migrations/v1_21/v265.go b/models/migrations/v1_21/v265.go index b6892acc27..800eb95f72 100644 --- a/models/migrations/v1_21/v265.go +++ b/models/migrations/v1_21/v265.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_21/v266.go b/models/migrations/v1_21/v266.go index 440549e868..79a5f5e14c 100644 --- a/models/migrations/v1_21/v266.go +++ b/models/migrations/v1_21/v266.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_21/v267.go b/models/migrations/v1_21/v267.go index 13992d8776..f94696a22b 100644 --- a/models/migrations/v1_21/v267.go +++ b/models/migrations/v1_21/v267.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_21/v268.go b/models/migrations/v1_21/v268.go index b677d2383e..332793ff07 100644 --- a/models/migrations/v1_21/v268.go +++ b/models/migrations/v1_21/v268.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_21/v269.go b/models/migrations/v1_21/v269.go index 042040927d..475ec02380 100644 --- a/models/migrations/v1_21/v269.go +++ b/models/migrations/v1_21/v269.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_21/v270.go b/models/migrations/v1_21/v270.go index ab7c5660ba..b9cc84d3ac 100644 --- a/models/migrations/v1_21/v270.go +++ b/models/migrations/v1_21/v270.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_21/v271.go b/models/migrations/v1_21/v271.go index e3ce2d4b74..f45c113c1f 100644 --- a/models/migrations/v1_21/v271.go +++ b/models/migrations/v1_21/v271.go @@ -1,8 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 - +package v1_21 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_21/v272.go b/models/migrations/v1_21/v272.go index 14c1e0c4b0..a729c49f1b 100644 --- a/models/migrations/v1_21/v272.go +++ b/models/migrations/v1_21/v272.go @@ -1,8 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 - +package v1_21 //nolint import ( "xorm.io/xorm" ) diff --git a/models/migrations/v1_21/v273.go b/models/migrations/v1_21/v273.go index d6ec80d3d5..1ec6ade566 100644 --- a/models/migrations/v1_21/v273.go +++ b/models/migrations/v1_21/v273.go @@ -1,8 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 - +package v1_21 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_21/v274.go b/models/migrations/v1_21/v274.go index a1211d1fdd..b74e5fed51 100644 --- a/models/migrations/v1_21/v274.go +++ b/models/migrations/v1_21/v274.go @@ -1,8 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 - +package v1_21 //nolint import ( "time" diff --git a/models/migrations/v1_21/v275.go b/models/migrations/v1_21/v275.go index 2bfe5c72fa..78804a59d6 100644 --- a/models/migrations/v1_21/v275.go +++ b/models/migrations/v1_21/v275.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_21/v276.go b/models/migrations/v1_21/v276.go index 3b0bc23da7..0830c3bd92 100644 --- a/models/migrations/v1_21/v276.go +++ b/models/migrations/v1_21/v276.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( repo_model "forgejo.org/models/repo" diff --git a/models/migrations/v1_21/v277.go b/models/migrations/v1_21/v277.go index 0c102eddde..12529160b7 100644 --- a/models/migrations/v1_21/v277.go +++ b/models/migrations/v1_21/v277.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_21/v278.go b/models/migrations/v1_21/v278.go index 846f228678..d6a462d1e7 100644 --- a/models/migrations/v1_21/v278.go +++ b/models/migrations/v1_21/v278.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_21/v279.go b/models/migrations/v1_21/v279.go index beb39effe1..2abd1bbe84 100644 --- a/models/migrations/v1_21/v279.go +++ b/models/migrations/v1_21/v279.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 +package v1_21 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_22/main_test.go b/models/migrations/v1_22/main_test.go index 7b05993e09..dc991b78fe 100644 --- a/models/migrations/v1_22/main_test.go +++ b/models/migrations/v1_22/main_test.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "testing" diff --git a/models/migrations/v1_22/v280.go b/models/migrations/v1_22/v280.go index 2271cb6089..a8ee4a3bf7 100644 --- a/models/migrations/v1_22/v280.go +++ b/models/migrations/v1_22/v280.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_22/v281.go b/models/migrations/v1_22/v281.go index 2eeca9be82..5271c786be 100644 --- a/models/migrations/v1_22/v281.go +++ b/models/migrations/v1_22/v281.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_22/v282.go b/models/migrations/v1_22/v282.go index eed64c30f7..baad9e0916 100644 --- a/models/migrations/v1_22/v282.go +++ b/models/migrations/v1_22/v282.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_22/v283.go b/models/migrations/v1_22/v283.go index 33a2513069..86946d1c39 100644 --- a/models/migrations/v1_22/v283.go +++ b/models/migrations/v1_22/v283.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_22/v283_test.go b/models/migrations/v1_22/v283_test.go index 652d96ac16..d8e147a131 100644 --- a/models/migrations/v1_22/v283_test.go +++ b/models/migrations/v1_22/v283_test.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "testing" diff --git a/models/migrations/v1_22/v284.go b/models/migrations/v1_22/v284.go index 31b38f6aed..2b95078980 100644 --- a/models/migrations/v1_22/v284.go +++ b/models/migrations/v1_22/v284.go @@ -1,8 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 - +package v1_22 //nolint import ( "xorm.io/xorm" ) diff --git a/models/migrations/v1_22/v285.go b/models/migrations/v1_22/v285.go index fed89f670e..a55cc17c04 100644 --- a/models/migrations/v1_22/v285.go +++ b/models/migrations/v1_22/v285.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "time" diff --git a/models/migrations/v1_22/v286.go b/models/migrations/v1_22/v286.go index 05247bb436..d0489e7aeb 100644 --- a/models/migrations/v1_22/v286.go +++ b/models/migrations/v1_22/v286.go @@ -1,6 +1,6 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "fmt" diff --git a/models/migrations/v1_22/v286_test.go b/models/migrations/v1_22/v286_test.go index 5bb3334df2..c63deef495 100644 --- a/models/migrations/v1_22/v286_test.go +++ b/models/migrations/v1_22/v286_test.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "testing" diff --git a/models/migrations/v1_22/v287.go b/models/migrations/v1_22/v287.go index 5fd901f9de..c8b1593286 100644 --- a/models/migrations/v1_22/v287.go +++ b/models/migrations/v1_22/v287.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_22/v288.go b/models/migrations/v1_22/v288.go index 78be3b6ef2..44e4991851 100644 --- a/models/migrations/v1_22/v288.go +++ b/models/migrations/v1_22/v288.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_22/v289.go b/models/migrations/v1_22/v289.go index 78689a4ffa..b9941aadd9 100644 --- a/models/migrations/v1_22/v289.go +++ b/models/migrations/v1_22/v289.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_22/v290.go b/models/migrations/v1_22/v290.go index ebafab6567..594e417644 100644 --- a/models/migrations/v1_22/v290.go +++ b/models/migrations/v1_22/v290.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_22/v290_test.go b/models/migrations/v1_22/v290_test.go index a1907cf4d6..569d77bc16 100644 --- a/models/migrations/v1_22/v290_test.go +++ b/models/migrations/v1_22/v290_test.go @@ -1,7 +1,7 @@ // Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "strconv" diff --git a/models/migrations/v1_22/v291.go b/models/migrations/v1_22/v291.go index 823a644a95..74726fae96 100644 --- a/models/migrations/v1_22/v291.go +++ b/models/migrations/v1_22/v291.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_22/v292.go b/models/migrations/v1_22/v292.go index 440f48ce80..beca556aee 100644 --- a/models/migrations/v1_22/v292.go +++ b/models/migrations/v1_22/v292.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint // NOTE: noop the original migration has bug which some projects will be skip, so // these projects will have no default board. diff --git a/models/migrations/v1_22/v293.go b/models/migrations/v1_22/v293.go index e9c9746b26..9f38c3db56 100644 --- a/models/migrations/v1_22/v293.go +++ b/models/migrations/v1_22/v293.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "forgejo.org/modules/setting" diff --git a/models/migrations/v1_22/v293_test.go b/models/migrations/v1_22/v293_test.go index 6b1931b761..444146737d 100644 --- a/models/migrations/v1_22/v293_test.go +++ b/models/migrations/v1_22/v293_test.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "testing" diff --git a/models/migrations/v1_22/v294.go b/models/migrations/v1_22/v294.go index 6c52372306..314b4519f1 100644 --- a/models/migrations/v1_22/v294.go +++ b/models/migrations/v1_22/v294.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_22/v294_test.go b/models/migrations/v1_22/v294_test.go index e87a4bc85f..ef7b67ca5b 100644 --- a/models/migrations/v1_22/v294_test.go +++ b/models/migrations/v1_22/v294_test.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import ( "slices" @@ -45,8 +45,7 @@ func Test_AddUniqueIndexForProjectIssue(t *testing.T) { for _, index := range tables[0].Indexes { if index.Type == schemas.UniqueType { found = true - slices.Sort(index.Cols) - assert.Equal(t, []string{"issue_id", "project_id"}, index.Cols) + slices.Equal(index.Cols, []string{"project_id", "issue_id"}) break } } diff --git a/models/migrations/v1_22/v295.go b/models/migrations/v1_22/v295.go index 319b1a399b..17bdadb4ad 100644 --- a/models/migrations/v1_22/v295.go +++ b/models/migrations/v1_22/v295.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_22/v296.go b/models/migrations/v1_22/v296.go index 75350f9f65..1ecacab95f 100644 --- a/models/migrations/v1_22/v296.go +++ b/models/migrations/v1_22/v296.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_22/v298.go b/models/migrations/v1_22/v298.go index 7700173a00..b9f3b95ade 100644 --- a/models/migrations/v1_22/v298.go +++ b/models/migrations/v1_22/v298.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 +package v1_22 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_23/main_test.go b/models/migrations/v1_23/main_test.go index 5fb4fec999..0fd90a4a67 100644 --- a/models/migrations/v1_23/main_test.go +++ b/models/migrations/v1_23/main_test.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 +package v1_23 //nolint import ( "testing" diff --git a/models/migrations/v1_23/v299.go b/models/migrations/v1_23/v299.go index 73ce19c875..f6db960c3b 100644 --- a/models/migrations/v1_23/v299.go +++ b/models/migrations/v1_23/v299.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 +package v1_23 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_23/v300.go b/models/migrations/v1_23/v300.go index 404d8dbea8..f1f1cccdbf 100644 --- a/models/migrations/v1_23/v300.go +++ b/models/migrations/v1_23/v300.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 +package v1_23 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_23/v301.go b/models/migrations/v1_23/v301.go index f2a4d8c559..b7797f6c6b 100644 --- a/models/migrations/v1_23/v301.go +++ b/models/migrations/v1_23/v301.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 +package v1_23 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_23/v302.go b/models/migrations/v1_23/v302.go index 1b056993bd..c8ed786d63 100644 --- a/models/migrations/v1_23/v302.go +++ b/models/migrations/v1_23/v302.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 +package v1_23 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_23/v303.go b/models/migrations/v1_23/v303.go index 03197d2857..fae0131bdd 100644 --- a/models/migrations/v1_23/v303.go +++ b/models/migrations/v1_23/v303.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. // SPDX-License-Identifier: GPL-3.0-or-later -package v1_23 +package v1_23 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_23/v303_test.go b/models/migrations/v1_23/v303_test.go index f2c764bae3..f105d11830 100644 --- a/models/migrations/v1_23/v303_test.go +++ b/models/migrations/v1_23/v303_test.go @@ -1,7 +1,7 @@ // Copyright 2025 The Forgejo Authors. // SPDX-License-Identifier: GPL-3.0-or-later -package v1_23 +package v1_23 //nolint import ( "testing" diff --git a/models/migrations/v1_6/v70.go b/models/migrations/v1_6/v70.go index eb669f57b6..ec6bd09bb5 100644 --- a/models/migrations/v1_6/v70.go +++ b/models/migrations/v1_6/v70.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_6 +package v1_6 //nolint import ( "fmt" diff --git a/models/migrations/v1_6/v71.go b/models/migrations/v1_6/v71.go index 42fe8cd1ba..3706ad4406 100644 --- a/models/migrations/v1_6/v71.go +++ b/models/migrations/v1_6/v71.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_6 +package v1_6 //nolint import ( "fmt" diff --git a/models/migrations/v1_6/v72.go b/models/migrations/v1_6/v72.go index 7cd2331376..4df2a0f6e9 100644 --- a/models/migrations/v1_6/v72.go +++ b/models/migrations/v1_6/v72.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_6 +package v1_6 //nolint import ( "fmt" diff --git a/models/migrations/v1_7/v73.go b/models/migrations/v1_7/v73.go index e0b7a28537..b5a748aae3 100644 --- a/models/migrations/v1_7/v73.go +++ b/models/migrations/v1_7/v73.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_7 +package v1_7 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_7/v74.go b/models/migrations/v1_7/v74.go index 376be37a24..f0567e3c9b 100644 --- a/models/migrations/v1_7/v74.go +++ b/models/migrations/v1_7/v74.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_7 +package v1_7 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_7/v75.go b/models/migrations/v1_7/v75.go index ef11575466..fa7430970c 100644 --- a/models/migrations/v1_7/v75.go +++ b/models/migrations/v1_7/v75.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_7 +package v1_7 //nolint import ( "xorm.io/builder" diff --git a/models/migrations/v1_8/v76.go b/models/migrations/v1_8/v76.go index 8d47280b41..61ad006a47 100644 --- a/models/migrations/v1_8/v76.go +++ b/models/migrations/v1_8/v76.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 +package v1_8 //nolint import ( "fmt" diff --git a/models/migrations/v1_8/v77.go b/models/migrations/v1_8/v77.go index 4fe5ebe635..8b19993924 100644 --- a/models/migrations/v1_8/v77.go +++ b/models/migrations/v1_8/v77.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 +package v1_8 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_8/v78.go b/models/migrations/v1_8/v78.go index 840fc20d96..8102b19335 100644 --- a/models/migrations/v1_8/v78.go +++ b/models/migrations/v1_8/v78.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 +package v1_8 //nolint import ( "forgejo.org/models/migrations/base" diff --git a/models/migrations/v1_8/v79.go b/models/migrations/v1_8/v79.go index c8e0db531f..f7d2d68f96 100644 --- a/models/migrations/v1_8/v79.go +++ b/models/migrations/v1_8/v79.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 +package v1_8 //nolint import ( "forgejo.org/modules/setting" diff --git a/models/migrations/v1_8/v80.go b/models/migrations/v1_8/v80.go index 6f9df47a93..cebbbead28 100644 --- a/models/migrations/v1_8/v80.go +++ b/models/migrations/v1_8/v80.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 +package v1_8 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_8/v81.go b/models/migrations/v1_8/v81.go index 8152a47ad7..734fc24641 100644 --- a/models/migrations/v1_8/v81.go +++ b/models/migrations/v1_8/v81.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 +package v1_8 //nolint import ( "fmt" diff --git a/models/migrations/v1_9/v82.go b/models/migrations/v1_9/v82.go index 235c73c504..78a90bdde9 100644 --- a/models/migrations/v1_9/v82.go +++ b/models/migrations/v1_9/v82.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_9 +package v1_9 //nolint import ( "fmt" diff --git a/models/migrations/v1_9/v83.go b/models/migrations/v1_9/v83.go index 9640564a44..fa24a92d28 100644 --- a/models/migrations/v1_9/v83.go +++ b/models/migrations/v1_9/v83.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_9 +package v1_9 //nolint import ( "forgejo.org/modules/timeutil" diff --git a/models/migrations/v1_9/v84.go b/models/migrations/v1_9/v84.go index 423915ae57..c7155fe9cf 100644 --- a/models/migrations/v1_9/v84.go +++ b/models/migrations/v1_9/v84.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_9 +package v1_9 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_9/v85.go b/models/migrations/v1_9/v85.go index 9d5adc82dd..d8e9d91840 100644 --- a/models/migrations/v1_9/v85.go +++ b/models/migrations/v1_9/v85.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_9 +package v1_9 //nolint import ( "fmt" diff --git a/models/migrations/v1_9/v86.go b/models/migrations/v1_9/v86.go index 9464ff0cf6..cf2725d158 100644 --- a/models/migrations/v1_9/v86.go +++ b/models/migrations/v1_9/v86.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_9 +package v1_9 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_9/v87.go b/models/migrations/v1_9/v87.go index 81a4ebf80d..fa01b6e5e3 100644 --- a/models/migrations/v1_9/v87.go +++ b/models/migrations/v1_9/v87.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_9 +package v1_9 //nolint import ( "xorm.io/xorm" diff --git a/models/moderation/abuse_report.go b/models/moderation/abuse_report.go index 152b81bb51..3a6244ef4c 100644 --- a/models/moderation/abuse_report.go +++ b/models/moderation/abuse_report.go @@ -8,7 +8,6 @@ import ( "database/sql" "errors" "slices" - "time" "forgejo.org/models/db" "forgejo.org/modules/log" @@ -48,22 +47,14 @@ const ( AbuseCategoryTypeIllegalContent // 4 ) -// llu:TrKeys -var AbuseCategoriesTranslationKeys = map[AbuseCategoryType]string{ - AbuseCategoryTypeSpam: "moderation.abuse_category.spam", - AbuseCategoryTypeMalware: "moderation.abuse_category.malware", - AbuseCategoryTypeIllegalContent: "moderation.abuse_category.illegal_content", - AbuseCategoryTypeOther: "moderation.abuse_category.other_violations", -} - // GetAbuseCategoriesList returns a list of pairs with the available abuse category types // and their corresponding translation keys func GetAbuseCategoriesList() []AbuseCategoryItem { return []AbuseCategoryItem{ - {AbuseCategoryTypeSpam, AbuseCategoriesTranslationKeys[AbuseCategoryTypeSpam]}, - {AbuseCategoryTypeMalware, AbuseCategoriesTranslationKeys[AbuseCategoryTypeMalware]}, - {AbuseCategoryTypeIllegalContent, AbuseCategoriesTranslationKeys[AbuseCategoryTypeIllegalContent]}, - {AbuseCategoryTypeOther, AbuseCategoriesTranslationKeys[AbuseCategoryTypeOther]}, + {AbuseCategoryTypeSpam, "moderation.abuse_category.spam"}, + {AbuseCategoryTypeMalware, "moderation.abuse_category.malware"}, + {AbuseCategoryTypeIllegalContent, "moderation.abuse_category.illegal_content"}, + {AbuseCategoryTypeOther, "moderation.abuse_category.other_violations"}, } } @@ -113,7 +104,6 @@ type AbuseReport struct { // The ID of the corresponding shadow-copied content when exists; otherwise null. ShadowCopyID sql.NullInt64 `xorm:"DEFAULT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` - ResolvedUnix timeutil.TimeStamp `xorm:"DEFAULT NULL"` } var ErrSelfReporting = errors.New("reporting yourself is not allowed") @@ -164,25 +154,6 @@ func ReportAbuse(ctx context.Context, report *AbuseReport) error { return err } -// GetResolvedReports gets all resolved reports -func GetResolvedReports(ctx context.Context, keepReportsFor time.Duration) ([]*AbuseReport, error) { - cond := builder.And( - builder.Or( - builder.Eq{"`status`": ReportStatusTypeHandled}, - builder.Eq{"`status`": ReportStatusTypeIgnored}, - ), - ) - - if keepReportsFor > 0 { - cond = cond.And(builder.Lt{"resolved_unix": time.Now().Add(-keepReportsFor).Unix()}) - } - - abuseReports := make([]*AbuseReport, 0, 30) - return abuseReports, db.GetEngine(ctx). - Where(cond). - Find(&abuseReports) -} - /* // MarkAsHandled will change the status to 'Handled' for all reports linked to the same item (user, repository, issue or comment). func MarkAsHandled(ctx context.Context, contentType ReportedContentType, contentID int64) error { diff --git a/models/moderation/abuse_report_detailed.go b/models/moderation/abuse_report_detailed.go deleted file mode 100644 index 265d143709..0000000000 --- a/models/moderation/abuse_report_detailed.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package moderation - -import ( - "context" - "fmt" - "strings" - - "forgejo.org/models/db" - "forgejo.org/modules/setting" - "forgejo.org/modules/timeutil" - - "xorm.io/builder" -) - -type AbuseReportDetailed struct { - AbuseReport `xorm:"extends"` - ReportedTimes int // only for overview - ReporterName string - ContentReference string - ShadowCopyDate timeutil.TimeStamp // only for details - ShadowCopyRawValue string // only for details -} - -func (ard AbuseReportDetailed) ContentTypeIconName() string { - switch ard.ContentType { - case ReportedContentTypeUser: - return "octicon-person" - case ReportedContentTypeRepository: - return "octicon-repo" - case ReportedContentTypeIssue: - return "octicon-issue-opened" - case ReportedContentTypeComment: - return "octicon-comment" - default: - return "octicon-question" - } -} - -func (ard AbuseReportDetailed) ContentURL() string { - switch ard.ContentType { - case ReportedContentTypeUser: - return strings.TrimLeft(ard.ContentReference, "@") - case ReportedContentTypeIssue: - return strings.ReplaceAll(ard.ContentReference, "#", "/issues/") - default: - return ard.ContentReference - } -} - -func GetOpenReports(ctx context.Context) ([]*AbuseReportDetailed, error) { - var reports []*AbuseReportDetailed - - // - For PostgreSQL user table name should be escaped. - // - Escaping can be done with double quotes (") but this doesn't work for MariaDB. - // - For SQLite index column name should be escaped. - // - Escaping can be done with double quotes (") or backticks (`). - // - For MariaDB/MySQL there is no need to escape the above. - // - Therefore we will use double quotes (") but only for PostgreSQL and SQLite. - identifierEscapeChar := `` - if setting.Database.Type.IsPostgreSQL() || setting.Database.Type.IsSQLite3() { - identifierEscapeChar = `"` - } - - err := db.GetEngine(ctx).SQL(fmt.Sprintf(`SELECT AR.*, ARD.reported_times, U.name AS reporter_name, REFS.ref AS content_reference - FROM abuse_report AR - INNER JOIN ( - SELECT min(id) AS id, count(id) AS reported_times - FROM abuse_report - WHERE status = %[2]d - GROUP BY content_type, content_id - ) ARD ON ARD.id = AR.id - LEFT JOIN %[1]suser%[1]s U ON U.id = AR.reporter_id - LEFT JOIN ( - SELECT %[3]d AS type, id, concat('@', name) AS "ref" - FROM %[1]suser%[1]s WHERE id IN ( - SELECT content_id FROM abuse_report WHERE status = %[2]d AND content_type = %[3]d - ) - UNION - SELECT %[4]d AS "type", id, concat(owner_name, '/', name) AS "ref" - FROM repository WHERE id IN ( - SELECT content_id FROM abuse_report WHERE status = %[2]d AND content_type = %[4]d - ) - UNION - SELECT %[5]d AS "type", I.id, concat(IR.owner_name, '/', IR.name, '#', I.%[1]sindex%[1]s) AS "ref" - FROM issue I - LEFT JOIN repository IR ON IR.id = I.repo_id - WHERE I.id IN ( - SELECT content_id FROM abuse_report WHERE status = %[2]d AND content_type = %[5]d - ) - UNION - SELECT %[6]d AS "type", C.id, concat(CIR.owner_name, '/', CIR.name, '/issues/', CI.%[1]sindex%[1]s, '#issuecomment-', C.id) AS "ref" - FROM comment C - LEFT JOIN issue CI ON CI.id = C.issue_id - LEFT JOIN repository CIR ON CIR.id = CI.repo_id - WHERE C.id IN ( - SELECT content_id FROM abuse_report WHERE status = %[2]d AND content_type = %[6]d - ) - ) REFS ON REFS.type = AR.content_type AND REFS.id = AR.content_id - ORDER BY AR.created_unix ASC`, identifierEscapeChar, ReportStatusTypeOpen, - ReportedContentTypeUser, ReportedContentTypeRepository, ReportedContentTypeIssue, ReportedContentTypeComment)). - Find(&reports) - if err != nil { - return nil, err - } - return reports, nil -} - -func GetOpenReportsByTypeAndContentID(ctx context.Context, contentType ReportedContentType, contentID int64) ([]*AbuseReportDetailed, error) { - var reports []*AbuseReportDetailed - - // Some remarks concerning PostgreSQL: - // - user table should be escaped (e.g. `user`); - // - tried to use aliases for table names but errors like 'invalid reference to FROM-clause entry' - // or 'missing FROM-clause entry' were returned; - err := db.GetEngine(ctx). - Select("abuse_report.*, `user`.name AS reporter_name, abuse_report_shadow_copy.created_unix AS shadow_copy_date, abuse_report_shadow_copy.raw_value AS shadow_copy_raw_value"). - Table("abuse_report"). - Join("LEFT", "user", "`user`.id = abuse_report.reporter_id"). - Join("LEFT", "abuse_report_shadow_copy", "abuse_report_shadow_copy.id = abuse_report.shadow_copy_id"). - Where(builder.Eq{ - "content_type": contentType, - "content_id": contentID, - "status": ReportStatusTypeOpen, - }). - Asc("abuse_report.created_unix"). - Find(&reports) - if err != nil { - return nil, err - } - - return reports, nil -} diff --git a/models/moderation/shadow_copy.go b/models/moderation/shadow_copy.go index 8abb32e8ec..d363610a48 100644 --- a/models/moderation/shadow_copy.go +++ b/models/moderation/shadow_copy.go @@ -26,22 +26,6 @@ func (sc AbuseReportShadowCopy) NullableID() sql.NullInt64 { return sql.NullInt64{Int64: sc.ID, Valid: sc.ID > 0} } -// ShadowCopyField defines a pair of a value stored within the shadow copy -// (of some content reported as abusive) and a corresponding key (caption). -// A list of such pairs is used when rendering shadow copies for admins reviewing abuse reports. -type ShadowCopyField struct { - Key string - Value string -} - -// ShadowCopyData interface should be implemented by the type structs used for marshaling/unmarshaling the fields -// preserved as shadow copies for abusive content reports (i.e. UserData, RepositoryData, IssueData, CommentData). -type ShadowCopyData interface { - // GetFieldsMap returns a list of pairs with the fields stored within shadow copies - // of content reported as abusive, to be used when rendering a shadow copy in the admin UI. - GetFieldsMap() []ShadowCopyField -} - func init() { // RegisterModel will create the table if does not already exist // or any missing columns if the table was previously created. diff --git a/models/organization/org.go b/models/organization/org.go index c4df5d4fe1..ff95261051 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -186,11 +186,6 @@ func (org *Organization) CanCreateRepo() bool { return org.AsUser().CanCreateRepo() } -// IsGhost returns if the organization is a ghost -func (org *Organization) IsGhost() bool { - return org.AsUser().IsGhost() -} - // FindOrgMembersOpts represensts find org members conditions type FindOrgMembersOpts struct { db.ListOptions diff --git a/models/organization/org_list.go b/models/organization/org_list.go index 371993cdee..e387936473 100644 --- a/models/organization/org_list.go +++ b/models/organization/org_list.go @@ -71,8 +71,11 @@ func GetOrgsCanCreateRepoByUserID(ctx context.Context, userID int64) ([]*Organiz Find(&orgs) } +// MinimalOrg represents a simple organization with only the needed columns +type MinimalOrg = Organization + // GetUserOrgsList returns all organizations the given user has access to -func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*Organization, error) { +func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*MinimalOrg, error) { schema, err := db.TableInfo(new(user_model.User)) if err != nil { return nil, err @@ -97,7 +100,7 @@ func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*Organizatio } columnsStr := selectColumns.String() - var orgs []*Organization + var orgs []*MinimalOrg if err := db.GetEngine(ctx).Select(columnsStr). Table("user"). Where(builder.In("`user`.`id`", queryUserOrgIDs(user.ID, true))). @@ -135,7 +138,6 @@ func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*Organizatio for _, org := range orgs { org.NumRepos = orgCountMap[org.ID] - org.Type = user_model.UserTypeOrganization } return orgs, nil diff --git a/models/organization/org_list_test.go b/models/organization/org_list_test.go index 6e8c0bac26..170e2bf131 100644 --- a/models/organization/org_list_test.go +++ b/models/organization/org_list_test.go @@ -85,11 +85,11 @@ func TestGetUserOrgsList(t *testing.T) { require.NoError(t, unittest.PrepareTestDatabase()) orgs, err := organization.GetUserOrgsList(db.DefaultContext, &user_model.User{ID: 4}) require.NoError(t, err) - assert.Len(t, orgs, 1) - assert.EqualValues(t, 3, orgs[0].ID) - // repo_id: 3 is in the team, 32 is public, 5 is private with no team - assert.Equal(t, 2, orgs[0].NumRepos) - assert.Equal(t, user_model.UserTypeOrganization, orgs[0].Type) + if assert.Len(t, orgs, 1) { + assert.EqualValues(t, 3, orgs[0].ID) + // repo_id: 3 is in the team, 32 is public, 5 is private with no team + assert.Equal(t, 2, orgs[0].NumRepos) + } } func TestGetUserOrgsListSorting(t *testing.T) { @@ -97,7 +97,7 @@ func TestGetUserOrgsListSorting(t *testing.T) { orgs, err := organization.GetUserOrgsList(db.DefaultContext, &user_model.User{ID: 1}) require.NoError(t, err) - isSorted := slices.IsSortedFunc(orgs, func(a, b *organization.Organization) int { + isSorted := slices.IsSortedFunc(orgs, func(a, b *organization.MinimalOrg) int { return strings.Compare(strings.ToLower(a.Name), strings.ToLower(b.Name)) }) diff --git a/models/organization/team.go b/models/organization/team.go index 209471e013..c78eff39fb 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -1,6 +1,5 @@ -// Copyright 2016 The Gogs Authors. All rights reserved. // Copyright 2018 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. +// Copyright 2016 The Gogs Authors. All rights reserved. // SPDX-License-Identifier: MIT package organization @@ -8,7 +7,6 @@ package organization import ( "context" "fmt" - "net/url" "strings" "forgejo.org/models/db" @@ -22,6 +20,13 @@ import ( "xorm.io/builder" ) +// ___________ +// \__ ___/___ _____ _____ +// | |_/ __ \\__ \ / \ +// | |\ ___/ / __ \| Y Y \ +// |____| \___ >____ /__|_| / +// \/ \/ \/ + // ErrTeamAlreadyExist represents a "TeamAlreadyExist" kind of error. type ErrTeamAlreadyExist struct { OrgID int64 @@ -188,27 +193,6 @@ func (t *Team) UnitAccessMode(ctx context.Context, tp unit.Type) perm.AccessMode return perm.AccessModeNone } -// GetOrg returns the team's organization -func (t *Team) GetOrg(ctx context.Context) *Organization { - org, err := GetOrgByID(ctx, t.OrgID) - if err != nil { - return OrgFromUser(user_model.NewGhostUser()) - } - return org -} - -// Link returns the team's page link -func (t *Team) Link(ctx context.Context) string { - if t.IsGhost() { - return "" - } - org := t.GetOrg(ctx) - if org.IsGhost() { - return "" - } - return org.OrganisationLink() + "/teams/" + url.PathEscape(t.Name) -} - // IsUsableTeamName tests if a name could be as team name func IsUsableTeamName(name string) error { switch name { @@ -309,22 +293,10 @@ func FixInconsistentOwnerTeams(ctx context.Context) (int64, error) { return int64(len(teamIDs)), nil } -const ( - GhostTeamID = -1 - GhostTeamName = "Ghost team" - GhostTeamLowerName = "ghost team" -) - -// NewGhostTeam creates ghost team (for deleted team) func NewGhostTeam() *Team { return &Team{ - ID: GhostTeamID, - Name: GhostTeamName, - LowerName: GhostTeamLowerName, + ID: -1, + Name: "Ghost team", + LowerName: "ghost team", } } - -// IsGhost returns if a team is a ghost team -func (t *Team) IsGhost() bool { - return t.ID == GhostTeamID -} diff --git a/models/organization/team_test.go b/models/organization/team_test.go index 768ccdf5be..60c500e7ec 100644 --- a/models/organization/team_test.go +++ b/models/organization/team_test.go @@ -1,5 +1,4 @@ // Copyright 2017 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package organization_test @@ -16,33 +15,14 @@ import ( "github.com/stretchr/testify/require" ) -func TestTeam(t *testing.T) { +func TestTeam_IsOwnerTeam(t *testing.T) { require.NoError(t, unittest.PrepareTestDatabase()) - owners := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) - assert.Equal(t, int64(3), owners.GetOrg(db.DefaultContext).ID) - assert.Equal(t, "/org/org3/teams/Owners", owners.Link(db.DefaultContext)) - assert.False(t, owners.IsGhost()) - assert.True(t, owners.IsOwnerTeam()) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) + assert.True(t, team.IsOwnerTeam()) - team1 := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) - assert.Equal(t, int64(3), team1.GetOrg(db.DefaultContext).ID) - assert.Equal(t, "/org/org3/teams/team1", team1.Link(db.DefaultContext)) - assert.False(t, team1.IsGhost()) - assert.False(t, team1.IsOwnerTeam()) - - ghost := organization.NewGhostTeam() - assert.Equal(t, int64(-1), ghost.ID) - assert.Equal(t, int64(-1), ghost.GetOrg(db.DefaultContext).ID) - assert.Empty(t, ghost.Link(db.DefaultContext)) - assert.True(t, ghost.IsGhost()) - assert.False(t, ghost.IsOwnerTeam()) - - ghosted := organization.Team{ID: 10, Name: "Ghosted"} - assert.Equal(t, int64(-1), ghosted.GetOrg(db.DefaultContext).ID) - assert.Empty(t, ghosted.Link(db.DefaultContext)) - assert.False(t, ghosted.IsGhost()) - assert.False(t, ghosted.IsOwnerTeam()) + team = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) + assert.False(t, team.IsOwnerTeam()) } func TestTeam_IsMember(t *testing.T) { diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index f7daf38e5c..ce9963b83a 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -7,7 +7,6 @@ import ( "context" "fmt" - actions_model "forgejo.org/models/actions" "forgejo.org/models/db" "forgejo.org/models/organization" perm_model "forgejo.org/models/perm" @@ -137,33 +136,6 @@ func (p *Permission) LogString() string { return fmt.Sprintf(format, args...) } -func GetActionRepoPermission(ctx context.Context, repo *repo_model.Repository, task *actions_model.ActionTask) (Permission, error) { - // straight forward case: an actions task is attempting to access its own repo - if task.RepoID == repo.ID { - var mode perm_model.AccessMode - - // determine default access mode for repo: - if task.IsForkPullRequest { - mode = perm_model.AccessModeRead - } else { - mode = perm_model.AccessModeWrite - } - - if err := repo.LoadUnits(ctx); err != nil { - return Permission{}, err - } - - perm := Permission{ - AccessMode: mode, - Units: repo.Units, - } - - return perm, nil - } - - return GetUserRepoPermission(ctx, repo, user_model.NewActionsUser()) -} - // GetUserRepoPermission returns the user permissions to the repository func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (Permission, error) { var perm Permission diff --git a/models/perm/access/repo_permission_test.go b/models/perm/access/repo_permission_test.go deleted file mode 100644 index 55bc975421..0000000000 --- a/models/perm/access/repo_permission_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package access_test - -import ( - "testing" - - actions_model "forgejo.org/models/actions" - "forgejo.org/models/db" - perm_model "forgejo.org/models/perm" - "forgejo.org/models/perm/access" - repo_model "forgejo.org/models/repo" - "forgejo.org/models/unittest" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func assertAccess(t *testing.T, expectedMode perm_model.AccessMode, perm *access.Permission) { - assert.Equal(t, expectedMode, perm.AccessMode) - - for _, unit := range perm.Units { - assert.Equal(t, expectedMode, perm.UnitAccessMode(unit.Type)) - } -} - -func TestActionTaskCanAccessOwnRepo(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: actionTask.RepoID}) - - perm, err := access.GetActionRepoPermission(db.DefaultContext, repo, actionTask) - require.NoError(t, err) - assertAccess(t, perm_model.AccessModeWrite, &perm) -} - -func TestActionTaskCanAccessPublicRepo(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - - perm, err := access.GetActionRepoPermission(db.DefaultContext, repo, actionTask) - require.NoError(t, err) - assertAccess(t, perm_model.AccessModeRead, &perm) -} - -func TestActionTaskCanAccessPublicRepoOfLimitedOrg(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 38}) - - perm, err := access.GetActionRepoPermission(db.DefaultContext, repo, actionTask) - require.NoError(t, err) - assertAccess(t, perm_model.AccessModeRead, &perm) -} - -func TestActionTaskNoAccessPublicRepoOfPrivateOrg(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 40}) - - perm, err := access.GetActionRepoPermission(db.DefaultContext, repo, actionTask) - require.NoError(t, err) - assertAccess(t, perm_model.AccessModeNone, &perm) -} - -func TestActionTaskNoAccessPrivateRepo(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) - - perm, err := access.GetActionRepoPermission(db.DefaultContext, repo, actionTask) - require.NoError(t, err) - assertAccess(t, perm_model.AccessModeNone, &perm) -} diff --git a/models/project/project.go b/models/project/project.go index 18c647c8ac..b9813fda91 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -182,8 +182,6 @@ func init() { } // GetCardConfig retrieves the types of configurations project column cards could have -// -//llu:returnsTrKey func GetCardConfig() []CardConfig { return []CardConfig{ {CardTypeTextOnly, "repo.projects.card_type.text_only"}, diff --git a/models/project/template.go b/models/project/template.go index 278cf5b781..06d5d2af14 100644 --- a/models/project/template.go +++ b/models/project/template.go @@ -26,8 +26,6 @@ const ( ) // GetTemplateConfigs retrieves the template configs of configurations project columns could have -// -//llu:returnsTrKey func GetTemplateConfigs() []TemplateConfig { return []TemplateConfig{ {TemplateTypeNone, "repo.projects.type.none"}, diff --git a/models/quota/default.go b/models/quota/default.go index 37b23739ad..9f655d7847 100644 --- a/models/quota/default.go +++ b/models/quota/default.go @@ -7,7 +7,7 @@ import ( "forgejo.org/modules/setting" ) -func EvaluateDefault(used Used, forSubject LimitSubject) bool { +func EvaluateDefault(used Used, forSubject LimitSubject) (bool, int64) { groups := GroupList{ &Group{ Name: "builtin-default-group", diff --git a/models/quota/group.go b/models/quota/group.go index a4ec8d0e14..7ddc20b2d6 100644 --- a/models/quota/group.go +++ b/models/quota/group.go @@ -5,6 +5,7 @@ package quota import ( "context" + "math" "forgejo.org/models/db" user_model "forgejo.org/models/user" @@ -178,40 +179,78 @@ func (g *Group) RemoveRuleByName(ctx context.Context, ruleName string) error { return committer.Commit() } -// Group.Evaluate returns whether the group contains a matching rule for the subject -// and if so, whether the group allows the action given the size used -func (g *Group) Evaluate(used Used, forSubject LimitSubject) (match, allow bool) { - for _, rule := range g.Rules { - ruleMatch, ruleAllow := rule.Evaluate(used, forSubject) - if ruleMatch { - // evaluation stops as soon as we find a matching rule that denies the action - if !ruleAllow { - return true, false - } +var affectsMap = map[LimitSubject]LimitSubjects{ + LimitSubjectSizeAll: { + LimitSubjectSizeReposAll, + LimitSubjectSizeGitLFS, + LimitSubjectSizeAssetsAll, + }, + LimitSubjectSizeReposAll: { + LimitSubjectSizeReposPublic, + LimitSubjectSizeReposPrivate, + }, + LimitSubjectSizeAssetsAll: { + LimitSubjectSizeAssetsAttachmentsAll, + LimitSubjectSizeAssetsArtifacts, + LimitSubjectSizeAssetsPackagesAll, + }, + LimitSubjectSizeAssetsAttachmentsAll: { + LimitSubjectSizeAssetsAttachmentsIssues, + LimitSubjectSizeAssetsAttachmentsReleases, + }, +} - match = true - allow = true +// Evaluate returns whether the size used is acceptable for the topic if a rule +// was found, and returns the smallest limit of all applicable rules or the +// first limit found to be unacceptable for the size used. +func (g *Group) Evaluate(used Used, forSubject LimitSubject) (bool, bool, int64) { + var found bool + foundLimit := int64(math.MaxInt64) + for _, rule := range g.Rules { + ok, has := rule.Evaluate(used, forSubject) + if has { + if !ok { + return false, true, rule.Limit + } + found = true + foundLimit = min(foundLimit, rule.Limit) } } - return match, allow + if !found { + // If Evaluation for forSubject did not succeed, try evaluating against + // subjects below + + for _, subject := range affectsMap[forSubject] { + ok, has, limit := g.Evaluate(used, subject) + if has { + if !ok { + return false, true, limit + } + found = true + foundLimit = min(foundLimit, limit) + } + } + } + + return true, found, foundLimit } -// GroupList.Evaluate returns whether the grouplist allows the action given the size used -func (gl *GroupList) Evaluate(used Used, forSubject LimitSubject) (pass bool) { +// Evaluate returns if the used size is acceptable for the subject and the +// lowest limit that is acceptable for the subject. +func (gl *GroupList) Evaluate(used Used, forSubject LimitSubject) (bool, int64) { // If there are no groups, use the configured defaults: if gl == nil || len(*gl) == 0 { return EvaluateDefault(used, forSubject) } for _, group := range *gl { - groupMatch, groupAllow := group.Evaluate(used, forSubject) - if groupMatch && groupAllow { - // evaluation stops as soon as we find a matching group that allows the action - return true + ok, has, limit := group.Evaluate(used, forSubject) + if has && ok { + return true, limit } } - return false + return false, 0 } func GetGroupByName(ctx context.Context, name string) (*Group, error) { diff --git a/models/quota/quota.go b/models/quota/quota.go index 9869e9acab..9f1c3ca949 100644 --- a/models/quota/quota.go +++ b/models/quota/quota.go @@ -32,6 +32,6 @@ func EvaluateForUser(ctx context.Context, userID int64, subject LimitSubject) (b return false, err } - allow := groups.Evaluate(*used, subject) - return allow, nil + acceptable, _ := groups.Evaluate(*used, subject) + return acceptable, nil } diff --git a/models/quota/quota_group_test.go b/models/quota/quota_group_test.go index 7085682bfe..7f693b391b 100644 --- a/models/quota/quota_group_test.go +++ b/models/quota/quota_group_test.go @@ -4,16 +4,15 @@ package quota_test import ( + "math" "testing" quota_model "forgejo.org/models/quota" - "forgejo.org/modules/setting" - "forgejo.org/modules/test" "github.com/stretchr/testify/assert" ) -func TestQuotaGroupAllRulesMustAllow(t *testing.T) { +func TestQuotaGroupAllRulesMustPass(t *testing.T) { unlimitedRule := quota_model.Rule{ Limit: -1, Subjects: quota_model.LimitSubjects{ @@ -36,11 +35,12 @@ func TestQuotaGroupAllRulesMustAllow(t *testing.T) { used := quota_model.Used{} used.Size.Repos.Public = 1024 - // Within a group, *all* matching rules must allow. Thus, if we have a deny-all rule, - // and an unlimited rule, the deny rule wins. - match, allow := group.Evaluate(used, quota_model.LimitSubjectSizeAll) - assert.True(t, match) - assert.False(t, allow) + // Within a group, *all* rules must pass. Thus, if we have a deny-all rule, + // and an unlimited rule, that will always fail. + ok, has, limit := group.Evaluate(used, quota_model.LimitSubjectSizeAll) + assert.True(t, has) + assert.False(t, ok) + assert.EqualValues(t, 0, limit) } func TestQuotaGroupRuleScenario1(t *testing.T) { @@ -68,21 +68,25 @@ func TestQuotaGroupRuleScenario1(t *testing.T) { used.Size.Assets.Packages.All = 256 used.Size.Git.LFS = 16 - match, allow := group.Evaluate(used, quota_model.LimitSubjectSizeAssetsAttachmentsReleases) - assert.True(t, match, "size:assets:attachments:releases is covered") - assert.True(t, allow, "size:assets:attachments:releases is allowed") + ok, has, limit := group.Evaluate(used, quota_model.LimitSubjectSizeAssetsAttachmentsReleases) + assert.True(t, has, "size:assets:attachments:releases is covered") + assert.True(t, ok, "size:assets:attachments:releases passes") + assert.EqualValues(t, 1024, limit) - match, allow = group.Evaluate(used, quota_model.LimitSubjectSizeAssetsPackagesAll) - assert.True(t, match, "size:assets:packages:all is covered") - assert.True(t, allow, "size:assets:packages:all is allowed") + ok, has, limit = group.Evaluate(used, quota_model.LimitSubjectSizeAssetsPackagesAll) + assert.True(t, has, "size:assets:packages:all is covered") + assert.True(t, ok, "size:assets:packages:all passes") + assert.EqualValues(t, 1024, limit) - match, allow = group.Evaluate(used, quota_model.LimitSubjectSizeGitLFS) - assert.True(t, match, "size:git:lfs is covered") - assert.False(t, allow, "size:git:lfs is denied") + ok, has, limit = group.Evaluate(used, quota_model.LimitSubjectSizeGitLFS) + assert.True(t, has, "size:git:lfs is covered") + assert.False(t, ok, "size:git:lfs fails") + assert.EqualValues(t, 0, limit) - match, allow = group.Evaluate(used, quota_model.LimitSubjectSizeAll) - assert.False(t, match, "size:all is not covered") - assert.False(t, allow, "size:all is not allowed (not covered)") + ok, has, limit = group.Evaluate(used, quota_model.LimitSubjectSizeAll) + assert.True(t, has, "size:all is covered") + assert.False(t, ok, "size:all fails") + assert.EqualValues(t, 0, limit) } func TestQuotaGroupRuleCombination(t *testing.T) { @@ -110,23 +114,31 @@ func TestQuotaGroupRuleCombination(t *testing.T) { }, } - // Git LFS does not match any rule - match, allow := group.Evaluate(used, quota_model.LimitSubjectSizeGitLFS) - assert.False(t, match) - assert.False(t, allow) + // Git LFS isn't covered by any rule + _, has, limit := group.Evaluate(used, quota_model.LimitSubjectSizeGitLFS) + assert.False(t, has) + assert.EqualValues(t, math.MaxInt, limit) - // repos:all has a matching rule and is allowed - match, allow = group.Evaluate(used, quota_model.LimitSubjectSizeReposAll) - assert.True(t, match) - assert.True(t, allow) + // repos:all is covered, and is passing + ok, has, limit := group.Evaluate(used, quota_model.LimitSubjectSizeReposAll) + assert.True(t, has) + assert.True(t, ok) + assert.EqualValues(t, 4096, limit) - // packages:all has a matching rule and is denied - match, allow = group.Evaluate(used, quota_model.LimitSubjectSizeAssetsPackagesAll) - assert.True(t, match) - assert.False(t, allow) + // packages:all is covered, and is failing + ok, has, limit = group.Evaluate(used, quota_model.LimitSubjectSizeAssetsPackagesAll) + assert.True(t, has) + assert.False(t, ok) + assert.EqualValues(t, 0, limit) + + // size:all is covered, and is failing (due to packages:all being over quota) + ok, has, limit = group.Evaluate(used, quota_model.LimitSubjectSizeAll) + assert.True(t, has, "size:all should be covered") + assert.False(t, ok, "size:all should fail") + assert.EqualValues(t, 0, limit) } -func TestQuotaGroupListsRequireOnlyOneAllow(t *testing.T) { +func TestQuotaGroupListsRequireOnlyOnePassing(t *testing.T) { unlimitedRule := quota_model.Rule{ Limit: -1, Subjects: quota_model.LimitSubjects{ @@ -156,12 +168,13 @@ func TestQuotaGroupListsRequireOnlyOneAllow(t *testing.T) { used := quota_model.Used{} used.Size.Repos.Public = 1024 - // In a group list, an action is allowed if any group matches and allows it. - allow := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) - assert.True(t, allow) + // In a group list, if any group passes, the entire evaluation passes. + ok, limit := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) + assert.True(t, ok) + assert.EqualValues(t, -1, limit) } -func TestQuotaGroupListAllDeny(t *testing.T) { +func TestQuotaGroupListAllFailing(t *testing.T) { denyRule := quota_model.Rule{ Limit: 0, Subjects: quota_model.LimitSubjects{ @@ -191,38 +204,18 @@ func TestQuotaGroupListAllDeny(t *testing.T) { used := quota_model.Used{} used.Size.Repos.Public = 2048 - allow := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) - assert.False(t, allow) + ok, limit := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) + assert.False(t, ok) + assert.EqualValues(t, 0, limit) } -// An empty group list should result in the use of the built in Default -// group: size:all defaulting to unlimited -func TestQuotaDefaultGroup(t *testing.T) { +func TestQuotaGroupListEmpty(t *testing.T) { groups := quota_model.GroupList{} used := quota_model.Used{} used.Size.Repos.Public = 2048 - testSets := []struct { - name string - limit int64 - expectAllow bool - }{ - {"unlimited", -1, true}, - {"limit-allow", 1024 * 1024, true}, - {"limit-deny", 1024, false}, - } - - for _, testSet := range testSets { - t.Run(testSet.name, func(t *testing.T) { - defer test.MockVariableValue(&setting.Quota.Default.Total, testSet.limit)() - - for subject := quota_model.LimitSubjectFirst; subject <= quota_model.LimitSubjectLast; subject++ { - t.Run(subject.String(), func(t *testing.T) { - allow := groups.Evaluate(used, subject) - assert.Equal(t, testSet.expectAllow, allow) - }) - } - }) - } + ok, limit := groups.Evaluate(used, quota_model.LimitSubjectSizeAll) + assert.True(t, ok) + assert.EqualValues(t, -1, limit) } diff --git a/models/quota/quota_rule_test.go b/models/quota/quota_rule_test.go index c4605fd58e..59c05563f0 100644 --- a/models/quota/quota_rule_test.go +++ b/models/quota/quota_rule_test.go @@ -83,43 +83,28 @@ func assertEvaluation(t *testing.T, rule quota_model.Rule, used quota_model.Used t.Helper() t.Run(subject.String(), func(t *testing.T) { - match, allow := rule.Evaluate(used, subject) - assert.True(t, match) - assert.Equal(t, expected, allow) + ok, has := rule.Evaluate(used, subject) + assert.True(t, has) + assert.Equal(t, expected, ok) }) } -func TestQuotaRuleNoMatch(t *testing.T) { - testSets := []struct { - name string - limit int64 - }{ - {"unlimited", -1}, - {"limit-0", 0}, - {"limit-1k", 1024}, - {"limit-1M", 1024 * 1024}, +func TestQuotaRuleNoEvaluation(t *testing.T) { + rule := quota_model.Rule{ + Limit: 1024, + Subjects: quota_model.LimitSubjects{ + quota_model.LimitSubjectSizeAssetsAttachmentsAll, + }, } + used := quota_model.Used{} + used.Size.Repos.Public = 4096 - for _, testSet := range testSets { - t.Run(testSet.name, func(t *testing.T) { - rule := quota_model.Rule{ - Limit: testSet.limit, - Subjects: quota_model.LimitSubjects{ - quota_model.LimitSubjectSizeAssetsAttachmentsAll, - }, - } - used := quota_model.Used{} - used.Size.Repos.Public = 4096 + _, has := rule.Evaluate(used, quota_model.LimitSubjectSizeReposAll) - match, allow := rule.Evaluate(used, quota_model.LimitSubjectSizeReposAll) - - // We have a rule for "size:assets:attachments:all", and query for - // "size:repos:all". We don't cover that subject, so the rule does not match - // regardless of the limit. - assert.False(t, match) - assert.False(t, allow) - }) - } + // We have a rule for "size:assets:attachments:all", and query for + // "size:repos:all". We don't cover that subject, so the evaluation returns + // with no rules found. + assert.False(t, has) } func TestQuotaRuleDirectEvaluation(t *testing.T) { @@ -144,12 +129,13 @@ func TestQuotaRuleDirectEvaluation(t *testing.T) { } t.Run("limit:0", func(t *testing.T) { - // With limit:0, any usage will fail evaluation, including 0 + // With limit:0, nothing used is fine. t.Run("used:0", func(t *testing.T) { for subject := quota_model.LimitSubjectFirst; subject <= quota_model.LimitSubjectLast; subject++ { - runTest(t, subject, 0, 0, false) + runTest(t, subject, 0, 0, true) } }) + // With limit:0, any usage will fail evaluation t.Run("used:512", func(t *testing.T) { for subject := quota_model.LimitSubjectFirst; subject <= quota_model.LimitSubjectLast; subject++ { runTest(t, subject, 0, 512, false) @@ -184,6 +170,14 @@ func TestQuotaRuleDirectEvaluation(t *testing.T) { } func TestQuotaRuleCombined(t *testing.T) { + rule := quota_model.Rule{ + Limit: 1024, + Subjects: quota_model.LimitSubjects{ + quota_model.LimitSubjectSizeGitLFS, + quota_model.LimitSubjectSizeAssetsAttachmentsReleases, + quota_model.LimitSubjectSizeAssetsPackagesAll, + }, + } used := quota_model.Used{ Size: quota_model.UsedSize{ Repos: quota_model.UsedSizeRepos{ @@ -204,112 +198,107 @@ func TestQuotaRuleCombined(t *testing.T) { }, } - expectMatch := map[quota_model.LimitSubject]bool{ - quota_model.LimitSubjectSizeGitLFS: true, - quota_model.LimitSubjectSizeAssetsAttachmentsReleases: true, - quota_model.LimitSubjectSizeAssetsPackagesAll: true, + expectationMap := map[quota_model.LimitSubject]bool{ + quota_model.LimitSubjectSizeGitLFS: false, + quota_model.LimitSubjectSizeAssetsAttachmentsReleases: false, + quota_model.LimitSubjectSizeAssetsPackagesAll: false, } - testSets := []struct { - name string - limit int64 - expectAllow bool - }{ - {"unlimited", -1, true}, - {"limit-allow", 1024 * 1024, true}, - {"limit-deny", 1024, false}, - } + for subject := quota_model.LimitSubjectFirst; subject <= quota_model.LimitSubjectLast; subject++ { + t.Run(subject.String(), func(t *testing.T) { + evalOk, evalHas := rule.Evaluate(used, subject) + expected, expectedHas := expectationMap[subject] - for _, testSet := range testSets { - t.Run(testSet.name, func(t *testing.T) { - rule := quota_model.Rule{ - Limit: testSet.limit, - Subjects: quota_model.LimitSubjects{ - quota_model.LimitSubjectSizeGitLFS, - quota_model.LimitSubjectSizeAssetsAttachmentsReleases, - quota_model.LimitSubjectSizeAssetsPackagesAll, - }, - } - - for subject := quota_model.LimitSubjectFirst; subject <= quota_model.LimitSubjectLast; subject++ { - t.Run(subject.String(), func(t *testing.T) { - match, allow := rule.Evaluate(used, subject) - - assert.Equal(t, expectMatch[subject], match) - if expectMatch[subject] { - assert.Equal(t, testSet.expectAllow, allow) - } else { - assert.False(t, allow) - } - }) + assert.Equal(t, expectedHas, evalHas) + if expectedHas { + assert.Equal(t, expected, evalOk) } }) } } func TestQuotaRuleSizeAll(t *testing.T) { - type Test struct { - name string - limit int64 - expectAllow bool - } + runTests := func(t *testing.T, rule quota_model.Rule, expected bool) { + t.Helper() - usedSets := []struct { - name string - used quota_model.Used - testSets []Test - }{ - { - "empty", - quota_model.Used{}, - []Test{ - {"unlimited", -1, true}, - {"limit-1M", 1024 * 1024, true}, - {"limit-5k", 5 * 1024, true}, - {"limit-0", 0, false}, - }, - }, - { - "partial", - makePartiallyUsed(), - []Test{ - {"unlimited", -1, true}, - {"limit-1M", 1024 * 1024, true}, - {"limit-5k", 5 * 1024, true}, - {"limit-0", 0, false}, - }, - }, - { - "full", - makeFullyUsed(), - []Test{ - {"unlimited", -1, true}, - {"limit-1M", 1024 * 1024, true}, - {"limit-5k", 5 * 1024, false}, - {"limit-0", 0, false}, - }, - }, - } + subject := quota_model.LimitSubjectSizeAll - for _, usedSet := range usedSets { - t.Run(usedSet.name, func(t *testing.T) { - testSets := usedSet.testSets - used := usedSet.used + t.Run("used:0", func(t *testing.T) { + used := quota_model.Used{} - for _, testSet := range testSets { - t.Run(testSet.name, func(t *testing.T) { - rule := quota_model.Rule{ - Limit: testSet.limit, - Subjects: quota_model.LimitSubjects{ - quota_model.LimitSubjectSizeAll, - }, - } + assertEvaluation(t, rule, used, subject, true) + }) - match, allow := rule.Evaluate(used, quota_model.LimitSubjectSizeAll) - assert.True(t, match) - assert.Equal(t, testSet.expectAllow, allow) - }) - } + t.Run("used:some-each", func(t *testing.T) { + used := makeFullyUsed() + + assertEvaluation(t, rule, used, subject, expected) + }) + + t.Run("used:some", func(t *testing.T) { + used := makePartiallyUsed() + + assertEvaluation(t, rule, used, subject, expected) }) } + + // With all limits set to 0, evaluation always fails if usage > 0 + t.Run("rule:0", func(t *testing.T) { + rule := quota_model.Rule{ + Limit: 0, + Subjects: quota_model.LimitSubjects{ + quota_model.LimitSubjectSizeAll, + }, + } + + runTests(t, rule, false) + }) + + // With no limits, evaluation always succeeds + t.Run("rule:unlimited", func(t *testing.T) { + rule := quota_model.Rule{ + Limit: -1, + Subjects: quota_model.LimitSubjects{ + quota_model.LimitSubjectSizeAll, + }, + } + + runTests(t, rule, true) + }) + + // With a specific, very generous limit, evaluation succeeds if the limit isn't exhausted + t.Run("rule:generous", func(t *testing.T) { + rule := quota_model.Rule{ + Limit: 102400, + Subjects: quota_model.LimitSubjects{ + quota_model.LimitSubjectSizeAll, + }, + } + + runTests(t, rule, true) + + t.Run("limit exhaustion", func(t *testing.T) { + used := quota_model.Used{ + Size: quota_model.UsedSize{ + Repos: quota_model.UsedSizeRepos{ + Public: 204800, + }, + }, + } + + assertEvaluation(t, rule, used, quota_model.LimitSubjectSizeAll, false) + }) + }) + + // With a specific, small limit, evaluation fails + t.Run("rule:limited", func(t *testing.T) { + rule := quota_model.Rule{ + Limit: 512, + Subjects: quota_model.LimitSubjects{ + quota_model.LimitSubjectSizeAll, + }, + } + + runTests(t, rule, false) + }) } diff --git a/models/quota/rule.go b/models/quota/rule.go index 98959e0a91..89cb57cace 100644 --- a/models/quota/rule.go +++ b/models/quota/rule.go @@ -16,21 +16,6 @@ type Rule struct { Subjects LimitSubjects `json:"subjects,omitempty"` } -var subjectToParent = map[LimitSubject]LimitSubject{ - LimitSubjectSizeGitAll: LimitSubjectSizeAll, - LimitSubjectSizeGitLFS: LimitSubjectSizeGitAll, - LimitSubjectSizeReposAll: LimitSubjectSizeGitAll, - LimitSubjectSizeReposPublic: LimitSubjectSizeReposAll, - LimitSubjectSizeReposPrivate: LimitSubjectSizeReposAll, - LimitSubjectSizeAssetsAll: LimitSubjectSizeAll, - LimitSubjectSizeAssetsAttachmentsAll: LimitSubjectSizeAssetsAll, - LimitSubjectSizeAssetsAttachmentsIssues: LimitSubjectSizeAssetsAttachmentsAll, - LimitSubjectSizeAssetsAttachmentsReleases: LimitSubjectSizeAssetsAttachmentsAll, - LimitSubjectSizeAssetsArtifacts: LimitSubjectSizeAssetsAll, - LimitSubjectSizeAssetsPackagesAll: LimitSubjectSizeAssetsAll, - LimitSubjectSizeWiki: LimitSubjectSizeAssetsAll, -} - func (r *Rule) TableName() string { return "quota_rule" } @@ -51,25 +36,18 @@ func (r Rule) Sum(used Used) int64 { return sum } -func (r Rule) Evaluate(used Used, forSubject LimitSubject) (match, allow bool) { +func (r Rule) Evaluate(used Used, forSubject LimitSubject) (bool, bool) { + // If there's no limit, short circuit out + if r.Limit == -1 { + return true, true + } + + // If the rule does not cover forSubject, bail out early if !slices.Contains(r.Subjects, forSubject) { - // this rule does not match the subject being tested - parent := subjectToParent[forSubject] - if parent != LimitSubjectNone { - return r.Evaluate(used, parent) - } return false, false } - match = true - - if r.Limit == -1 { - // Unlimited, any value is allowed - allow = true - } else { - allow = r.Sum(used) < r.Limit - } - return match, allow + return r.Sum(used) <= r.Limit, true } func (r *Rule) Edit(ctx context.Context, limit *int64, subjects *LimitSubjects) (*Rule, error) { diff --git a/models/quota/used.go b/models/quota/used.go index 0d8f62ab78..22815165f6 100644 --- a/models/quota/used.go +++ b/models/quota/used.go @@ -25,7 +25,7 @@ type UsedSize struct { } func (u UsedSize) All() int64 { - return u.Git.All(u.Repos) + u.Assets.All() + return u.Repos.All() + u.Git.All(u.Repos) + u.Assets.All() } type UsedSizeRepos struct { diff --git a/models/quota/used_test.go b/models/quota/used_test.go index 0fed83342b..82cc5b9bcc 100644 --- a/models/quota/used_test.go +++ b/models/quota/used_test.go @@ -1,54 +1,23 @@ // Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: GPL-3.0-or-later -package quota_test +package quota import ( "testing" - quota_model "forgejo.org/models/quota" "forgejo.org/models/unittest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestQuotaUsedGetUsedForUser(t *testing.T) { +func TestGetUsedForUser(t *testing.T) { defer unittest.OverrideFixtures("models/fixtures/TestGetUsedForUser/")() require.NoError(t, unittest.PrepareTestDatabase()) - used, err := quota_model.GetUsedForUser(t.Context(), 5) + used, err := GetUsedForUser(t.Context(), 5) require.NoError(t, err) assert.EqualValues(t, 4096, used.Size.Assets.Artifacts) } - -func TestQuotaUsedTotals(t *testing.T) { - used := quota_model.Used{ - Size: quota_model.UsedSize{ - Repos: quota_model.UsedSizeRepos{ - Public: 2, - Private: 3, - }, - Git: quota_model.UsedSizeGit{ - LFS: 7, - }, - Assets: quota_model.UsedSizeAssets{ - Attachments: quota_model.UsedSizeAssetsAttachments{ - Issues: 11, - Releases: 13, - }, - Artifacts: 17, - Packages: quota_model.UsedSizeAssetsPackages{ - All: 19, - }, - }, - }, - } - - assert.EqualValues(t, 5, used.Size.Repos.All()) // repos public + repos private - assert.EqualValues(t, 12, used.Size.Git.All(used.Size.Repos)) // repos all + git lfs - assert.EqualValues(t, 24, used.Size.Assets.Attachments.All()) // issues + releases - assert.EqualValues(t, 60, used.Size.Assets.All()) // attachments all + artifacts + packages - assert.EqualValues(t, 72, used.Size.All()) // git all + assets all -} diff --git a/models/repo/git.go b/models/repo/git.go index 11f6452be5..692176c8f6 100644 --- a/models/repo/git.go +++ b/models/repo/git.go @@ -29,8 +29,6 @@ const ( MergeStyleRebaseUpdate MergeStyle = "rebase-update-only" ) -var MergeStyles = []MergeStyle{MergeStyleMerge, MergeStyleRebase, MergeStyleRebaseMerge, MergeStyleSquash, MergeStyleFastForwardOnly, MergeStyleManuallyMerged, MergeStyleRebaseUpdate} - type UpdateStyle string const ( diff --git a/models/repo/moderation.go b/models/repo/moderation.go index 0d2672227b..d7b87dffa0 100644 --- a/models/repo/moderation.go +++ b/models/repo/moderation.go @@ -5,8 +5,6 @@ package repo import ( "context" - "strconv" - "strings" "forgejo.org/models/moderation" "forgejo.org/modules/json" @@ -27,22 +25,6 @@ type RepositoryData struct { UpdatedUnix timeutil.TimeStamp } -// Implements GetFieldsMap() from ShadowCopyData interface, returning a list of pairs -// to be used when rendering the shadow copy for admins reviewing the corresponding abuse report(s). -func (rd RepositoryData) GetFieldsMap() []moderation.ShadowCopyField { - return []moderation.ShadowCopyField{ - {Key: "OwnerID", Value: strconv.FormatInt(rd.OwnerID, 10)}, - {Key: "OwnerName", Value: rd.OwnerName}, - {Key: "Name", Value: rd.Name}, - {Key: "Description", Value: rd.Description}, - {Key: "Website", Value: rd.Website}, - {Key: "Topics", Value: strings.Join(rd.Topics, ", ")}, - {Key: "Avatar", Value: rd.Avatar}, - {Key: "CreatedUnix", Value: rd.CreatedUnix.AsLocalTime().String()}, - {Key: "UpdatedUnix", Value: rd.UpdatedUnix.AsLocalTime().String()}, - } -} - // newRepositoryData creates a trimmed down repository to be used just to create a JSON structure // (keeping only the fields relevant for moderation purposes) func newRepositoryData(repo *Repository) RepositoryData { diff --git a/models/repo/moderation_test.go b/models/repo/moderation_test.go deleted file mode 100644 index 9852db1b51..0000000000 --- a/models/repo/moderation_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package repo_test - -import ( - "testing" - - "forgejo.org/models/moderation" - "forgejo.org/models/repo" - "forgejo.org/modules/timeutil" - - "github.com/stretchr/testify/assert" -) - -const ( - tsCreated timeutil.TimeStamp = timeutil.TimeStamp(1753093500) // 2025-07-21 10:25:00 UTC - tsUpdated timeutil.TimeStamp = timeutil.TimeStamp(1753093525) // 2025-07-21 10:25:25 UTC -) - -func testShadowCopyField(t *testing.T, scField moderation.ShadowCopyField, key, value string) { - assert.Equal(t, key, scField.Key) - assert.Equal(t, value, scField.Value) -} - -func TestRepositoryDataGetFieldsMap(t *testing.T) { - rd := repo.RepositoryData{ - OwnerID: 1002, - OwnerName: "alexsmith", - Name: "website", - Description: "My static website.", - Website: "http://promote-your-business.biz", - Topics: []string{"bulk-email", "email-services"}, - Avatar: "avatar-hash-repo-2002", - CreatedUnix: tsCreated, - UpdatedUnix: tsUpdated, - } - scFields := rd.GetFieldsMap() - - if assert.Len(t, scFields, 9) { - testShadowCopyField(t, scFields[0], "OwnerID", "1002") - testShadowCopyField(t, scFields[1], "OwnerName", "alexsmith") - testShadowCopyField(t, scFields[2], "Name", "website") - testShadowCopyField(t, scFields[3], "Description", "My static website.") - testShadowCopyField(t, scFields[4], "Website", "http://promote-your-business.biz") - testShadowCopyField(t, scFields[5], "Topics", "bulk-email, email-services") - testShadowCopyField(t, scFields[6], "Avatar", "avatar-hash-repo-2002") - testShadowCopyField(t, scFields[7], "CreatedUnix", tsCreated.AsLocalTime().String()) - testShadowCopyField(t, scFields[8], "UpdatedUnix", tsUpdated.AsLocalTime().String()) - } -} diff --git a/models/repo/pushmirror.go b/models/repo/pushmirror.go index e57897fb7e..d6d0d1135a 100644 --- a/models/repo/pushmirror.go +++ b/models/repo/pushmirror.go @@ -32,7 +32,6 @@ type PushMirror struct { Repo *Repository `xorm:"-"` RemoteName string RemoteAddress string `xorm:"VARCHAR(2048)"` - BranchFilter string `xorm:"VARCHAR(2048)"` // A keypair formatted in OpenSSH format. PublicKey string `xorm:"VARCHAR(100)"` @@ -123,11 +122,6 @@ func UpdatePushMirrorInterval(ctx context.Context, m *PushMirror) error { return err } -func UpdatePushMirrorBranchFilter(ctx context.Context, m *PushMirror) error { - _, err := db.GetEngine(ctx).ID(m.ID).Cols("branch_filter").Update(m) - return err -} - var DeletePushMirrors = deletePushMirrors func deletePushMirrors(ctx context.Context, opts PushMirrorOptions) error { diff --git a/models/repo/pushmirror_test.go b/models/repo/pushmirror_test.go index a7e063ff71..fbef835372 100644 --- a/models/repo/pushmirror_test.go +++ b/models/repo/pushmirror_test.go @@ -75,139 +75,3 @@ func TestPushMirrorPrivatekey(t *testing.T) { assert.Empty(t, actualPrivateKey) }) } - -func TestPushMirrorBranchFilter(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - t.Run("Create push mirror with branch filter", func(t *testing.T) { - m := &repo_model.PushMirror{ - RepoID: 1, - RemoteName: "test-branch-filter", - BranchFilter: "main,develop", - } - unittest.AssertSuccessfulInsert(t, m) - assert.NotZero(t, m.ID) - assert.Equal(t, "main,develop", m.BranchFilter) - }) - - t.Run("Create push mirror with empty branch filter", func(t *testing.T) { - m := &repo_model.PushMirror{ - RepoID: 1, - RemoteName: "test-empty-filter", - BranchFilter: "", - } - unittest.AssertSuccessfulInsert(t, m) - assert.NotZero(t, m.ID) - assert.Empty(t, m.BranchFilter) - }) - - t.Run("Create push mirror without branch filter", func(t *testing.T) { - m := &repo_model.PushMirror{ - RepoID: 1, - RemoteName: "test-no-filter", - // BranchFilter: "", - } - unittest.AssertSuccessfulInsert(t, m) - assert.NotZero(t, m.ID) - assert.Empty(t, m.BranchFilter) - }) - - t.Run("Update branch filter", func(t *testing.T) { - m := &repo_model.PushMirror{ - RepoID: 1, - RemoteName: "test-update", - BranchFilter: "main", - } - unittest.AssertSuccessfulInsert(t, m) - - m.BranchFilter = "main,develop" - require.NoError(t, repo_model.UpdatePushMirrorBranchFilter(db.DefaultContext, m)) - - updated := unittest.AssertExistsAndLoadBean(t, &repo_model.PushMirror{ID: m.ID}) - assert.Equal(t, "main,develop", updated.BranchFilter) - }) - - t.Run("Retrieve push mirror with branch filter", func(t *testing.T) { - original := &repo_model.PushMirror{ - RepoID: 1, - RemoteName: "test-retrieve", - BranchFilter: "main,develop", - } - unittest.AssertSuccessfulInsert(t, original) - - retrieved := unittest.AssertExistsAndLoadBean(t, &repo_model.PushMirror{ID: original.ID}) - assert.Equal(t, original.BranchFilter, retrieved.BranchFilter) - assert.Equal(t, "main,develop", retrieved.BranchFilter) - }) - - t.Run("GetPushMirrorsByRepoID includes branch filter", func(t *testing.T) { - mirrors := []*repo_model.PushMirror{ - { - RepoID: 2, - RemoteName: "mirror-1", - BranchFilter: "main", - }, - { - RepoID: 2, - RemoteName: "mirror-2", - BranchFilter: "develop,feature-*", - }, - { - RepoID: 2, - RemoteName: "mirror-3", - BranchFilter: "", - }, - } - - for _, mirror := range mirrors { - unittest.AssertSuccessfulInsert(t, mirror) - } - - retrieved, count, err := repo_model.GetPushMirrorsByRepoID(db.DefaultContext, 2, db.ListOptions{}) - require.NoError(t, err) - assert.Equal(t, int64(3), count) - assert.Len(t, retrieved, 3) - - filterMap := make(map[string]string) - for _, mirror := range retrieved { - filterMap[mirror.RemoteName] = mirror.BranchFilter - } - - assert.Equal(t, "main", filterMap["mirror-1"]) - assert.Equal(t, "develop,feature-*", filterMap["mirror-2"]) - assert.Empty(t, filterMap["mirror-3"]) - }) - - t.Run("GetPushMirrorsSyncedOnCommit includes branch filter", func(t *testing.T) { - mirrors := []*repo_model.PushMirror{ - { - RepoID: 3, - RemoteName: "sync-mirror-1", - BranchFilter: "main,develop", - SyncOnCommit: true, - }, - { - RepoID: 3, - RemoteName: "sync-mirror-2", - BranchFilter: "feature-*", - SyncOnCommit: true, - }, - } - - for _, mirror := range mirrors { - unittest.AssertSuccessfulInsert(t, mirror) - } - - retrieved, err := repo_model.GetPushMirrorsSyncedOnCommit(db.DefaultContext, 3) - require.NoError(t, err) - assert.Len(t, retrieved, 2) - - filterMap := make(map[string]string) - for _, mirror := range retrieved { - filterMap[mirror.RemoteName] = mirror.BranchFilter - } - - assert.Equal(t, "main,develop", filterMap["sync-mirror-1"]) - assert.Equal(t, "feature-*", filterMap["sync-mirror-2"]) - }) -} diff --git a/models/repo/redirect.go b/models/repo/redirect.go index e5239a3684..9c44a255d0 100644 --- a/models/repo/redirect.go +++ b/models/repo/redirect.go @@ -14,9 +14,8 @@ import ( // ErrRedirectNotExist represents a "RedirectNotExist" kind of error. type ErrRedirectNotExist struct { - OwnerID int64 - RepoName string - MissingPermission bool + OwnerID int64 + RepoName string } // IsErrRedirectNotExist check if an error is an ErrRepoRedirectNotExist. @@ -50,8 +49,8 @@ func init() { db.RegisterModel(new(Redirect)) } -// GetRedirect returns the redirect for a given pair of ownerID and repository name. -func GetRedirect(ctx context.Context, ownerID int64, repoName string) (int64, error) { +// LookupRedirect look up if a repository has a redirect name +func LookupRedirect(ctx context.Context, ownerID int64, repoName string) (int64, error) { repoName = strings.ToLower(repoName) redirect := &Redirect{OwnerID: ownerID, LowerName: repoName} if has, err := db.GetEngine(ctx).Get(redirect); err != nil { diff --git a/models/repo/redirect_test.go b/models/repo/redirect_test.go index 2f2210588f..d84cbbed54 100644 --- a/models/repo/redirect_test.go +++ b/models/repo/redirect_test.go @@ -10,9 +10,21 @@ import ( repo_model "forgejo.org/models/repo" "forgejo.org/models/unittest" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +func TestLookupRedirect(t *testing.T) { + require.NoError(t, unittest.PrepareTestDatabase()) + + repoID, err := repo_model.LookupRedirect(db.DefaultContext, 2, "oldrepo1") + require.NoError(t, err) + assert.EqualValues(t, 1, repoID) + + _, err = repo_model.LookupRedirect(db.DefaultContext, unittest.NonexistentID, "doesnotexist") + assert.True(t, repo_model.IsErrRedirectNotExist(err)) +} + func TestNewRedirect(t *testing.T) { // redirect to a completely new name require.NoError(t, unittest.PrepareTestDatabase()) diff --git a/models/repo/release.go b/models/repo/release.go index b39a1de971..10e9bb259f 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -77,7 +77,7 @@ type Release struct { Target string TargetBehind string `xorm:"-"` // to handle non-existing or empty target Title string - Sha1 string `xorm:"INDEX VARCHAR(64)"` + Sha1 string `xorm:"VARCHAR(64)"` HideArchiveLinks bool `xorm:"NOT NULL DEFAULT false"` NumCommits int64 NumCommitsBehind int64 `xorm:"-"` @@ -618,17 +618,3 @@ func InsertReleases(ctx context.Context, rels ...*Release) error { return committer.Commit() } - -func FindTagsByCommitIDs(ctx context.Context, repoID int64, commitIDs ...string) (map[string][]*Release, error) { - releases := make([]*Release, 0, len(commitIDs)) - if err := db.GetEngine(ctx).Where("repo_id=?", repoID). - In("sha1", commitIDs). - Find(&releases); err != nil { - return nil, err - } - res := make(map[string][]*Release, len(releases)) - for _, r := range releases { - res[r.Sha1] = append(res[r.Sha1], r) - } - return res, nil -} diff --git a/models/repo/release_test.go b/models/repo/release_test.go index 69f9333589..94dbd6d9d5 100644 --- a/models/repo/release_test.go +++ b/models/repo/release_test.go @@ -49,16 +49,3 @@ func TestReleaseDisplayName(t *testing.T) { release.Title = "Title" assert.Equal(t, "Title", release.DisplayName()) } - -func Test_FindTagsByCommitIDs(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - sha1Rels, err := FindTagsByCommitIDs(db.DefaultContext, 1, "65f1bf27bc3bf70f64657658635e66094edbcb4d") - require.NoError(t, err) - assert.Len(t, sha1Rels, 1) - rels := sha1Rels["65f1bf27bc3bf70f64657658635e66094edbcb4d"] - assert.Len(t, rels, 3) - assert.Equal(t, "v1.1", rels[0].TagName) - assert.Equal(t, "delete-tag", rels[1].TagName) - assert.Equal(t, "v1.0", rels[2].TagName) -} diff --git a/models/repo/repo_repository.go b/models/repo/repo_repository.go index 9d586b8345..0ba50e6614 100644 --- a/models/repo/repo_repository.go +++ b/models/repo/repo_repository.go @@ -38,18 +38,18 @@ func StoreFollowingRepos(ctx context.Context, localRepoID int64, followingRepoLi } // Begin transaction - dbCtx, committer, err := db.TxContext((ctx)) + ctx, committer, err := db.TxContext((ctx)) if err != nil { return err } defer committer.Close() - _, err = db.GetEngine(dbCtx).Where("repo_id=?", localRepoID).Delete(FollowingRepo{}) + _, err = db.GetEngine(ctx).Where("repo_id=?", localRepoID).Delete(FollowingRepo{}) if err != nil { return err } for _, followingRepo := range followingRepoList { - _, err = db.GetEngine(dbCtx).Insert(followingRepo) + _, err = db.GetEngine(ctx).Insert(followingRepo) if err != nil { return err } diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go index aa6f2fa0ae..e50f79e945 100644 --- a/models/repo/repo_unit.go +++ b/models/repo/repo_unit.go @@ -336,8 +336,5 @@ func getUnitsByRepoID(ctx context.Context, repoID int64) (units []*RepoUnit, err // UpdateRepoUnit updates the provided repo unit func UpdateRepoUnit(ctx context.Context, unit *RepoUnit) error { _, err := db.GetEngine(ctx).ID(unit.ID).Update(unit) - if err != nil { - return fmt.Errorf("UpdateRepoUnit: %v", err) - } - return nil + return err } diff --git a/models/repo/topic.go b/models/repo/topic.go index 9086f17627..4a3bdc7d8c 100644 --- a/models/repo/topic.go +++ b/models/repo/topic.go @@ -164,7 +164,7 @@ func FindTopics(ctx context.Context, opts *FindTopicOptions) ([]*Topic, int64, e orderBy := "topic.repo_count DESC" if opts.RepoID > 0 { sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id") - orderBy = "topic.name" // When rendering topics for a repo, it's better to sort them by name to get consistent results + orderBy = "topic.name" // when render topics for a repo, it's better to sort them by name, to get consistent result } if opts.PageSize > 0 { sess = db.SetSessionPagination(sess, opts) diff --git a/models/secret/main_test.go b/models/secret/main_test.go deleted file mode 100644 index 85bfec0c4f..0000000000 --- a/models/secret/main_test.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package secret_test - -import ( - "testing" - - "forgejo.org/models/unittest" - - _ "forgejo.org/models" - _ "forgejo.org/models/activities" -) - -func TestMain(m *testing.M) { - unittest.MainTest(m) -} diff --git a/models/secret/secret.go b/models/secret/secret.go index 6f6867db52..7be7f454a1 100644 --- a/models/secret/secret.go +++ b/models/secret/secret.go @@ -11,8 +11,9 @@ import ( actions_model "forgejo.org/models/actions" "forgejo.org/models/db" actions_module "forgejo.org/modules/actions" - "forgejo.org/modules/keying" "forgejo.org/modules/log" + secret_module "forgejo.org/modules/secret" + "forgejo.org/modules/setting" "forgejo.org/modules/timeutil" "forgejo.org/modules/util" @@ -38,7 +39,7 @@ type Secret struct { OwnerID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL"` RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"` Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"` - Data []byte `xorm:"BLOB"` // encrypted data + Data string `xorm:"LONGTEXT"` // encrypted data CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` } @@ -66,21 +67,17 @@ func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, dat return nil, fmt.Errorf("%w: ownerID and repoID cannot be both zero, global secrets are not supported", util.ErrInvalidArgument) } + encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data) + if err != nil { + return nil, err + } secret := &Secret{ OwnerID: ownerID, RepoID: repoID, Name: strings.ToUpper(name), + Data: encrypted, } - - return secret, db.WithTx(ctx, func(ctx context.Context) error { - if err := db.Insert(ctx, secret); err != nil { - return err - } - - secret.SetSecret(data) - _, err := db.GetEngine(ctx).ID(secret.ID).Cols("data").Update(secret) - return err - }) + return secret, db.Insert(ctx, secret) } func init() { @@ -116,9 +113,21 @@ func (opts FindSecretsOptions) ToConds() builder.Cond { return cond } -func (s *Secret) SetSecret(data string) { - key := keying.DeriveKey(keying.ContextActionSecret) - s.Data = key.Encrypt([]byte(data), keying.ColumnAndID("data", s.ID)) +// UpdateSecret changes org or user reop secret. +func UpdateSecret(ctx context.Context, secretID int64, data string) error { + encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data) + if err != nil { + return err + } + + s := &Secret{ + Data: encrypted, + } + affected, err := db.GetEngine(ctx).ID(secretID).Cols("data").Update(s) + if affected != 1 { + return ErrSecretNotFound{} + } + return err } func GetSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) (map[string]string, error) { @@ -146,14 +155,13 @@ func GetSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) (map[ return nil, err } - key := keying.DeriveKey(keying.ContextActionSecret) for _, secret := range append(ownerSecrets, repoSecrets...) { - v, err := key.Decrypt(secret.Data, keying.ColumnAndID("data", secret.ID)) + v, err := secret_module.DecryptSecret(setting.SecretKey, secret.Data) if err != nil { - log.Error("unable to decrypt secret[id=%d,name=%q]: %v", secret.ID, secret.Name, err) + log.Error("decrypt secret %v %q: %v", secret.ID, secret.Name, err) return nil, err } - secrets[secret.Name] = string(v) + secrets[secret.Name] = v } return secrets, nil diff --git a/models/secret/secret_test.go b/models/secret/secret_test.go deleted file mode 100644 index 15142d207b..0000000000 --- a/models/secret/secret_test.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package secret - -import ( - "testing" - - "forgejo.org/models/actions" - "forgejo.org/models/repo" - "forgejo.org/models/unittest" - "forgejo.org/modules/keying" - "forgejo.org/modules/util" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestInsertEncryptedSecret(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - t.Run("Global secret", func(t *testing.T) { - secret, err := InsertEncryptedSecret(t.Context(), 0, 0, "GLOBAL_SECRET", "some common secret") - require.ErrorIs(t, err, util.ErrInvalidArgument) - assert.Nil(t, secret) - }) - - key := keying.DeriveKey(keying.ContextActionSecret) - - t.Run("Insert repository secret", func(t *testing.T) { - secret, err := InsertEncryptedSecret(t.Context(), 0, 1, "REPO_SECRET", "some repository secret") - require.NoError(t, err) - assert.NotNil(t, secret) - assert.Equal(t, "REPO_SECRET", secret.Name) - assert.EqualValues(t, 1, secret.RepoID) - assert.NotEmpty(t, secret.Data) - - // Assert the secret is stored in the database. - unittest.AssertExistsAndLoadBean(t, &Secret{RepoID: 1, Name: "REPO_SECRET", Data: secret.Data}) - - t.Run("Keying", func(t *testing.T) { - // Cannot decrypt with different ID. - plainText, err := key.Decrypt(secret.Data, keying.ColumnAndID("data", secret.ID+1)) - require.Error(t, err) - assert.Nil(t, plainText) - - // Cannot decrypt with different column. - plainText, err = key.Decrypt(secret.Data, keying.ColumnAndID("metadata", secret.ID)) - require.Error(t, err) - assert.Nil(t, plainText) - - // Can decrypt with correct column and ID. - plainText, err = key.Decrypt(secret.Data, keying.ColumnAndID("data", secret.ID)) - require.NoError(t, err) - assert.EqualValues(t, "some repository secret", plainText) - }) - }) - - t.Run("Insert owner secret", func(t *testing.T) { - secret, err := InsertEncryptedSecret(t.Context(), 2, 0, "OWNER_SECRET", "some owner secret") - require.NoError(t, err) - assert.NotNil(t, secret) - assert.Equal(t, "OWNER_SECRET", secret.Name) - assert.EqualValues(t, 2, secret.OwnerID) - assert.NotEmpty(t, secret.Data) - - // Assert the secret is stored in the database. - unittest.AssertExistsAndLoadBean(t, &Secret{OwnerID: 2, Name: "OWNER_SECRET", Data: secret.Data}) - - t.Run("Keying", func(t *testing.T) { - // Cannot decrypt with different ID. - plainText, err := key.Decrypt(secret.Data, keying.ColumnAndID("data", secret.ID+1)) - require.Error(t, err) - assert.Nil(t, plainText) - - // Cannot decrypt with different column. - plainText, err = key.Decrypt(secret.Data, keying.ColumnAndID("metadata", secret.ID)) - require.Error(t, err) - assert.Nil(t, plainText) - - // Can decrypt with correct column and ID. - plainText, err = key.Decrypt(secret.Data, keying.ColumnAndID("data", secret.ID)) - require.NoError(t, err) - assert.EqualValues(t, "some owner secret", plainText) - }) - }) - - t.Run("Get secrets", func(t *testing.T) { - secrets, err := GetSecretsOfTask(t.Context(), &actions.ActionTask{ - Job: &actions.ActionRunJob{ - Run: &actions.ActionRun{ - RepoID: 1, - Repo: &repo.Repository{ - OwnerID: 2, - }, - }, - }, - }) - require.NoError(t, err) - assert.Equal(t, "some owner secret", secrets["OWNER_SECRET"]) - assert.Equal(t, "some repository secret", secrets["REPO_SECRET"]) - }) -} diff --git a/models/unit/unit.go b/models/unit/unit.go index 6b4f2765ee..a14f3ff364 100644 --- a/models/unit/unit.go +++ b/models/unit/unit.go @@ -271,6 +271,7 @@ type Unit struct { Name string NameKey string URI string + DescKey string Idx int MaxAccessMode perm.AccessMode // The max access mode of the unit. i.e. Read means this unit can only be read. } @@ -298,6 +299,7 @@ var ( "code", "repo.code", "/", + "repo.code.desc", 0, perm.AccessModeOwner, } @@ -307,6 +309,7 @@ var ( "issues", "repo.issues", "/issues", + "repo.issues.desc", 1, perm.AccessModeOwner, } @@ -316,6 +319,7 @@ var ( "ext_issues", "repo.ext_issues", "/issues", + "repo.ext_issues.desc", 1, perm.AccessModeRead, } @@ -325,6 +329,7 @@ var ( "pulls", "repo.pulls", "/pulls", + "repo.pulls.desc", 2, perm.AccessModeOwner, } @@ -334,6 +339,7 @@ var ( "releases", "repo.releases", "/releases", + "repo.releases.desc", 3, perm.AccessModeOwner, } @@ -343,6 +349,7 @@ var ( "wiki", "repo.wiki", "/wiki", + "repo.wiki.desc", 4, perm.AccessModeOwner, } @@ -352,6 +359,7 @@ var ( "ext_wiki", "repo.ext_wiki", "/wiki", + "repo.ext_wiki.desc", 4, perm.AccessModeRead, } @@ -361,6 +369,7 @@ var ( "projects", "repo.projects", "/projects", + "repo.projects.desc", 5, perm.AccessModeOwner, } @@ -370,6 +379,7 @@ var ( "packages", "repo.packages", "/packages", + "packages.desc", 6, perm.AccessModeRead, } @@ -379,6 +389,7 @@ var ( "actions", "repo.actions", "/actions", + "actions.unit.desc", 7, perm.AccessModeOwner, } diff --git a/models/unittest/fixture_loader.go b/models/unittest/fixture_loader.go index 0b4ab52c61..67ef1b28df 100644 --- a/models/unittest/fixture_loader.go +++ b/models/unittest/fixture_loader.go @@ -12,9 +12,7 @@ import ( "path/filepath" "strings" - "forgejo.org/modules/container" - - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) type insertSQL struct { @@ -34,15 +32,13 @@ type loader struct { fixtureFiles []*fixtureFile } -func newFixtureLoader(db *sql.DB, dialect string, fixturePaths []string, allTableNames container.Set[string]) (*loader, error) { +func newFixtureLoader(db *sql.DB, dialect string, fixturePaths []string) (*loader, error) { l := &loader{ db: db, dialect: dialect, fixtureFiles: []*fixtureFile{}, } - tablesWithoutFixture := allTableNames - // Load fixtures for _, fixturePath := range fixturePaths { stat, err := os.Stat(fixturePath) @@ -64,7 +60,6 @@ func newFixtureLoader(db *sql.DB, dialect string, fixturePaths []string, allTabl return nil, err } l.fixtureFiles = append(l.fixtureFiles, fixtureFile) - tablesWithoutFixture.Remove(fixtureFile.name) } } } else { @@ -76,14 +71,6 @@ func newFixtureLoader(db *sql.DB, dialect string, fixturePaths []string, allTabl } } - // Even though these tables have no fixtures, they can still be used and ensure - // they are cleaned. - for table := range tablesWithoutFixture.Seq() { - l.fixtureFiles = append(l.fixtureFiles, &fixtureFile{ - name: table, - }) - } - return l, nil } @@ -191,13 +178,13 @@ func (l *loader) Load() error { }() // Clean the table and re-insert the fixtures. - tableDeleted := make(container.Set[string]) + tableDeleted := map[string]struct{}{} for _, fixture := range l.fixtureFiles { - if !tableDeleted.Contains(fixture.name) { + if _, ok := tableDeleted[fixture.name]; !ok { if _, err := tx.Exec(fmt.Sprintf("DELETE FROM %s", l.quoteKeyword(fixture.name))); err != nil { return fmt.Errorf("cannot delete table %s: %w", fixture.name, err) } - tableDeleted.Add(fixture.name) + tableDeleted[fixture.name] = struct{}{} } for _, insertSQL := range fixture.insertSQLs { diff --git a/models/unittest/fixtures.go b/models/unittest/fixtures.go index 829cc16466..6dc5c8412d 100644 --- a/models/unittest/fixtures.go +++ b/models/unittest/fixtures.go @@ -7,12 +7,10 @@ package unittest import ( "fmt" "path/filepath" - "sync" "time" "forgejo.org/models/db" "forgejo.org/modules/auth/password/hash" - "forgejo.org/modules/container" "forgejo.org/modules/setting" "xorm.io/xorm" @@ -46,8 +44,6 @@ func OverrideFixtures(dir string) func() { } } -var allTableNames = sync.OnceValue(db.GetTableNames) - // InitFixtures initialize test fixtures for a test database func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) { e, err := GetXORMEngine(engine...) @@ -79,12 +75,7 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) { panic("Unsupported RDBMS for test") } - var allTables container.Set[string] - if !opts.SkipCleanRegistedModels { - allTables = allTableNames().Clone() - } - - fixturesLoader, err = newFixtureLoader(e.DB().DB, dialect, fixturePaths, allTables) + fixturesLoader, err = newFixtureLoader(e.DB().DB, dialect, fixturePaths) if err != nil { return err } diff --git a/models/unittest/mock_http.go b/models/unittest/mock_http.go index c2c12e55ee..6064e07e9b 100644 --- a/models/unittest/mock_http.go +++ b/models/unittest/mock_http.go @@ -41,10 +41,6 @@ func NewMockWebServer(t *testing.T, liveServerBaseURL, testDataDir string, liveM log.Info("Mock HTTP Server: got request for path %s", r.URL.Path) // TODO check request method (support POST?) fixturePath := fmt.Sprintf("%s/%s_%s", testDataDir, r.Method, url.PathEscape(path)) - if strings.Contains(path, "test_repo.git") { - // We got a git clone request against our mock server - fixturePath = fmt.Sprintf("%s/%s", testDataDir, strings.TrimLeft(r.URL.Path, "/")) - } if liveMode { liveURL := fmt.Sprintf("%s%s", liveServerBaseURL, path) diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go index 29ec82c55f..d34c9e9a0a 100644 --- a/models/unittest/testdb.go +++ b/models/unittest/testdb.go @@ -217,10 +217,6 @@ type FixturesOptions struct { Files []string Dirs []string Base string - // By default all registered models are cleaned, even if they do not have - // fixture. Enabling this will skip that and only models with fixtures are - // considered. - SkipCleanRegistedModels bool } // CreateTestEngine creates a memory database and loads the fixture data from fixturesDir diff --git a/models/user/activitypub.go b/models/user/activitypub.go index aabf2336fc..816fd8a098 100644 --- a/models/user/activitypub.go +++ b/models/user/activitypub.go @@ -19,7 +19,7 @@ func (u *User) APActorID() string { return fmt.Sprintf("%sapi/v1/activitypub/user-id/%s", setting.AppURL, url.PathEscape(fmt.Sprintf("%d", u.ID))) } -// KeyID returns the ID of the user's public key -func (u *User) KeyID() string { +// APActorKeyID returns the ID of the user's public key +func (u *User) APActorKeyID() string { return u.APActorID() + "#main-key" } diff --git a/models/user/fixtures/login_source.yml b/models/user/fixtures/login_source.yml deleted file mode 100644 index 3950f85964..0000000000 --- a/models/user/fixtures/login_source.yml +++ /dev/null @@ -1,8 +0,0 @@ -- - id: 1001 - type: 6 # OAuth2 - name: OAuth2 authentication source - is_active: 1 - cfg: '{"Provider":"invalid","ClientID":"invalid","ClientSecret":"invalid","AllowUsernameChange":true}' - created_unix: 1753740851 - updated_unix: 1753740851 diff --git a/models/user/fixtures/user.yml b/models/user/fixtures/user.yml index 137064a368..b1892f331b 100644 --- a/models/user/fixtures/user.yml +++ b/models/user/fixtures/user.yml @@ -11,7 +11,6 @@ must_change_password: false login_source: 1001 login_name: 123 - login_type: 6 type: 5 salt: ZogKvWdyEx max_repo_creation: -1 diff --git a/models/user/follow.go b/models/user/follow.go index 8663b2a943..e32c226385 100644 --- a/models/user/follow.go +++ b/models/user/follow.go @@ -39,21 +39,21 @@ func FollowUser(ctx context.Context, userID, followID int64) (err error) { return ErrBlockedByUser } - dbCtx, committer, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } defer committer.Close() - if err = db.Insert(dbCtx, &Follow{UserID: userID, FollowID: followID}); err != nil { + if err = db.Insert(ctx, &Follow{UserID: userID, FollowID: followID}); err != nil { return err } - if _, err = db.Exec(dbCtx, "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?", followID); err != nil { + if _, err = db.Exec(ctx, "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?", followID); err != nil { return err } - if _, err = db.Exec(dbCtx, "UPDATE `user` SET num_following = num_following + 1 WHERE id = ?", userID); err != nil { + if _, err = db.Exec(ctx, "UPDATE `user` SET num_following = num_following + 1 WHERE id = ?", userID); err != nil { return err } return committer.Commit() @@ -65,21 +65,21 @@ func UnfollowUser(ctx context.Context, userID, followID int64) (err error) { return nil } - dbCtx, committer, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } defer committer.Close() - if _, err = db.DeleteByBean(dbCtx, &Follow{UserID: userID, FollowID: followID}); err != nil { + if _, err = db.DeleteByBean(ctx, &Follow{UserID: userID, FollowID: followID}); err != nil { return err } - if _, err = db.Exec(dbCtx, "UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?", followID); err != nil { + if _, err = db.Exec(ctx, "UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?", followID); err != nil { return err } - if _, err = db.Exec(dbCtx, "UPDATE `user` SET num_following = num_following - 1 WHERE id = ?", userID); err != nil { + if _, err = db.Exec(ctx, "UPDATE `user` SET num_following = num_following - 1 WHERE id = ?", userID); err != nil { return err } return committer.Commit() diff --git a/models/user/moderation.go b/models/user/moderation.go index 17901f84ec..f9c16a17b3 100644 --- a/models/user/moderation.go +++ b/models/user/moderation.go @@ -37,26 +37,6 @@ type UserData struct { //revive:disable-line:exported AvatarEmail string } -// Implements GetFieldsMap() from ShadowCopyData interface, returning a list of pairs -// to be used when rendering the shadow copy for admins reviewing the corresponding abuse report(s). -func (ud UserData) GetFieldsMap() []moderation.ShadowCopyField { - return []moderation.ShadowCopyField{ - {Key: "Name", Value: ud.Name}, - {Key: "FullName", Value: ud.FullName}, - {Key: "Email", Value: ud.Email}, - {Key: "LoginName", Value: ud.LoginName}, - {Key: "Location", Value: ud.Location}, - {Key: "Website", Value: ud.Website}, - {Key: "Pronouns", Value: ud.Pronouns}, - {Key: "Description", Value: ud.Description}, - {Key: "CreatedUnix", Value: ud.CreatedUnix.AsLocalTime().String()}, - {Key: "UpdatedUnix", Value: ud.UpdatedUnix.AsLocalTime().String()}, - {Key: "LastLogin", Value: ud.LastLogin.AsLocalTime().String()}, - {Key: "Avatar", Value: ud.Avatar}, - {Key: "AvatarEmail", Value: ud.AvatarEmail}, - } -} - // newUserData creates a trimmed down user to be used just to create a JSON structure // (keeping only the fields relevant for moderation purposes) func newUserData(user *User) UserData { diff --git a/models/user/moderation_test.go b/models/user/moderation_test.go deleted file mode 100644 index f951e41e11..0000000000 --- a/models/user/moderation_test.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package user_test - -import ( - "testing" - - "forgejo.org/models/moderation" - "forgejo.org/models/user" - "forgejo.org/modules/timeutil" - - "github.com/stretchr/testify/assert" -) - -const ( - tsCreated timeutil.TimeStamp = timeutil.TimeStamp(1753093200) // 2025-07-21 10:20:00 UTC - tsUpdated timeutil.TimeStamp = timeutil.TimeStamp(1753093320) // 2025-07-21 10:22:00 UTC - tsLastLogin timeutil.TimeStamp = timeutil.TimeStamp(1753093800) // 2025-07-21 10:30:00 UTC -) - -func testShadowCopyField(t *testing.T, scField moderation.ShadowCopyField, key, value string) { - assert.Equal(t, key, scField.Key) - assert.Equal(t, value, scField.Value) -} - -func TestUserDataGetFieldsMap(t *testing.T) { - ud := user.UserData{ - Name: "alexsmith", - FullName: "Alex Smith", - Email: "alexsmith@example.org", - LoginName: "", - Location: "@master@seo.net", - Website: "http://promote-your-business.biz", - Pronouns: "SEO", - Description: "I can help you promote your business online using SEO.", - CreatedUnix: tsCreated, - UpdatedUnix: tsUpdated, - LastLogin: tsLastLogin, - Avatar: "avatar-hash-user-1002", - AvatarEmail: "alexsmith@example.org", - } - scFields := ud.GetFieldsMap() - - if assert.Len(t, scFields, 13) { - testShadowCopyField(t, scFields[0], "Name", "alexsmith") - testShadowCopyField(t, scFields[1], "FullName", "Alex Smith") - testShadowCopyField(t, scFields[2], "Email", "alexsmith@example.org") - testShadowCopyField(t, scFields[3], "LoginName", "") - testShadowCopyField(t, scFields[4], "Location", "@master@seo.net") - testShadowCopyField(t, scFields[5], "Website", "http://promote-your-business.biz") - testShadowCopyField(t, scFields[6], "Pronouns", "SEO") - testShadowCopyField(t, scFields[7], "Description", "I can help you promote your business online using SEO.") - testShadowCopyField(t, scFields[8], "CreatedUnix", tsCreated.AsLocalTime().String()) - testShadowCopyField(t, scFields[9], "UpdatedUnix", tsUpdated.AsLocalTime().String()) - testShadowCopyField(t, scFields[10], "LastLogin", tsLastLogin.AsLocalTime().String()) - testShadowCopyField(t, scFields[11], "Avatar", "avatar-hash-user-1002") - testShadowCopyField(t, scFields[12], "AvatarEmail", "alexsmith@example.org") - } -} diff --git a/models/user/openid.go b/models/user/openid.go index b4d4f175b2..96b00255a3 100644 --- a/models/user/openid.go +++ b/models/user/openid.go @@ -40,8 +40,8 @@ func GetUserOpenIDs(ctx context.Context, uid int64) ([]*UserOpenID, error) { return openids, nil } -// IsOpenIDUsed returns true if the openid has been used. -func IsOpenIDUsed(ctx context.Context, uri string) (bool, error) { +// isOpenIDUsed returns true if the openid has been used. +func isOpenIDUsed(ctx context.Context, uri string) (bool, error) { if len(uri) == 0 { return true, nil } @@ -71,7 +71,7 @@ func (err ErrOpenIDAlreadyUsed) Unwrap() error { // AddUserOpenID adds an pre-verified/normalized OpenID URI to given user. // NOTE: make sure openid.URI is normalized already func AddUserOpenID(ctx context.Context, openid *UserOpenID) error { - used, err := IsOpenIDUsed(ctx, openid.URI) + used, err := isOpenIDUsed(ctx, openid.URI) if err != nil { return err } else if used { diff --git a/models/user/redirect.go b/models/user/redirect.go index bcb421d4a1..75876f17d2 100644 --- a/models/user/redirect.go +++ b/models/user/redirect.go @@ -21,8 +21,7 @@ import ( // ErrUserRedirectNotExist represents a "UserRedirectNotExist" kind of error. type ErrUserRedirectNotExist struct { - Name string - MissingPermission bool + Name string } // IsErrUserRedirectNotExist check if an error is an ErrUserRedirectNotExist. @@ -82,6 +81,15 @@ func GetUserRedirect(ctx context.Context, userName string) (*Redirect, error) { return redirect, nil } +// LookupUserRedirect look up userID if a user has a redirect name +func LookupUserRedirect(ctx context.Context, userName string) (int64, error) { + redirect, err := GetUserRedirect(ctx, userName) + if err != nil { + return 0, err + } + return redirect.RedirectUserID, nil +} + // NewUserRedirect create a new user redirect func NewUserRedirect(ctx context.Context, ID int64, oldUserName, newUserName string) error { oldUserName = strings.ToLower(oldUserName) diff --git a/models/user/redirect_test.go b/models/user/redirect_test.go new file mode 100644 index 0000000000..c598fb045f --- /dev/null +++ b/models/user/redirect_test.go @@ -0,0 +1,26 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package user_test + +import ( + "testing" + + "forgejo.org/models/db" + "forgejo.org/models/unittest" + user_model "forgejo.org/models/user" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestLookupUserRedirect(t *testing.T) { + require.NoError(t, unittest.PrepareTestDatabase()) + + userID, err := user_model.LookupUserRedirect(db.DefaultContext, "olduser1") + require.NoError(t, err) + assert.EqualValues(t, 1, userID) + + _, err = user_model.LookupUserRedirect(db.DefaultContext, "doesnotexist") + assert.True(t, user_model.IsErrUserRedirectNotExist(err)) +} diff --git a/models/user/user.go b/models/user/user.go index 8cdecc06e4..6b54776adf 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -234,33 +234,6 @@ func GetAllAdmins(ctx context.Context) ([]*User, error) { return users, db.GetEngine(ctx).OrderBy("id").Where("type = ?", UserTypeIndividual).And("is_admin = ?", true).Find(&users) } -// MustHaveTwoFactor returns true if the user is a individual and requires 2fa -func (u *User) MustHaveTwoFactor() bool { - if !u.IsIndividual() || setting.GlobalTwoFactorRequirement.IsNone() { - return false - } - - return setting.GlobalTwoFactorRequirement.IsAll() || (u.IsAdmin && setting.GlobalTwoFactorRequirement.IsAdmin()) -} - -// IsAccessAllowed determines whether the user is permitted to log in based on -// their activation status, login prohibition, 2FA requirement and 2FA enrollment status. -func (u *User) IsAccessAllowed(ctx context.Context) bool { - if !u.IsActive || u.ProhibitLogin { - return false - } - if !u.MustHaveTwoFactor() { - return true - } - - hasTwoFactor, err := auth.HasTwoFactorByUID(ctx, u.ID) - if err != nil { - log.Error("Error getting 2fa: %s", err) - return false - } - return hasTwoFactor -} - // IsLocal returns true if user login type is LoginPlain. func (u *User) IsLocal() bool { return u.LoginType <= auth.Plain @@ -323,9 +296,6 @@ func (u *User) CanImportLocal() bool { // DashboardLink returns the user dashboard page link. func (u *User) DashboardLink() string { - if u.IsGhost() { - return "" - } if u.IsOrganization() { return u.OrganisationLink() + "/dashboard" } @@ -334,25 +304,16 @@ func (u *User) DashboardLink() string { // HomeLink returns the user or organization home page link. func (u *User) HomeLink() string { - if u.IsGhost() { - return "" - } return setting.AppSubURL + "/" + url.PathEscape(u.Name) } // HTMLURL returns the user or organization's full link. func (u *User) HTMLURL() string { - if u.IsGhost() { - return "" - } return setting.AppURL + url.PathEscape(u.Name) } // OrganisationLink returns the organization sub page link. func (u *User) OrganisationLink() string { - if u.IsGhost() || !u.IsOrganization() { - return "" - } return setting.AppSubURL + "/org/" + url.PathEscape(u.Name) } @@ -1202,8 +1163,8 @@ func GetUserByEmail(ctx context.Context, email string) (*User, error) { email = strings.ToLower(email) // Otherwise, check in alternative list for activated email addresses - emailAddress := &EmailAddress{} - has, err := db.GetEngine(ctx).Where("lower_email = ? AND is_activated = ?", email, true).Get(emailAddress) + emailAddress := &EmailAddress{LowerEmail: email, IsActivated: true} + has, err := db.GetEngine(ctx).Get(emailAddress) if err != nil { return nil, err } diff --git a/models/user/user_repository.go b/models/user/user_repository.go index df864746e8..3f24efb1fb 100644 --- a/models/user/user_repository.go +++ b/models/user/user_repository.go @@ -28,7 +28,7 @@ func CreateFederatedUser(ctx context.Context, user *User, federatedUser *Federat } // Begin transaction - txCtx, committer, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext((ctx)) if err != nil { return err } @@ -39,7 +39,7 @@ func CreateFederatedUser(ctx context.Context, user *User, federatedUser *Federat } }() - if err := CreateUser(txCtx, user, &overwrite); err != nil { + if err := CreateUser(ctx, user, &overwrite); err != nil { return err } @@ -48,7 +48,7 @@ func CreateFederatedUser(ctx context.Context, user *User, federatedUser *Federat return err } - _, err = db.GetEngine(txCtx).Insert(federatedUser) + _, err = db.GetEngine(ctx).Insert(federatedUser) if err != nil { return err } @@ -57,6 +57,14 @@ func CreateFederatedUser(ctx context.Context, user *User, federatedUser *Federat return committer.Commit() } +func (federatedUser *FederatedUser) UpdateFederatedUser(ctx context.Context) error { + if _, err := validation.IsValid(federatedUser); err != nil { + return err + } + _, err := db.GetEngine(ctx).ID(federatedUser.ID).Cols("inbox_path").Update(federatedUser) + return err +} + func FindFederatedUser(ctx context.Context, externalID string, federationHostID int64) (*User, *FederatedUser, error) { federatedUser := new(FederatedUser) user := new(User) @@ -70,7 +78,7 @@ func FindFederatedUser(ctx context.Context, externalID string, federationHostID if err != nil { return nil, nil, err } else if !has { - return nil, nil, fmt.Errorf("FederatedUser table contains entry for user ID %v, but no user with this ID exists", federatedUser.UserID) + return nil, nil, fmt.Errorf("User %v for federated user is missing", federatedUser.UserID) } if res, err := validation.IsValid(*user); !res { @@ -87,7 +95,7 @@ func GetFederatedUser(ctx context.Context, externalID string, federationHostID i if err != nil { return nil, nil, err } else if federatedUser == nil { - return nil, nil, fmt.Errorf("FederatedUser not found (given externalId: %v, federationHostId: %v)", externalID, federationHostID) + return nil, nil, fmt.Errorf("FederatedUser for externalId = %v and federationHostId = %v does not exist", externalID, federationHostID) } return user, federatedUser, nil } @@ -99,13 +107,13 @@ func GetFederatedUserByUserID(ctx context.Context, userID int64) (*User, *Federa if err != nil { return nil, nil, err } else if !has { - return nil, nil, fmt.Errorf("FederatedUser table does not contain entry for user ID: %v", federatedUser.UserID) + return nil, nil, fmt.Errorf("Federated user %v does not exist", federatedUser.UserID) } has, err = db.GetEngine(ctx).ID(federatedUser.UserID).Get(user) if err != nil { return nil, nil, err } else if !has { - return nil, nil, fmt.Errorf("FederatedUser table contains entry for user ID %v, but no user with this ID exists", federatedUser.UserID) + return nil, nil, fmt.Errorf("User %v for federated user is missing", federatedUser.UserID) } if res, err := validation.IsValid(*user); !res { @@ -130,7 +138,7 @@ func FindFederatedUserByKeyID(ctx context.Context, keyID string) (*User, *Federa if err != nil { return nil, nil, err } else if !has { - return nil, nil, fmt.Errorf("FederatedUser table contains entry for user ID %v, but no user with this ID exists", federatedUser.UserID) + return nil, nil, fmt.Errorf("User %v for federated user is missing", federatedUser.UserID) } if res, err := validation.IsValid(*user); !res { @@ -211,6 +219,7 @@ func RemoveFollower(ctx context.Context, followedUser *User, followingUser *Fede return err } +// TODO: We should unify Activity-pub-following and classical following (see models/user/follow.go) func IsFollowingAp(ctx context.Context, followedUser *User, followingUser *FederatedUser) (bool, error) { if res, err := validation.IsValid(followedUser); !res { return false, err diff --git a/models/user/user_test.go b/models/user/user_test.go index e4a94cbc57..fd9d05653f 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -46,28 +46,6 @@ func TestIsValidUserID(t *testing.T) { assert.True(t, user_model.IsValidUserID(200)) } -func TestUserLinks(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - assert.Equal(t, "/", user1.DashboardLink()) - assert.Equal(t, "/user1", user1.HomeLink()) - assert.Equal(t, "https://try.gitea.io/user1", user1.HTMLURL()) - assert.Empty(t, user1.OrganisationLink()) - - org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) - assert.Equal(t, "/org/org3/dashboard", org3.DashboardLink()) - assert.Equal(t, "/org3", org3.HomeLink()) - assert.Equal(t, "https://try.gitea.io/org3", org3.HTMLURL()) - assert.Equal(t, "/org/org3", org3.OrganisationLink()) - - ghost := user_model.NewGhostUser() - assert.Empty(t, ghost.DashboardLink()) - assert.Empty(t, ghost.HomeLink()) - assert.Empty(t, ghost.HTMLURL()) - assert.Empty(t, ghost.OrganisationLink()) -} - func TestGetUserFromMap(t *testing.T) { id := int64(200) idMap := map[int64]*user_model.User{ @@ -172,7 +150,7 @@ func TestAPActorID_APActorID(t *testing.T) { func TestKeyID(t *testing.T) { user := user_model.User{ID: 1} - url := user.KeyID() + url := user.APActorKeyID() expected := "https://try.gitea.io/api/v1/activitypub/user-id/1#main-key" assert.Equal(t, expected, url) } @@ -637,145 +615,6 @@ func TestGetAllAdmins(t *testing.T) { assert.Equal(t, int64(1), admins[0].ID) } -func TestMustHaveTwoFactor(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - normalUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17}) - restrictedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}) - ghostUser := user_model.NewGhostUser() - - t.Run("NoneTwoFactorRequirement", func(t *testing.T) { - // this should be the default, so don't have to set the variable - assert.False(t, adminUser.MustHaveTwoFactor()) - assert.False(t, normalUser.MustHaveTwoFactor()) - assert.False(t, restrictedUser.MustHaveTwoFactor()) - assert.False(t, org.MustHaveTwoFactor()) - assert.False(t, ghostUser.MustHaveTwoFactor()) - }) - - t.Run("AllTwoFactorRequirement", func(t *testing.T) { - defer test.MockVariableValue(&setting.GlobalTwoFactorRequirement, setting.AllTwoFactorRequirement)() - - assert.True(t, adminUser.MustHaveTwoFactor()) - assert.True(t, normalUser.MustHaveTwoFactor()) - assert.True(t, restrictedUser.MustHaveTwoFactor()) - assert.False(t, org.MustHaveTwoFactor()) - assert.True(t, ghostUser.MustHaveTwoFactor()) - }) - - t.Run("AdminTwoFactorRequirement", func(t *testing.T) { - defer test.MockVariableValue(&setting.GlobalTwoFactorRequirement, setting.AdminTwoFactorRequirement)() - - assert.True(t, adminUser.MustHaveTwoFactor()) - assert.False(t, normalUser.MustHaveTwoFactor()) - assert.False(t, restrictedUser.MustHaveTwoFactor()) - assert.False(t, org.MustHaveTwoFactor()) - assert.False(t, ghostUser.MustHaveTwoFactor()) - }) -} - -func TestIsAccessAllowed(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - runTest := func(t *testing.T, user *user_model.User, useTOTP, accessAllowed bool) { - t.Helper() - if useTOTP { - unittest.AssertSuccessfulInsert(t, &auth.TwoFactor{UID: user.ID}) - defer unittest.AssertSuccessfulDelete(t, &auth.TwoFactor{UID: user.ID}) - } - - assert.Equal(t, accessAllowed, user.IsAccessAllowed(t.Context())) - } - - adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - normalUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) - inactiveUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 9}) - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17}) - restrictedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}) - prohibitLoginUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 37}) - ghostUser := user_model.NewGhostUser() - - // users with enabled WebAuthn - normalWebAuthnUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 32}) - - t.Run("NoneTwoFactorRequirement", func(t *testing.T) { - // this should be the default, so don't have to set the variable - - t.Run("no 2fa", func(t *testing.T) { - runTest(t, adminUser, false, true) - runTest(t, normalUser, false, true) - runTest(t, inactiveUser, false, false) - runTest(t, org, false, true) - runTest(t, restrictedUser, false, true) - runTest(t, prohibitLoginUser, false, false) - runTest(t, ghostUser, false, false) - }) - - t.Run("enabled 2fa", func(t *testing.T) { - runTest(t, normalWebAuthnUser, false, true) - - runTest(t, adminUser, true, true) - runTest(t, normalUser, true, true) - runTest(t, inactiveUser, true, false) - runTest(t, org, true, true) - runTest(t, restrictedUser, true, true) - runTest(t, prohibitLoginUser, true, false) - }) - }) - - t.Run("AllTwoFactorRequirement", func(t *testing.T) { - defer test.MockVariableValue(&setting.GlobalTwoFactorRequirement, setting.AllTwoFactorRequirement)() - - t.Run("no 2fa", func(t *testing.T) { - runTest(t, adminUser, false, false) - runTest(t, normalUser, false, false) - runTest(t, inactiveUser, false, false) - runTest(t, org, false, true) - runTest(t, restrictedUser, false, false) - runTest(t, prohibitLoginUser, false, false) - runTest(t, ghostUser, false, false) - }) - - t.Run("enabled 2fa", func(t *testing.T) { - runTest(t, normalWebAuthnUser, false, true) - - runTest(t, adminUser, true, true) - runTest(t, normalUser, true, true) - runTest(t, inactiveUser, true, false) - runTest(t, org, true, true) - runTest(t, restrictedUser, true, true) - runTest(t, prohibitLoginUser, true, false) - }) - }) - - t.Run("AdminTwoFactorRequirement", func(t *testing.T) { - defer test.MockVariableValue(&setting.GlobalTwoFactorRequirement, setting.AdminTwoFactorRequirement)() - - t.Run("no 2fa", func(t *testing.T) { - runTest(t, adminUser, false, false) - runTest(t, normalUser, false, true) - runTest(t, inactiveUser, false, false) - runTest(t, org, false, true) - runTest(t, restrictedUser, false, true) - runTest(t, prohibitLoginUser, false, false) - runTest(t, ghostUser, false, false) - }) - - t.Run("enabled 2fa", func(t *testing.T) { - runTest(t, normalWebAuthnUser, false, true) - - runTest(t, adminUser, true, true) - runTest(t, normalUser, true, true) - runTest(t, inactiveUser, true, false) - runTest(t, org, true, true) - runTest(t, restrictedUser, true, true) - runTest(t, prohibitLoginUser, true, false) - }) - }) -} - func Test_ValidateUser(t *testing.T) { defer test.MockVariableValue(&setting.Service.AllowedUserVisibilityModesSlice, []bool{true, false, true})() @@ -996,25 +835,3 @@ func TestPronounsPrivacy(t *testing.T) { assert.Equal(t, "any", user.GetPronouns(true)) }) } - -func TestGetUserByEmail(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - t.Run("Normal", func(t *testing.T) { - u, err := user_model.GetUserByEmail(t.Context(), "user2@example.com") - require.NoError(t, err) - assert.EqualValues(t, 2, u.ID) - }) - - t.Run("Not activated", func(t *testing.T) { - u, err := user_model.GetUserByEmail(t.Context(), "user11@example.com") - require.ErrorIs(t, err, user_model.ErrUserNotExist{Name: "user11@example.com"}) - assert.Nil(t, u) - }) - - t.Run("Not primary", func(t *testing.T) { - u, err := user_model.GetUserByEmail(t.Context(), "user1-3@example.com") - require.NoError(t, err) - assert.EqualValues(t, 1, u.ID) - }) -} diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go index c3960d140a..7ae4557ed6 100644 --- a/modules/actions/workflows.go +++ b/modules/actions/workflows.go @@ -13,11 +13,11 @@ import ( api "forgejo.org/modules/structs" webhook_module "forgejo.org/modules/webhook" - "code.forgejo.org/forgejo/runner/v11/act/jobparser" - "code.forgejo.org/forgejo/runner/v11/act/model" - "code.forgejo.org/forgejo/runner/v11/act/workflowpattern" "github.com/gobwas/glob" - "go.yaml.in/yaml/v3" + "github.com/nektos/act/pkg/jobparser" + "github.com/nektos/act/pkg/model" + "github.com/nektos/act/pkg/workflowpattern" + "gopkg.in/yaml.v3" ) type DetectedWorkflow struct { @@ -86,7 +86,7 @@ func GetContentFromEntry(entry *git.TreeEntry) ([]byte, error) { } func GetEventsFromContent(content []byte) ([]*jobparser.Event, error) { - workflow, err := model.ReadWorkflow(bytes.NewReader(content), false) + workflow, err := model.ReadWorkflow(bytes.NewReader(content)) if err != nil { return nil, err } diff --git a/modules/activitypub/client.go b/modules/activitypub/client.go index 11a2fd94c3..d015fb7bec 100644 --- a/modules/activitypub/client.go +++ b/modules/activitypub/client.go @@ -66,11 +66,6 @@ type ClientFactory struct { // NewClient function func NewClientFactory() (c *ClientFactory, err error) { - return NewClientFactoryWithTimeout(5 * time.Second) -} - -// NewClient function -func NewClientFactoryWithTimeout(timeout time.Duration) (c *ClientFactory, err error) { if err = containsRequiredHTTPHeaders(http.MethodGet, setting.Federation.GetHeaders); err != nil { return nil, err } else if err = containsRequiredHTTPHeaders(http.MethodPost, setting.Federation.PostHeaders); err != nil { @@ -82,7 +77,7 @@ func NewClientFactoryWithTimeout(timeout time.Duration) (c *ClientFactory, err e Transport: &http.Transport{ Proxy: proxy.Proxy(), }, - Timeout: timeout, + Timeout: 5 * time.Second, }, algs: setting.HttpsigAlgs, digestAlg: httpsig.DigestAlgorithm(setting.Federation.DigestAlgorithm), @@ -94,7 +89,6 @@ func NewClientFactoryWithTimeout(timeout time.Duration) (c *ClientFactory, err e type APClientFactory interface { WithKeys(ctx context.Context, user *user_model.User, pubID string) (APClient, error) - WithKeysDirect(ctx context.Context, privateKey, pubID string) (APClient, error) } // Client struct @@ -109,8 +103,12 @@ type Client struct { } // NewRequest function -func (cf *ClientFactory) WithKeysDirect(ctx context.Context, privateKey, pubID string) (APClient, error) { - privPem, _ := pem.Decode([]byte(privateKey)) +func (cf *ClientFactory) WithKeys(ctx context.Context, user *user_model.User, pubID string) (APClient, error) { + priv, err := GetPrivateKey(ctx, user) + if err != nil { + return nil, err + } + privPem, _ := pem.Decode([]byte(priv)) privParsed, err := x509.ParsePKCS1PrivateKey(privPem.Bytes) if err != nil { return nil, err @@ -128,14 +126,6 @@ func (cf *ClientFactory) WithKeysDirect(ctx context.Context, privateKey, pubID s return &c, nil } -func (cf *ClientFactory) WithKeys(ctx context.Context, user *user_model.User, pubID string) (APClient, error) { - priv, err := GetPrivateKey(ctx, user) - if err != nil { - return nil, err - } - return cf.WithKeysDirect(ctx, priv, pubID) -} - // NewRequest function func (c *Client) newRequest(method string, b []byte, to string) (req *http.Request, err error) { buf := bytes.NewBuffer(b) @@ -159,14 +149,12 @@ func (c *Client) Post(b []byte, to string) (resp *http.Response, err error) { return nil, err } - if c.pubID != "" { - signer, _, err := httpsig.NewSigner(c.algs, c.digestAlg, c.postHeaders, httpsig.Signature, httpsigExpirationTime) - if err != nil { - return nil, err - } - if err := signer.SignRequest(c.priv, c.pubID, req, b); err != nil { - return nil, err - } + signer, _, err := httpsig.NewSigner(c.algs, c.digestAlg, c.postHeaders, httpsig.Signature, httpsigExpirationTime) + if err != nil { + return nil, err + } + if err := signer.SignRequest(c.priv, c.pubID, req, b); err != nil { + return nil, err } resp, err = c.client.Do(req) @@ -179,15 +167,12 @@ func (c *Client) Get(to string) (resp *http.Response, err error) { if req, err = c.newRequest(http.MethodGet, nil, to); err != nil { return nil, err } - - if c.pubID != "" { - signer, _, err := httpsig.NewSigner(c.algs, c.digestAlg, c.getHeaders, httpsig.Signature, httpsigExpirationTime) - if err != nil { - return nil, err - } - if err := signer.SignRequest(c.priv, c.pubID, req, nil); err != nil { - return nil, err - } + signer, _, err := httpsig.NewSigner(c.algs, c.digestAlg, c.getHeaders, httpsig.Signature, httpsigExpirationTime) + if err != nil { + return nil, err + } + if err := signer.SignRequest(c.priv, c.pubID, req, nil); err != nil { + return nil, err } resp, err = c.client.Do(req) diff --git a/modules/base/tool.go b/modules/base/tool.go index e3a3ff4a23..fd6a7c2b77 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -114,7 +114,7 @@ func EntryIcon(entry *git.TreeEntry) string { return "file-symlink-file" case entry.IsDir(): return "file-directory-fill" - case entry.IsSubmodule(): + case entry.IsSubModule(): return "file-submodule" } diff --git a/modules/container/set.go b/modules/container/set.go index d3719dc552..70f837bc66 100644 --- a/modules/container/set.go +++ b/modules/container/set.go @@ -74,8 +74,3 @@ func (s Set[T]) Values() []T { func (s Set[T]) Seq() iter.Seq[T] { return maps.Keys(s) } - -// Clone returns a identical shallow copy of this set. -func (s Set[T]) Clone() Set[T] { - return maps.Clone(s) -} diff --git a/modules/container/set_test.go b/modules/container/set_test.go index 44e4847f6b..af5e9126ab 100644 --- a/modules/container/set_test.go +++ b/modules/container/set_test.go @@ -47,11 +47,4 @@ func TestSet(t *testing.T) { assert.False(t, s.IsSubset([]string{"key1"})) assert.True(t, s.IsSubset([]string{})) - - t.Run("Clone", func(t *testing.T) { - clonedSet := s.Clone() - clonedSet.Remove("key6") - assert.False(t, clonedSet.Contains("key6")) - assert.True(t, s.Contains("key6")) - }) } diff --git a/modules/forgefed/activity_follow_test.go b/modules/forgefed/activity_follow_test.go index 8ba31d5f6f..bb0c1de2f7 100644 --- a/modules/forgefed/activity_follow_test.go +++ b/modules/forgefed/activity_follow_test.go @@ -9,7 +9,6 @@ import ( "forgejo.org/modules/validation" ap "github.com/go-ap/activitypub" - "github.com/stretchr/testify/assert" ) func Test_NewForgeFollowValidation(t *testing.T) { @@ -18,13 +17,15 @@ func Test_NewForgeFollowValidation(t *testing.T) { sut.Actor = ap.IRI("example.org/alice") sut.Object = ap.IRI("example.org/bob") - valid, err := validation.IsValid(sut) - assert.True(t, valid, "sut is invalid: %v\n", err) + if err, _ := validation.IsValid(sut); !err { + t.Errorf("sut is invalid: %v\n", err) + } sut = ForgeFollow{} sut.Actor = ap.IRI("example.org/alice") sut.Object = ap.IRI("example.org/bob") - valid, err = validation.IsValid(sut) - assert.False(t, valid, "sut is valid: %v\n", err) + if err, _ := validation.IsValid(sut); err { + t.Errorf("sut is valid: %v\n", err) + } } diff --git a/modules/forgefed/activity_like_test.go b/modules/forgefed/activity_like_test.go index eef5563d8b..6b252d5960 100644 --- a/modules/forgefed/activity_like_test.go +++ b/modules/forgefed/activity_like_test.go @@ -13,8 +13,6 @@ import ( "forgejo.org/modules/validation" ap "github.com/go-ap/activitypub" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_NewForgeLike(t *testing.T) { @@ -24,14 +22,21 @@ func Test_NewForgeLike(t *testing.T) { objectIRI := "https://codeberg.org/api/v1/activitypub/repository-id/1" startTime, _ := time.Parse("2006-Jan-02", "2024-Mar-07") sut, err := NewForgeLike(actorIRI, objectIRI, startTime) - require.NoError(t, err, "unexpected error: %v\n", err) - - valid, _ := validation.IsValid(sut) - assert.True(t, valid, "sut expected to be valid: %v\n", sut.Validate()) + if err != nil { + t.Errorf("unexpected error: %v\n", err) + } + if valid, _ := validation.IsValid(sut); !valid { + t.Errorf("sut expected to be valid: %v\n", sut.Validate()) + } got, err := sut.MarshalJSON() - require.NoError(t, err, "MarshalJSON() error = %q", err) - assert.True(t, reflect.DeepEqual(got, want), "MarshalJSON()\n got: %q,\n want: %q", got, want) + if err != nil { + t.Errorf("MarshalJSON() error = \"%v\"", err) + return + } + if !reflect.DeepEqual(got, want) { + t.Errorf("MarshalJSON() got = %q, want %q", got, want) + } } func Test_LikeMarshalJSON(t *testing.T) { @@ -61,8 +66,13 @@ func Test_LikeMarshalJSON(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { got, err := tt.item.MarshalJSON() - assert.False(t, (err != nil || tt.wantErr != nil) && tt.wantErr.Error() != err.Error(), "MarshalJSON()\n got: %v,\n want: %v", err, tt.wantErr) - assert.True(t, reflect.DeepEqual(got, tt.want), "MarshalJSON()\n got: %q\n want: %q", got, tt.want) + if (err != nil || tt.wantErr != nil) && tt.wantErr.Error() != err.Error() { + t.Errorf("MarshalJSON() error = \"%v\", wantErr \"%v\"", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("MarshalJSON() got = %q, want %q", got, tt.want) + } }) } } @@ -79,8 +89,8 @@ func Test_LikeUnmarshalJSON(t *testing.T) { item: []byte(`{"type":"Like","actor":"https://repo.prod.meissa.de/api/activitypub/user-id/1","object":"https://codeberg.org/api/activitypub/repository-id/1"}`), want: &ForgeLike{ Activity: ap.Activity{ - Type: "Like", Actor: ap.IRI("https://repo.prod.meissa.de/api/activitypub/user-id/1"), + Type: "Like", Object: ap.IRI("https://codeberg.org/api/activitypub/repository-id/1"), }, }, @@ -97,10 +107,12 @@ func Test_LikeUnmarshalJSON(t *testing.T) { t.Run(name, func(t *testing.T) { got := new(ForgeLike) err := got.UnmarshalJSON(test.item) - assert.False(t, (err != nil || test.wantErr != nil) && !strings.Contains(err.Error(), test.wantErr.Error()), "UnmarshalJSON()\n error: %v\n wantErr: %v", err, test.wantErr) - + if (err != nil || test.wantErr != nil) && !strings.Contains(err.Error(), test.wantErr.Error()) { + t.Errorf("UnmarshalJSON() error = \"%v\", wantErr \"%v\"", err, test.wantErr) + return + } if !reflect.DeepEqual(got, test.want) { - assert.Errorf(t, err, "UnmarshalJSON() got = %q, want %q, err %q", got, test.want, err.Error()) + t.Errorf("UnmarshalJSON() got = %q, want %q, err %q", got, test.want, err.Error()) } }) } @@ -108,47 +120,46 @@ func Test_LikeUnmarshalJSON(t *testing.T) { func Test_ForgeLikeValidation(t *testing.T) { // Successful + sut := new(ForgeLike) sut.UnmarshalJSON([]byte(`{"type":"Like", "actor":"https://repo.prod.meissa.de/api/activitypub/user-id/1", "object":"https://codeberg.org/api/activitypub/repository-id/1", "startTime": "2014-12-31T23:00:00-08:00"}`)) - valid, _ := validation.IsValid(sut) - assert.True(t, valid, "sut expected to be valid: %v\n", sut.Validate()) + if res, _ := validation.IsValid(sut); !res { + t.Errorf("sut expected to be valid: %v\n", sut.Validate()) + } // Errors + sut.UnmarshalJSON([]byte(`{"actor":"https://repo.prod.meissa.de/api/activitypub/user-id/1", "object":"https://codeberg.org/api/activitypub/repository-id/1", "startTime": "2014-12-31T23:00:00-08:00"}`)) - validate := sut.Validate() - assert.Len(t, validate, 2) - assert.Equal(t, - "Field type contains the value , which is not in allowed subset [Like]", - validate[1]) + if err := validateAndCheckError(sut, "type should not be empty"); err != nil { + t.Error(err) + } sut.UnmarshalJSON([]byte(`{"type":"bad-type", "actor":"https://repo.prod.meissa.de/api/activitypub/user-id/1", "object":"https://codeberg.org/api/activitypub/repository-id/1", "startTime": "2014-12-31T23:00:00-08:00"}`)) - validate = sut.Validate() - assert.Len(t, validate, 1) - assert.Equal(t, - "Field type contains the value bad-type, which is not in allowed subset [Like]", - validate[0]) + if err := validateAndCheckError(sut, "Field type contains the value bad-type, which is not in allowed subset [Like]"); err != nil { + t.Error(err) + } sut.UnmarshalJSON([]byte(`{"type":"Like", "actor":"https://repo.prod.meissa.de/api/activitypub/user-id/1", "object":"https://codeberg.org/api/activitypub/repository-id/1", "startTime": "not a date"}`)) - validate = sut.Validate() - assert.Len(t, validate, 1) - assert.Equal(t, - "StartTime was invalid.", - validate[0]) + if err := validateAndCheckError(sut, "StartTime was invalid."); err != nil { + t.Error(err) + } } func TestActivityValidation_Attack(t *testing.T) { sut := new(ForgeLike) sut.UnmarshalJSON([]byte(`{rubbish}`)) - assert.Len(t, sut.Validate(), 5) + if len(sut.Validate()) != 5 { + t.Errorf("5 validation errors expected but was: %v\n", len(sut.Validate())) + } } diff --git a/modules/forgefed/activity_undo_like_test.go b/modules/forgefed/activity_undo_like_test.go index 76358b1669..5867a84e7b 100644 --- a/modules/forgefed/activity_undo_like_test.go +++ b/modules/forgefed/activity_undo_like_test.go @@ -173,7 +173,7 @@ func TestActivityValidationUndo(t *testing.T) { "startTime":"2024-03-27T00:00:00Z", "actor":"https://repo.prod.meissa.de/api/v1/activitypub/user-id/1", "object":"https://codeberg.org/api/v1/activitypub/repository-id/1"}}`)) - if err := validateAndCheckError(sut, "Value type should not be empty"); err != nil { + if err := validateAndCheckError(sut, "type should not be empty"); err != nil { t.Error(*err) } diff --git a/modules/forgefed/activity_user_activity_test.go b/modules/forgefed/activity_user_activity_test.go index 107ae51204..9cb9f133b9 100644 --- a/modules/forgefed/activity_user_activity_test.go +++ b/modules/forgefed/activity_user_activity_test.go @@ -9,7 +9,6 @@ import ( "forgejo.org/modules/validation" ap "github.com/go-ap/activitypub" - "github.com/stretchr/testify/assert" ) func Test_ForgeUserActivityValidation(t *testing.T) { @@ -35,6 +34,7 @@ func Test_ForgeUserActivityValidation(t *testing.T) { sut.Note = note - valid, _ := validation.IsValid(sut) - assert.True(t, valid, "sut expected to be valid: %v\n", sut.Validate()) + if res, _ := validation.IsValid(sut); !res { + t.Errorf("sut expected to be valid: %v\n", sut.Validate()) + } } diff --git a/modules/forgefed/actor_person_test.go b/modules/forgefed/actor_person_test.go index e4f1734a9d..f466ddb964 100644 --- a/modules/forgefed/actor_person_test.go +++ b/modules/forgefed/actor_person_test.go @@ -115,7 +115,7 @@ func TestPersonIdValidation(t *testing.T) { result, err := validation.IsValid(sut) assert.False(t, result) - require.EqualError(t, err, "Validation Error: forgefed.PersonID: Value path should not be empty\npath: \"\" has to be a person specific api path") + require.EqualError(t, err, "Validation Error: forgefed.PersonID: path should not be empty\npath: \"\" has to be a person specific api path") sut = PersonID{} sut.ID = "1" @@ -166,28 +166,38 @@ func TestWebfingerId(t *testing.T) { } func TestShouldThrowErrorOnInvalidInput(t *testing.T) { - tests := []struct { - input string - username string - expectErr bool - }{ - {"", "forgejo", true}, - {"http://localhost:3000/api/v1/something", "forgejo", true}, - {"./api/v1/something", "forgejo", true}, - {"http://1.2.3.4/api/v1/something", "forgejo", true}, - {"http:///[fe80::1ff:fe23:4567:890a%25eth0]/api/v1/something", "forgejo", true}, - {"https://codeberg.org/api/v1/activitypub/../activitypub/user-id/12345", "forgejo", true}, - {"https://myuser@an.other.host/api/v1/activitypub/user-id/1", "forgejo", true}, - {"https://an.other.host/api/v1/activitypub/user-id/1", "forgejo", false}, + var err any + _, err = NewPersonID("", "forgejo") + if err == nil { + t.Errorf("empty input should be invalid.") } - - for _, tt := range tests { - _, err := NewPersonID(tt.input, tt.username) - if tt.expectErr { - assert.Error(t, err, "Expected an error for input: %s", tt.input) - } else { - assert.NoError(t, err, "Expected no error for input: %s, but got: %v", tt.input, err) - } + _, err = NewPersonID("http://localhost:3000/api/v1/something", "forgejo") + if err == nil { + t.Errorf("localhost uris are not external") + } + _, err = NewPersonID("./api/v1/something", "forgejo") + if err == nil { + t.Errorf("relative uris are not allowed") + } + _, err = NewPersonID("http://1.2.3.4/api/v1/something", "forgejo") + if err == nil { + t.Errorf("uri may not be ip-4 based") + } + _, err = NewPersonID("http:///[fe80::1ff:fe23:4567:890a%25eth0]/api/v1/something", "forgejo") + if err == nil { + t.Errorf("uri may not be ip-6 based") + } + _, err = NewPersonID("https://codeberg.org/api/v1/activitypub/../activitypub/user-id/12345", "forgejo") + if err == nil { + t.Errorf("uri may not contain relative path elements") + } + _, err = NewPersonID("https://myuser@an.other.host/api/v1/activitypub/user-id/1", "forgejo") + if err == nil { + t.Errorf("uri may not contain unparsed elements") + } + _, err = NewPersonID("https://an.other.host/api/v1/activitypub/user-id/1", "forgejo") + if err != nil { + t.Errorf("this uri should be valid but was: %v", err) } } @@ -211,11 +221,14 @@ func Test_PersonUnmarshalJSON(t *testing.T) { } sut := new(ForgePerson) err := sut.UnmarshalJSON([]byte(`{"type":"Person","preferredUsername":"MaxMuster"}`)) - require.NoError(t, err, "UnmarshalJSON() unexpected error: %q", err) - + if err != nil { + t.Errorf("UnmarshalJSON() unexpected error: %v", err) + } x, _ := expected.MarshalJSON() y, _ := sut.MarshalJSON() - assert.True(t, reflect.DeepEqual(x, y), "UnmarshalJSON()\n got: %q,\n want: %q", x, y) + if !reflect.DeepEqual(x, y) { + t.Errorf("UnmarshalJSON() expected: %q got: %q", x, y) + } expectedStr := strings.ReplaceAll(strings.ReplaceAll(`{ "id":"https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/10", @@ -231,7 +244,9 @@ func Test_PersonUnmarshalJSON(t *testing.T) { "\n", ""), "\t", "") err = sut.UnmarshalJSON([]byte(expectedStr)) - require.NoError(t, err, "UnmarshalJSON() unexpected error: %q", err) + if err != nil { + t.Errorf("UnmarshalJSON() unexpected error: %v", err) + } result, _ := sut.MarshalJSON() assert.JSONEq(t, expectedStr, string(result), "Expected string is not equal") } @@ -239,8 +254,9 @@ func Test_PersonUnmarshalJSON(t *testing.T) { func TestForgePersonValidation(t *testing.T) { sut := new(ForgePerson) sut.UnmarshalJSON([]byte(`{"type":"Person","preferredUsername":"MaxMuster"}`)) - valid, _ := validation.IsValid(sut) - assert.True(t, valid, "sut expected to be valid: %v\n", sut.Validate()) + if res, _ := validation.IsValid(sut); !res { + t.Errorf("sut expected to be valid: %v\n", sut.Validate()) + } } func TestAsloginName(t *testing.T) { diff --git a/modules/forgefed/actor_test.go b/modules/forgefed/actor_test.go index a32114616c..48d773c5b9 100644 --- a/modules/forgefed/actor_test.go +++ b/modules/forgefed/actor_test.go @@ -58,7 +58,7 @@ func TestActorIdValidation(t *testing.T) { sut.UnvalidatedInput = "https://an.other.host/api/v1/activitypub/user-id/" result := sut.Validate() assert.Len(t, result, 1) - assert.Equal(t, "Value ID should not be empty", result[0]) + assert.Equal(t, "ID should not be empty", result[0]) sut = ActorID{} sut.ID = "1" diff --git a/modules/forgefed/object_user_activity_note_test.go b/modules/forgefed/object_user_activity_note_test.go index 02aebd58d3..20c3666bb1 100644 --- a/modules/forgefed/object_user_activity_note_test.go +++ b/modules/forgefed/object_user_activity_note_test.go @@ -9,7 +9,6 @@ import ( "forgejo.org/modules/validation" ap "github.com/go-ap/activitypub" - "github.com/stretchr/testify/assert" ) func Test_UserActivityNoteValidation(t *testing.T) { @@ -23,6 +22,7 @@ func Test_UserActivityNoteValidation(t *testing.T) { } sut.URL = ap.IRI("example.org/user-id/57") - valid, _ := validation.IsValid(sut) - assert.True(t, valid, "sut expected to be valid: %v\n", sut.Validate()) + if res, _ := validation.IsValid(sut); !res { + t.Errorf("sut expected to be valid: %v\n", sut.Validate()) + } } diff --git a/modules/git/blame.go b/modules/git/blame.go index 868edab2b8..4ff347e31b 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -132,7 +132,7 @@ func (r *BlameReader) Close() error { // CreateBlameReader creates reader for given repository, commit and file func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) { var ignoreRevsFile *string - if !bypassBlameIgnore { + if CheckGitVersionAtLeast("2.23") == nil && !bypassBlameIgnore { ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit) } diff --git a/modules/git/blob.go b/modules/git/blob.go index 4eef5f0e2a..8c5c275146 100644 --- a/modules/git/blob.go +++ b/modules/git/blob.go @@ -8,7 +8,6 @@ import ( "bufio" "bytes" "encoding/base64" - "fmt" "io" "forgejo.org/modules/log" @@ -173,43 +172,60 @@ func (b *Blob) GetBlobContent(limit int64) (string, error) { return string(buf), err } -type BlobTooLargeError struct { - Size, Limit int64 -} - -func (b BlobTooLargeError) Error() string { - return fmt.Sprintf("blob: content larger than limit (%d > %d)", b.Size, b.Limit) -} - -// GetContentBase64 Reads the content of the blob and returns it as base64 encoded string. -// Returns [BlobTooLargeError] if the (unencoded) content is larger than the limit. -func (b *Blob) GetContentBase64(limit int64) (string, error) { - if b.Size() > limit { - return "", BlobTooLargeError{ - Size: b.Size(), - Limit: limit, - } +// GetBlobLineCount gets line count of the blob +func (b *Blob) GetBlobLineCount() (int, error) { + reader, err := b.DataAsync() + if err != nil { + return 0, err } + defer reader.Close() + buf := make([]byte, 32*1024) + count := 1 + lineSep := []byte{'\n'} - rc, size, err := b.NewTruncatedReader(limit) + c, err := reader.Read(buf) + if c == 0 && err == io.EOF { + return 0, nil + } + for { + count += bytes.Count(buf[:c], lineSep) + switch { + case err == io.EOF: + return count, nil + case err != nil: + return count, err + } + c, err = reader.Read(buf) + } +} + +// GetBlobContentBase64 Reads the content of the blob with a base64 encode and returns the encoded string +func (b *Blob) GetBlobContentBase64() (string, error) { + dataRc, err := b.DataAsync() if err != nil { return "", err } - defer rc.Close() + defer dataRc.Close() - encoding := base64.StdEncoding - buf := bytes.NewBuffer(make([]byte, 0, encoding.EncodedLen(int(size)))) + pr, pw := io.Pipe() + encoder := base64.NewEncoder(base64.StdEncoding, pw) - encoder := base64.NewEncoder(encoding, buf) + go func() { + _, err := io.Copy(encoder, dataRc) + _ = encoder.Close() - if _, err := io.Copy(encoder, rc); err != nil { + if err != nil { + _ = pw.CloseWithError(err) + } else { + _ = pw.Close() + } + }() + + out, err := io.ReadAll(pr) + if err != nil { return "", err } - if err := encoder.Close(); err != nil { - return "", err - } - - return buf.String(), nil + return string(out), nil } // GuessContentType guesses the content type of the blob. @@ -220,7 +236,7 @@ func (b *Blob) GuessContentType() (typesniffer.SniffedType, error) { } defer r.Close() - return typesniffer.DetectContentTypeFromReader(r, b.Name()) + return typesniffer.DetectContentTypeFromReader(r) } // GetBlob finds the blob object in the repository. diff --git a/modules/git/blob_test.go b/modules/git/blob_test.go index a4b8033941..54115013d3 100644 --- a/modules/git/blob_test.go +++ b/modules/git/blob_test.go @@ -63,24 +63,6 @@ func TestBlob(t *testing.T) { require.Equal(t, "file2\n", r) }) - t.Run("GetContentBase64", func(t *testing.T) { - r, err := testBlob.GetContentBase64(100) - require.NoError(t, err) - require.Equal(t, "ZmlsZTIK", r) - - r, err = testBlob.GetContentBase64(-1) - require.ErrorAs(t, err, &BlobTooLargeError{}) - require.Empty(t, r) - - r, err = testBlob.GetContentBase64(4) - require.ErrorAs(t, err, &BlobTooLargeError{}) - require.Empty(t, r) - - r, err = testBlob.GetContentBase64(6) - require.NoError(t, err) - require.Equal(t, "ZmlsZTIK", r) - }) - t.Run("NewTruncatedReader", func(t *testing.T) { // read fewer than available rc, size, err := testBlob.NewTruncatedReader(100) diff --git a/modules/git/commit.go b/modules/git/commit.go index 4fb13ecd4f..96831e3ae4 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -16,6 +16,8 @@ import ( "forgejo.org/modules/log" "forgejo.org/modules/util" + + "github.com/go-git/go-git/v5/config" ) // Commit represents a git commit. @@ -27,8 +29,8 @@ type Commit struct { CommitMessage string Signature *ObjectSignature - Parents []ObjectID // ID strings - submodules map[string]Submodule // submodule indexed by path + Parents []ObjectID // ID strings + submoduleCache *ObjectCache } // Message returns the commit message. Same as retrieving CommitMessage directly. @@ -350,9 +352,71 @@ func (c *Commit) GetFileContent(filename string, limit int) (string, error) { return string(bytes), nil } +// GetSubModules get all the sub modules of current revision git tree +func (c *Commit) GetSubModules() (*ObjectCache, error) { + if c.submoduleCache != nil { + return c.submoduleCache, nil + } + + entry, err := c.GetTreeEntryByPath(".gitmodules") + if err != nil { + if _, ok := err.(ErrNotExist); ok { + return nil, nil + } + return nil, err + } + + content, err := entry.Blob().GetBlobContent(10 * 1024) + if err != nil { + return nil, err + } + + c.submoduleCache, err = parseSubmoduleContent([]byte(content)) + if err != nil { + return nil, err + } + return c.submoduleCache, nil +} + +func parseSubmoduleContent(bs []byte) (*ObjectCache, error) { + cfg := config.NewModules() + if err := cfg.Unmarshal(bs); err != nil { + return nil, err + } + submoduleCache := newObjectCache() + if len(cfg.Submodules) == 0 { + return nil, errors.New("no submodules found") + } + for _, subModule := range cfg.Submodules { + submoduleCache.Set(subModule.Path, subModule.URL) + } + + return submoduleCache, nil +} + +// GetSubModule returns the URL to the submodule according entryname +func (c *Commit) GetSubModule(entryname string) (string, error) { + modules, err := c.GetSubModules() + if err != nil { + return "", err + } + + if modules != nil { + module, has := modules.Get(entryname) + if has { + return module.(string), nil + } + } + return "", nil +} + // GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only') func (c *Commit) GetBranchName() (string, error) { - cmd := NewCommand(c.repo.Ctx, "name-rev", "--exclude", "refs/tags/*", "--name-only", "--no-undefined").AddDynamicArguments(c.ID.String()) + cmd := NewCommand(c.repo.Ctx, "name-rev") + if CheckGitVersionAtLeast("2.13.0") == nil { + cmd.AddArguments("--exclude", "refs/tags/*") + } + cmd.AddArguments("--name-only", "--no-undefined").AddDynamicArguments(c.ID.String()) data, _, err := cmd.RunStdString(&RunOpts{Dir: c.repo.Path}) if err != nil { // handle special case where git can not describe commit diff --git a/modules/git/commit_info.go b/modules/git/commit_info.go index 6511a1689a..8d9142d362 100644 --- a/modules/git/commit_info.go +++ b/modules/git/commit_info.go @@ -15,9 +15,9 @@ import ( // CommitInfo describes the first commit with the provided entry type CommitInfo struct { - Entry *TreeEntry - Commit *Commit - Submodule Submodule + Entry *TreeEntry + Commit *Commit + SubModuleFile *SubModuleFile } // GetCommitsInfo gets information of all commits that are corresponding to these entries @@ -71,18 +71,19 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath } // If the entry if a submodule add a submodule file for this - if entry.IsSubmodule() { + if entry.IsSubModule() { var fullPath string if len(treePath) > 0 { fullPath = treePath + "/" + entry.Name() } else { fullPath = entry.Name() } - submodule, err := commit.GetSubmodule(fullPath, entry) + subModuleURL, err := commit.GetSubModule(fullPath) if err != nil { return nil, nil, err } - commitsInfo[i].Submodule = submodule + subModuleFile := NewSubModuleFile(commitsInfo[i].Commit, subModuleURL, entry.ID.String()) + commitsInfo[i].SubModuleFile = subModuleFile } } diff --git a/modules/git/commit_test.go b/modules/git/commit_test.go index ee57a735e6..484827149c 100644 --- a/modules/git/commit_test.go +++ b/modules/git/commit_test.go @@ -436,3 +436,33 @@ func TestGetAllBranches(t *testing.T) { assert.Equal(t, []string{"branch1", "branch2", "master"}, branches) } + +func Test_parseSubmoduleContent(t *testing.T) { + submoduleFiles := []struct { + fileContent string + expectedPath string + expectedURL string + }{ + { + fileContent: `[submodule "jakarta-servlet"] +url = ../../ALP-pool/jakarta-servlet +path = jakarta-servlet`, + expectedPath: "jakarta-servlet", + expectedURL: "../../ALP-pool/jakarta-servlet", + }, + { + fileContent: `[submodule "jakarta-servlet"] +path = jakarta-servlet +url = ../../ALP-pool/jakarta-servlet`, + expectedPath: "jakarta-servlet", + expectedURL: "../../ALP-pool/jakarta-servlet", + }, + } + for _, kase := range submoduleFiles { + submodule, err := parseSubmoduleContent([]byte(kase.fileContent)) + require.NoError(t, err) + v, ok := submodule.Get(kase.expectedPath) + assert.True(t, ok) + assert.Equal(t, kase.expectedURL, v) + } +} diff --git a/modules/git/diff_compare.go b/modules/git/diff_compare.go deleted file mode 100644 index 0eba8cb541..0000000000 --- a/modules/git/diff_compare.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later -package git - -import ( - "bytes" - "context" - "fmt" - "os" - - "forgejo.org/modules/log" - "forgejo.org/modules/util" -) - -// CheckIfDiffDiffers returns if the diff of the newCommitID and -// oldCommitID with the merge base of the base branch has changed. -// -// Informally it checks if the following two diffs are exactly the same in their -// contents, thus ignoring different commit IDs, headers and messages: -// 1. git diff --merge-base baseReference newCommitID -// 2. git diff --merge-base baseReference oldCommitID -func (repo *Repository) CheckIfDiffDiffers(base, oldCommitID, newCommitID string, env []string) (hasChanged bool, err error) { - cmd := NewCommand(repo.Ctx, "diff", "--name-only", "-z").AddDynamicArguments(newCommitID, oldCommitID, base) - stdoutReader, stdoutWriter, err := os.Pipe() - if err != nil { - return false, fmt.Errorf("unable to open pipe for to run diff: %w", err) - } - - stderr := new(bytes.Buffer) - if err := cmd.Run(&RunOpts{ - Dir: repo.Path, - Stdout: stdoutWriter, - Stderr: stderr, - PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { - _ = stdoutWriter.Close() - defer func() { - _ = stdoutReader.Close() - }() - return util.IsEmptyReader(stdoutReader) - }, - }); err != nil { - if err == util.ErrNotEmpty { - return true, nil - } - err = ConcatenateError(err, stderr.String()) - - log.Error("Unable to run git diff on %s %s %s in %q: Error: %v", - newCommitID, oldCommitID, base, - repo.Path, - err) - - return false, fmt.Errorf("Unable to run git diff --name-only -z %s %s %s: %w", newCommitID, oldCommitID, base, err) - } - - return false, nil -} diff --git a/modules/git/diff_compare_test.go b/modules/git/diff_compare_test.go deleted file mode 100644 index 433497b5c4..0000000000 --- a/modules/git/diff_compare_test.go +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later -package git - -import ( - "bytes" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestCheckIfDiffDiffers(t *testing.T) { - tmpDir := t.TempDir() - - err := InitRepository(t.Context(), tmpDir, false, Sha1ObjectFormat.Name()) - require.NoError(t, err) - - gitRepo, err := openRepositoryWithDefaultContext(tmpDir) - require.NoError(t, err) - defer gitRepo.Close() - - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "main").Run(&RunOpts{Dir: tmpDir})) - - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("aaa"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "initial commit").Run(&RunOpts{Dir: tmpDir})) - - t.Run("Simple fast-forward", func(t *testing.T) { - // Check that A--B--C, where A is the base branch. - - t.Run("Different diff", func(t *testing.T) { - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "a-1", "main").Run(&RunOpts{Dir: tmpDir})) - - // B commit - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "a-2").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("ccc"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main", "a-1", "a-2", nil) - require.NoError(t, err) - assert.True(t, changed) - }) - - t.Run("Same diff", func(t *testing.T) { - // Because C is a empty commit, the diff does not differ relative to the - // base branch. - - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "a-3", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "a-4").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "--allow-empty", "-m", "No changes to the README").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main", "a-3", "a-4", nil) - require.NoError(t, err) - assert.False(t, changed) - }) - }) - - t.Run("Merge-base is base reference", func(t *testing.T) { - // B - // / - // A - // \ - // C - t.Run("Different diff", func(t *testing.T) { - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "b-1", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changed to the README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "b-2", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("ccc"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changed to the README").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main", "b-1", "b-2", nil) - require.NoError(t, err) - assert.True(t, changed) - }) - - t.Run("Same diff", func(t *testing.T) { - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "b-3", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changed to the README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "b-4", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changed to the README").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main", "b-3", "b-4", nil) - require.NoError(t, err) - assert.False(t, changed) - }) - }) - - t.Run("Merge-base is different", func(t *testing.T) { - // B - // / - // A--D - // \ - // C - // Where D is the base reference. - - // D commit, where A is `main`. - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "main-D", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "FUNFACT"), []byte("Smithy was the runner up to be Forgejo's name"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "FUNFACT").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Forgejo history").Run(&RunOpts{Dir: tmpDir})) - - t.Run("Different diff", func(t *testing.T) { - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "c-1", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "c-2", "main-D").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "FUNFACT"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "FUNFACT").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the funfact").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main-D", "c-1", "c-2", nil) - require.NoError(t, err) - assert.True(t, changed) - }) - - t.Run("Same diff", func(t *testing.T) { - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "c-3", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "c-4", "main-D").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main-D", "c-3", "c-4", nil) - require.NoError(t, err) - assert.False(t, changed) - }) - }) - - t.Run("Merge commit", func(t *testing.T) { - // B - // / - // A - D - // \ - // C - // - // From B, it merges D where E is the merge commit : - // B---E - // / / - // A---D - // \ - // C - - t.Run("Different diff", func(t *testing.T) { - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "d-1", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - // E commit - require.NoError(t, NewCommand(t.Context(), "merge", "--no-ff", "main-D").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "d-2", "main-D").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "FUNFACT"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "FUNFACT").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the funfact").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main-D", "d-1", "d-2", nil) - require.NoError(t, err) - assert.True(t, changed) - }) - - t.Run("Same diff", func(t *testing.T) { - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "d-3", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - // Merges D. - require.NoError(t, NewCommand(t.Context(), "merge", "--no-ff", "main-D").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "d-4", "main-D").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main-D", "d-3", "d-4", nil) - require.NoError(t, err) - assert.False(t, changed) - }) - }) - - t.Run("Non-typical rebase", func(t *testing.T) { - // B - // / - // A--D - // \ - // C - // Where D is the base reference. - // B was rebased onto D, which produced C. - // B and D made the same change to same file. - - // D commit. - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "main-D-2", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "FUNFACT"), []byte("Smithy was the runner up to be Forgejo's name"), 0o600)) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("ccc"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "FUNFACT", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Forgejo history").Run(&RunOpts{Dir: tmpDir})) - - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "e-1", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "CONTACT"), []byte("@example.com"), 0o600)) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("ccc"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README", "CONTACT").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the contact and README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "e-2").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "rebase", "main-D-2").Run(&RunOpts{Dir: tmpDir})) - - // The diff changed, because it no longers shows the change made to `README`. - changed, err := gitRepo.CheckIfDiffDiffers("main-D-2", "e-1", "e-2", nil) - require.NoError(t, err) - assert.False(t, changed) // This should be true. - }) - - t.Run("Directory", func(t *testing.T) { - // B - // / - // A - // \ - // C - t.Run("Same directory", func(t *testing.T) { - t.Run("Different diff", func(t *testing.T) { - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "f-1", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "docs"), 0o755)) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "docs", "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "docs/README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changed to the README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "f-2", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "docs"), 0o755)) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "docs", "README"), []byte("ccc"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "docs/README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changed to the README").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main", "f-1", "f-2", nil) - require.NoError(t, err) - assert.True(t, changed) - }) - - t.Run("Same diff", func(t *testing.T) { - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "f-3", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "docs"), 0o755)) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "docs", "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "docs/README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changed to the README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "f-4", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "docs"), 0o755)) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "docs", "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "docs/README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main", "f-3", "f-4", nil) - require.NoError(t, err) - assert.False(t, changed) - }) - }) - - t.Run("Different directory", func(t *testing.T) { - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "f-5", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "docs"), 0o755)) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "docs", "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "docs/README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "f-6", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "documentation"), 0o755)) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "documentation", "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "documentation/README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main", "f-5", "f-6", nil) - require.NoError(t, err) - assert.True(t, changed) - }) - - t.Run("Directory and file", func(t *testing.T) { - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "f-7", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "docs"), 0o755)) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "docs", "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "docs/README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "f-8", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README"), []byte("bbb"), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "README").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Changes to the README").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("main", "f-7", "f-8", nil) - require.NoError(t, err) - assert.True(t, changed) - }) - }) - - t.Run("Rebase", func(t *testing.T) { - // B - // / - // A--D - // \ - // C - // Where D is the base reference. - // B was rebased onto D, which produced C. - // B and D made different (non conflicting) changes to same file. - - // A commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "main-3", "main").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "REBASE"), bytes.Repeat([]byte{'b', 'b', 'b', '\n'}, 100), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "REBASE").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Rebasing is fun").Run(&RunOpts{Dir: tmpDir})) - - // B commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "g-1", "main-3").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "REBASE"), append(bytes.Repeat([]byte{'b', 'b', 'b', '\n'}, 100), 'a', 'a', 'a'), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "REBASE").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Rebasing is fun").Run(&RunOpts{Dir: tmpDir})) - - // D commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "g-2", "main-3").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "REBASE"), append([]byte{'a', 'a', 'a'}, bytes.Repeat([]byte{'b', 'b', 'b', '\n'}, 99)...), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "REBASE").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Rebasing is fun").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "g-3", "g-1").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "rebase", "g-2").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("g-2", "g-1", "g-3", nil) - require.NoError(t, err) - assert.True(t, changed) - }) - - t.Run("Rebasing change not shown", func(t *testing.T) { - // B - // / - // A--D - // \ - // C - // Where D is the base reference. - // B was rebased onto D, which produced C. - // B and D made different (non conflicting) changes to same file. - - // A commit - require.NoError(t, NewCommand(t.Context(), "switch", "--orphan", "main-4").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "A"), 0o700)) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "A", "a"), bytes.Repeat([]byte{'A', 'A', 'A', '\n'}, 100), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "A/a").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Just wondering").Run(&RunOpts{Dir: tmpDir})) - - // B commit - // Changes last line. - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "h-1").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "A", "a"), append(bytes.Repeat([]byte{'A', 'A', 'A', '\n'}, 99), 'B', 'B', 'B', '\n'), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "A/a").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Just wondering").Run(&RunOpts{Dir: tmpDir})) - - // D commit - // Changes first line. - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "h-2", "main-4").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "A", "a"), append([]byte{'B', 'B', 'B', '\n'}, bytes.Repeat([]byte{'A', 'A', 'A', '\n'}, 99)...), 0o600)) - require.NoError(t, NewCommand(t.Context(), "add", "A/a").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "commit", "-m", "Just wondering").Run(&RunOpts{Dir: tmpDir})) - - // C commit - require.NoError(t, NewCommand(t.Context(), "switch", "-c", "h-3").Run(&RunOpts{Dir: tmpDir})) - require.NoError(t, NewCommand(t.Context(), "rebase", "h-2").Run(&RunOpts{Dir: tmpDir})) - - changed, err := gitRepo.CheckIfDiffDiffers("h-2", "h-1", "h-3", nil) - require.NoError(t, err) - - assert.False(t, changed) - }) -} diff --git a/modules/git/git.go b/modules/git/git.go index 851b090b53..1dfd0b5134 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -23,7 +23,7 @@ import ( ) // RequiredVersion is the minimum Git version required -const RequiredVersion = "2.34.1" +const RequiredVersion = "2.0.0" var ( // GitExecutable is the command name of git @@ -33,6 +33,7 @@ var ( // DefaultContext is the default context to run git commands in, must be initialized by git.InitXxx DefaultContext context.Context + SupportProcReceive bool // >= 2.29 SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an โ€˜experimental curiosityโ€™ InvertedGitFlushEnv bool // 2.43.1 SupportCheckAttrOnBare bool // >= 2.40 @@ -112,7 +113,7 @@ func VersionInfo() string { format := "%s" args := []any{GitVersion.Original()} // Since git wire protocol has been released from git v2.18 - if setting.Git.EnableAutoGitWireProtocol { + if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { format += ", Wire Protocol %s Enabled" args = append(args, "Version 2") // for focus color } @@ -171,13 +172,16 @@ func InitFull(ctx context.Context) (err error) { _ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg")) } - if setting.Git.EnableAutoGitWireProtocol { + // Since git wire protocol has been released from git v2.18 + if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2") } // Explicitly disable credential helper, otherwise Git credentials might leak - globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") - + if CheckGitVersionAtLeast("2.9") == nil { + globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") + } + SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil SupportCheckAttrOnBare = CheckGitVersionAtLeast("2.40") == nil if SupportHashSha256 { @@ -191,6 +195,9 @@ func InitFull(ctx context.Context) (err error) { SupportGrepMaxCount = CheckGitVersionAtLeast("2.38") == nil if setting.LFS.StartServer { + if CheckGitVersionAtLeast("2.1.2") != nil { + return errors.New("LFS server support requires Git >= 2.1.2") + } globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") } @@ -227,28 +234,38 @@ func syncGitConfig() (err error) { } } - // Set git some configurations - these must be set to these values for forgejo to work correctly + // Set git some configurations - these must be set to these values for gitea to work correctly if err := configSet("core.quotePath", "false"); err != nil { return err } - if err := configSet("receive.advertisePushOptions", "true"); err != nil { - return err + if CheckGitVersionAtLeast("2.10") == nil { + if err := configSet("receive.advertisePushOptions", "true"); err != nil { + return err + } } - if err := configSet("core.commitGraph", "true"); err != nil { - return err - } - if err := configSet("gc.writeCommitGraph", "true"); err != nil { - return err - } - if err := configSet("fetch.writeCommitGraph", "true"); err != nil { - return err + if CheckGitVersionAtLeast("2.18") == nil { + if err := configSet("core.commitGraph", "true"); err != nil { + return err + } + if err := configSet("gc.writeCommitGraph", "true"); err != nil { + return err + } + if err := configSet("fetch.writeCommitGraph", "true"); err != nil { + return err + } } - // set support for AGit flow - if err := configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil { - return err + if SupportProcReceive { + // set support for AGit flow + if err := configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil { + return err + } + } else { + if err := configUnsetAll("receive.procReceiveRefs", "refs/for"); err != nil { + return err + } } // Due to CVE-2022-24765, git now denies access to git directories which are not owned by current user @@ -267,6 +284,11 @@ func syncGitConfig() (err error) { switch setting.Repository.Signing.Format { case "ssh": + // First do a git version check. + if CheckGitVersionAtLeast("2.34.0") != nil { + return errors.New("ssh signing requires Git >= 2.34.0") + } + // Get the ssh-keygen binary that Git will use. // This can be overridden in app.ini in [git.config] section, so we must // query this information. @@ -303,7 +325,8 @@ func syncGitConfig() (err error) { } } - if !setting.Git.DisablePartialClone { + // By default partial clones are disabled, enable them from git v2.22 + if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil { if err = configSet("uploadpack.allowfilter", "true"); err != nil { return err } diff --git a/modules/git/git_test.go b/modules/git/git_test.go index 38d4db169c..01200dba68 100644 --- a/modules/git/git_test.go +++ b/modules/git/git_test.go @@ -14,6 +14,7 @@ import ( "forgejo.org/modules/test" "forgejo.org/modules/util" + "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -104,6 +105,10 @@ func TestSyncConfigGPGFormat(t *testing.T) { }) t.Run("SSH format", func(t *testing.T) { + if CheckGitVersionAtLeast("2.34.0") != nil { + t.SkipNow() + } + r, err := os.OpenRoot(t.TempDir()) require.NoError(t, err) f, err := r.OpenFile("ssh-keygen", os.O_CREATE|os.O_TRUNC, 0o700) @@ -116,6 +121,13 @@ func TestSyncConfigGPGFormat(t *testing.T) { assert.True(t, gitConfigContains("[gpg]")) assert.True(t, gitConfigContains("format = ssh")) + t.Run("Old version", func(t *testing.T) { + oldVersion, err := version.NewVersion("2.33.0") + require.NoError(t, err) + defer test.MockVariableValue(&GitVersion, oldVersion)() + require.ErrorContains(t, syncGitConfig(), "ssh signing requires Git >= 2.34.0") + }) + t.Run("No ssh-keygen binary", func(t *testing.T) { require.NoError(t, r.Remove("ssh-keygen")) require.ErrorContains(t, syncGitConfig(), "git signing requires a ssh-keygen binary") diff --git a/modules/git/grep.go b/modules/git/grep.go index b5471b8f6c..3703b13660 100644 --- a/modules/git/grep.go +++ b/modules/git/grep.go @@ -36,7 +36,6 @@ const ( RegExpGrepMode ) -// llu:TrKeysSuffix search. var GrepSearchOptions = [3]string{"exact", "union", "regexp"} type GrepOptions struct { diff --git a/modules/git/parse.go b/modules/git/parse.go index c7b84d7198..6bc32057a7 100644 --- a/modules/git/parse.go +++ b/modules/git/parse.go @@ -10,6 +10,8 @@ import ( "io" "strconv" "strings" + + "forgejo.org/modules/log" ) // ParseTreeEntries parses the output of a `git ls-tree -l` command. @@ -53,9 +55,19 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) { entry.sized = true } - entry.entryMode, err = parseMode(string(entryMode)) - if err != nil { - return nil, err + switch string(entryMode) { + case "100644": + entry.entryMode = EntryModeBlob + case "100755": + entry.entryMode = EntryModeExec + case "120000": + entry.entryMode = EntryModeSymlink + case "160000": + entry.entryMode = EntryModeCommit + case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons + entry.entryMode = EntryModeTree + default: + return nil, fmt.Errorf("unknown type: %v", string(entryMode)) } entry.ID, err = NewIDFromString(string(entryObjectID)) @@ -96,10 +108,23 @@ loop: sz -= int64(count) entry := new(TreeEntry) entry.ptree = ptree - entry.entryMode, err = parseMode(string(mode)) - if err != nil { - return nil, err + + switch string(mode) { + case "100644": + entry.entryMode = EntryModeBlob + case "100755": + entry.entryMode = EntryModeExec + case "120000": + entry.entryMode = EntryModeSymlink + case "160000": + entry.entryMode = EntryModeCommit + case "40000", "40755": // git uses 40000 for tree object, but some users may get 40755 for unknown reasons + entry.entryMode = EntryModeTree + default: + log.Debug("Unknown mode: %v", string(mode)) + return nil, fmt.Errorf("unknown mode: %v", string(mode)) } + entry.ID = objectFormat.MustID(sha) entry.name = string(fname) entries = append(entries, entry) @@ -110,31 +135,3 @@ loop: return entries, nil } - -// Parse the file mode, we cannot hardcode the modes that we expect for -// a variety of reasons (that is not known to us) the permissions bits -// of files can vary, usually the result because of tooling that uses Git in -// a funny way. So we have to parse the mode as a integer and do bit tricks. -func parseMode(modeStr string) (EntryMode, error) { - mode, err := strconv.ParseUint(modeStr, 8, 64) - if err != nil { - return 0, fmt.Errorf("cannot parse mode: %v", err) - } - - switch mode & 0o170000 { - case 0o040000: - return EntryModeTree, nil - case 0o120000: - return EntryModeSymlink, nil - case 0o160000: - return EntryModeCommit, nil - case 0o100000: - // Check for the permission bit on the owner. - if mode&0o100 == 0o100 { - return EntryModeExec, nil - } - return EntryModeBlob, nil - } - - return 0, fmt.Errorf("unknown mode: %o", mode) -} diff --git a/modules/git/parse_test.go b/modules/git/parse_test.go index 502adab4da..03f359f6c1 100644 --- a/modules/git/parse_test.go +++ b/modules/git/parse_test.go @@ -101,38 +101,3 @@ func TestParseTreeEntriesInvalid(t *testing.T) { require.Error(t, err) assert.Empty(t, entries) } - -func TestParseMode(t *testing.T) { - ok := func(t *testing.T, mode string, entry EntryMode) { - t.Helper() - actualEntry, err := parseMode(mode) - require.NoError(t, err) - assert.Equal(t, entry, actualEntry) - } - - fail := func(t *testing.T, mode string) { - t.Helper() - entry, err := parseMode(mode) - require.Error(t, err) - assert.Zero(t, entry) - } - - ok(t, "100644", EntryModeBlob) - ok(t, "100755", EntryModeExec) - ok(t, "100754", EntryModeExec) - ok(t, "100700", EntryModeExec) - ok(t, "100744", EntryModeExec) - ok(t, "120000", EntryModeSymlink) - ok(t, "120644", EntryModeSymlink) - ok(t, "160000", EntryModeCommit) - ok(t, "160644", EntryModeCommit) - ok(t, "040000", EntryModeTree) - ok(t, "040755", EntryModeTree) - ok(t, "040775", EntryModeTree) - ok(t, "040754", EntryModeTree) - - fail(t, "not-a-number") - fail(t, "000000") - fail(t, "400000") - fail(t, "111111") -} diff --git a/modules/git/pipeline/revlist.go b/modules/git/pipeline/revlist.go index 1ee8921854..f39b7113bb 100644 --- a/modules/git/pipeline/revlist.go +++ b/modules/git/pipeline/revlist.go @@ -16,6 +16,26 @@ import ( "forgejo.org/modules/log" ) +// RevListAllObjects runs rev-list --objects --all and writes to a pipewriter +func RevListAllObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.WaitGroup, basePath string, errChan chan<- error) { + defer wg.Done() + defer revListWriter.Close() + + stderr := new(bytes.Buffer) + var errbuf strings.Builder + cmd := git.NewCommand(ctx, "rev-list", "--objects", "--all") + if err := cmd.Run(&git.RunOpts{ + Dir: basePath, + Stdout: revListWriter, + Stderr: stderr, + }); err != nil { + log.Error("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String()) + err = fmt.Errorf("git rev-list --objects --all [%s]: %w - %s", basePath, err, errbuf.String()) + _ = revListWriter.CloseWithError(err) + errChan <- err + } +} + // RevListObjects run rev-list --objects from headSHA to baseSHA func RevListObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath, headSHA, baseSHA string, errChan chan<- error) { defer wg.Done() diff --git a/modules/git/pushoptions/pushoptions.go b/modules/git/pushoptions/pushoptions.go index e96ba0a339..9709a8be79 100644 --- a/modules/git/pushoptions/pushoptions.go +++ b/modules/git/pushoptions/pushoptions.go @@ -4,7 +4,6 @@ package pushoptions import ( - "encoding/base64" "fmt" "os" "strconv" @@ -110,22 +109,5 @@ func (o gitPushOptions) GetBool(key Key, def bool) bool { func (o gitPushOptions) GetString(key Key) (string, bool) { val, ok := o[string(key)] - if !ok { - return "", false - } - - // If the value is prefixed with `{base64}` then everything after that is very - // likely to be encoded via base64. - base64Value, found := strings.CutPrefix(val, "{base64}") - if !found { - return val, true - } - - value, err := base64.StdEncoding.DecodeString(base64Value) - if err != nil { - // Not valid base64? Return the original value. - return val, true - } - - return string(value), true + return val, ok } diff --git a/modules/git/pushoptions/pushoptions_test.go b/modules/git/pushoptions/pushoptions_test.go index d7c50649d0..1cb36d9d1e 100644 --- a/modules/git/pushoptions/pushoptions_test.go +++ b/modules/git/pushoptions/pushoptions_test.go @@ -4,7 +4,6 @@ package pushoptions import ( - "encoding/base64" "fmt" "testing" @@ -93,23 +92,6 @@ func TestParse(t *testing.T) { assert.False(t, options.Parse("unknown=value")) assert.True(t, options.Empty()) }) - - t.Run("Base64 values", func(t *testing.T) { - options := New() - - description := `I contain -a -line` - assert.True(t, options.Parse(fmt.Sprintf("%s={base64}%s", AgitDescription, base64.StdEncoding.EncodeToString([]byte(description))))) - val, ok := options.GetString(AgitDescription) - assert.True(t, ok) - assert.Equal(t, description, val) - - assert.True(t, options.Parse(fmt.Sprintf("%s={base64}fooled you", AgitTitle))) - val, ok = options.GetString(AgitTitle) - assert.True(t, ok) - assert.Equal(t, "{base64}fooled you", val) - }) } func TestReadEnv(t *testing.T) { diff --git a/modules/git/remote.go b/modules/git/remote.go index 83a02fe2be..fb66d76ff0 100644 --- a/modules/git/remote.go +++ b/modules/git/remote.go @@ -12,7 +12,14 @@ import ( // GetRemoteAddress returns remote url of git repository in the repoPath with special remote name func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (string, error) { - result, _, err := NewCommand(ctx, "remote", "get-url").AddDynamicArguments(remoteName).RunStdString(&RunOpts{Dir: repoPath}) + var cmd *Command + if CheckGitVersionAtLeast("2.7") == nil { + cmd = NewCommand(ctx, "remote", "get-url").AddDynamicArguments(remoteName) + } else { + cmd = NewCommand(ctx, "config", "--get").AddDynamicArguments("remote." + remoteName + ".url") + } + + result, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath}) if err != nil { return "", err } diff --git a/modules/git/repo.go b/modules/git/repo.go index 4f2b05bca5..23e9337615 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -18,7 +18,6 @@ import ( "strings" "time" - "forgejo.org/modules/log" "forgejo.org/modules/proxy" "forgejo.org/modules/setting" "forgejo.org/modules/util" @@ -161,89 +160,24 @@ func CloneWithArgs(ctx context.Context, args TrustedCmdArgs, from, to string, op if len(opts.Branch) > 0 { cmd.AddArguments("-b").AddDynamicArguments(opts.Branch) } + cmd.AddDashesAndList(from, to) - envs := os.Environ() - parsedFromURL, err := url.Parse(from) - if err == nil { - envs = proxy.EnvWithProxy(parsedFromURL) - } - - fromURL := from - sanitizedFrom := from - - // If the clone URL has credentials, sanitize it and store the credentials in - // a temporary file that git will access. if strings.Contains(from, "://") && strings.Contains(from, "@") { - sanitizedFrom = util.SanitizeCredentialURLs(from) - if parsedFromURL != nil { - if pwd, has := parsedFromURL.User.Password(); has { - parsedFromURL.User = url.User(parsedFromURL.User.Username()) - fromURL = parsedFromURL.String() - - credentialsFile, err := os.CreateTemp(os.TempDir(), "forgejo-clone-credentials") - if err != nil { - return err - } - credentialsPath := credentialsFile.Name() - - defer func() { - _ = credentialsFile.Close() - if err := util.Remove(credentialsPath); err != nil { - log.Warn("Unable to remove temporary file %q: %v", credentialsPath, err) - } - }() - - // Make it read-write. - if err := credentialsFile.Chmod(0o600); err != nil { - return err - } - - // Write the password. - if _, err := fmt.Fprint(credentialsFile, pwd); err != nil { - return err - } - - askpassFile, err := os.CreateTemp(os.TempDir(), "forgejo-askpass") - if err != nil { - return err - } - askpassPath := askpassFile.Name() - - defer func() { - _ = askpassFile.Close() - if err := util.Remove(askpassPath); err != nil { - log.Warn("Unable to remove temporary file %q: %v", askpassPath, err) - } - }() - - // Make it executable. - if err := askpassFile.Chmod(0o700); err != nil { - return err - } - - // Write the password script. - if _, err := fmt.Fprintf(askpassFile, "exec cat %s", credentialsPath); err != nil { - return err - } - - // Close it, so that Git can use it and no busy errors arise. - _ = askpassFile.Close() - _ = credentialsFile.Close() - - // Use environments to specify that git should ask for credentials, this - // takes precedences over anything else https://git-scm.com/docs/gitcredentials#_requesting_credentials. - envs = append(envs, "GIT_ASKPASS="+askpassPath) - } - } + cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, util.SanitizeCredentialURLs(from), to, opts.Shared, opts.Mirror, opts.Depth)) + } else { + cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, from, to, opts.Shared, opts.Mirror, opts.Depth)) } - cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, sanitizedFrom, to, opts.Shared, opts.Mirror, opts.Depth)) - cmd.AddDashesAndList(fromURL, to) - if opts.Timeout <= 0 { opts.Timeout = -1 } + envs := os.Environ() + u, err := url.Parse(from) + if err == nil { + envs = proxy.EnvWithProxy(u) + } + stderr := new(bytes.Buffer) if err = cmd.Run(&RunOpts{ Timeout: opts.Timeout, diff --git a/modules/git/repo_attribute_test.go b/modules/git/repo_attribute_test.go index 3d2c845fa0..c69382e245 100644 --- a/modules/git/repo_attribute_test.go +++ b/modules/git/repo_attribute_test.go @@ -5,6 +5,7 @@ package git import ( "context" + "fmt" "io" "io/fs" "os" @@ -196,7 +197,7 @@ func TestGitAttributeCheckerError(t *testing.T) { path := t.TempDir() // we can't use unittest.CopyDir because of an import cycle (git.Init in unittest) - require.NoError(t, os.CopyFS(path, os.DirFS(filepath.Join(testReposDir, "language_stats_repo")))) + require.NoError(t, CopyFS(path, os.DirFS(filepath.Join(testReposDir, "language_stats_repo")))) gitRepo, err := openRepositoryWithDefaultContext(path) require.NoError(t, err) @@ -323,3 +324,32 @@ func TestGitAttributeCheckerError(t *testing.T) { require.ErrorIs(t, err, fs.ErrClosed) }) } + +// CopyFS is adapted from https://github.com/golang/go/issues/62484 +// which should be available with go1.23 +func CopyFS(dir string, fsys fs.FS) error { + return fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, _ error) error { + targ := filepath.Join(dir, filepath.FromSlash(path)) + if d.IsDir() { + return os.MkdirAll(targ, 0o777) + } + r, err := fsys.Open(path) + if err != nil { + return err + } + defer r.Close() + info, err := r.Stat() + if err != nil { + return err + } + w, err := os.OpenFile(targ, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o666|info.Mode()&0o777) + if err != nil { + return err + } + if _, err := io.Copy(w, r); err != nil { + w.Close() + return fmt.Errorf("copying %s: %v", path, err) + } + return w.Close() + }) +} diff --git a/modules/git/repo_blame.go b/modules/git/repo_blame.go index d812354af5..139cdd7be9 100644 --- a/modules/git/repo_blame.go +++ b/modules/git/repo_blame.go @@ -4,46 +4,20 @@ package git import ( - "errors" "fmt" - "regexp" -) - -var ( - ErrBlameFileDoesNotExist = errors.New("the blamed file does not exist") - ErrBlameFileNotEnoughLines = errors.New("the blamed file has not enough lines") - - notEnoughLinesRe = regexp.MustCompile(`^fatal: file .+ has only \d+ lines?\n$`) ) // LineBlame returns the latest commit at the given line -func (repo *Repository) LineBlame(revision, file string, line uint64) (*Commit, error) { - res, _, gitErr := NewCommand(repo.Ctx, "blame"). +func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) { + res, _, err := NewCommand(repo.Ctx, "blame"). AddOptionFormat("-L %d,%d", line, line). AddOptionValues("-p", revision). - AddDashesAndList(file).RunStdString(&RunOpts{Dir: repo.Path}) - if gitErr != nil { - stdErr := gitErr.Stderr() - - if stdErr == fmt.Sprintf("fatal: no such path %s in %s\n", file, revision) { - return nil, ErrBlameFileDoesNotExist - } - if notEnoughLinesRe.MatchString(stdErr) { - return nil, ErrBlameFileNotEnoughLines - } - - return nil, gitErr - } - - objectFormat, err := repo.GetObjectFormat() + AddDashesAndList(file).RunStdString(&RunOpts{Dir: path}) if err != nil { return nil, err } - - objectIDLen := objectFormat.FullLength() - if len(res) < objectIDLen { - return nil, fmt.Errorf("output of blame is invalid, cannot contain commit ID: %s", res) + if len(res) < 40 { + return nil, fmt.Errorf("invalid result of blame: %s", res) } - - return repo.GetCommit(res[:objectIDLen]) + return repo.GetCommit(res[:40]) } diff --git a/modules/git/repo_blame_test.go b/modules/git/repo_blame_test.go deleted file mode 100644 index 126b95386d..0000000000 --- a/modules/git/repo_blame_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package git - -import ( - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestLineBlame(t *testing.T) { - t.Run("SHA1", func(t *testing.T) { - repo, err := OpenRepository(t.Context(), filepath.Join(testReposDir, "repo1_bare")) - require.NoError(t, err) - defer repo.Close() - - commit, err := repo.LineBlame("HEAD", "foo/link_short", 1) - require.NoError(t, err) - assert.Equal(t, "37991dec2c8e592043f47155ce4808d4580f9123", commit.ID.String()) - - commit, err = repo.LineBlame("HEAD", "foo/link_short", 512) - require.ErrorIs(t, err, ErrBlameFileNotEnoughLines) - assert.Nil(t, commit) - - commit, err = repo.LineBlame("HEAD", "non-existent/path", 512) - require.ErrorIs(t, err, ErrBlameFileDoesNotExist) - assert.Nil(t, commit) - }) - - t.Run("SHA256", func(t *testing.T) { - skipIfSHA256NotSupported(t) - - repo, err := OpenRepository(t.Context(), filepath.Join(testReposDir, "repo1_bare_sha256")) - require.NoError(t, err) - defer repo.Close() - - commit, err := repo.LineBlame("HEAD", "foo/link_short", 1) - require.NoError(t, err) - assert.Equal(t, "6aae864a3d1d0d6a5be0cc64028c1e7021e2632b031fd8eb82afc5a283d1c3d1", commit.ID.String()) - - commit, err = repo.LineBlame("HEAD", "foo/link_short", 512) - require.ErrorIs(t, err, ErrBlameFileNotEnoughLines) - assert.Nil(t, commit) - - commit, err = repo.LineBlame("HEAD", "non-existent/path", 512) - require.ErrorIs(t, err, ErrBlameFileDoesNotExist) - assert.Nil(t, commit) - }) -} diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go index 1e38bf2946..3a9aa3e4e6 100644 --- a/modules/git/repo_branch.go +++ b/modules/git/repo_branch.go @@ -19,9 +19,15 @@ import ( // BranchPrefix base dir of the branch information file store on git const BranchPrefix = "refs/heads/" +// IsReferenceExist returns true if given reference exists in the repository. +func IsReferenceExist(ctx context.Context, repoPath, name string) bool { + _, _, err := NewCommand(ctx, "show-ref", "--verify").AddDashesAndList(name).RunStdString(&RunOpts{Dir: repoPath}) + return err == nil +} + // IsBranchExist returns true if given branch exists in the repository. func IsBranchExist(ctx context.Context, repoPath, name string) bool { - return NewCommand(ctx, "show-ref", "--verify", "--quiet").AddDashesAndList(BranchPrefix+name).Run(&RunOpts{Dir: repoPath}) == nil + return IsReferenceExist(ctx, repoPath, BranchPrefix+name) } // Branch represents a Git branch. diff --git a/modules/git/repo_branch_test.go b/modules/git/repo_branch_test.go index e61ea6f5d7..1e0fea7cd4 100644 --- a/modules/git/repo_branch_test.go +++ b/modules/git/repo_branch_test.go @@ -1,5 +1,4 @@ // Copyright 2018 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package git @@ -196,17 +195,3 @@ func TestRepository_IsReferenceExist(t *testing.T) { }) } } - -func TestIsBranchExist(t *testing.T) { - repo1Path := filepath.Join(testReposDir, "repo1_bare") - - assert.True(t, IsBranchExist(t.Context(), repo1Path, "branch1")) - assert.True(t, IsBranchExist(t.Context(), repo1Path, "branch2")) - assert.True(t, IsBranchExist(t.Context(), repo1Path, "master")) - - assert.False(t, IsBranchExist(t.Context(), repo1Path, "HEAD")) - assert.False(t, IsBranchExist(t.Context(), repo1Path, "153f451b9ee7fa1da317ab17a127e9fd9d384310")) - assert.False(t, IsBranchExist(t.Context(), repo1Path, "153f451b9ee7fa1da317ab17a127e9fd9d384310")) - assert.False(t, IsBranchExist(t.Context(), repo1Path, "signed-tag")) - assert.False(t, IsBranchExist(t.Context(), repo1Path, "test")) -} diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index a650e597d2..4c8516f828 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -443,43 +443,53 @@ func (repo *Repository) getCommitsBeforeLimit(id ObjectID, num int) ([]*Commit, } func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) { - command := NewCommand(repo.Ctx, "for-each-ref", "--format=%(refname:strip=2)").AddOptionValues("--contains", commit.ID.String(), BranchPrefix) + if CheckGitVersionAtLeast("2.7.0") == nil { + command := NewCommand(repo.Ctx, "for-each-ref", "--format=%(refname:strip=2)").AddOptionValues("--contains", commit.ID.String(), BranchPrefix) - if limit != -1 { - command = command.AddOptionFormat("--count=%d", limit) + if limit != -1 { + command = command.AddOptionFormat("--count=%d", limit) + } + + stdout, _, err := command.RunStdString(&RunOpts{Dir: repo.Path}) + if err != nil { + return nil, err + } + + branches := strings.Fields(stdout) + return branches, nil } - stdout, _, err := command.RunStdString(&RunOpts{Dir: repo.Path}) + stdout, _, err := NewCommand(repo.Ctx, "branch").AddOptionValues("--contains", commit.ID.String()).RunStdString(&RunOpts{Dir: repo.Path}) if err != nil { return nil, err } - branches := strings.Fields(stdout) + refs := strings.Split(stdout, "\n") + + var max int + if len(refs) > limit { + max = limit + } else { + max = len(refs) - 1 + } + + branches := make([]string, max) + for i, ref := range refs[:max] { + parts := strings.Fields(ref) + + branches[i] = parts[len(parts)-1] + } return branches, nil } -// GetCommitsFromIDs get commits from commit IDs. If ignoreExistence is -// specified, then commits that no longer exists are still returned but -// without any information except the ID. -func (repo *Repository) GetCommitsFromIDs(commitIDs []string, ignoreExistence bool) []*Commit { +// GetCommitsFromIDs get commits from commit IDs +func (repo *Repository) GetCommitsFromIDs(commitIDs []string) []*Commit { commits := make([]*Commit, 0, len(commitIDs)) for _, commitID := range commitIDs { commit, err := repo.GetCommit(commitID) if err == nil && commit != nil { commits = append(commits, commit) - } else if ignoreExistence && IsErrNotExist(err) { - // It's entirely possible the commit no longer exists, we only care - // about the status and verification. Verification is no longer possible, - // but getting the status is still possible with just the ID. We do have - // to assumme the commitID is not shortened, we cannot recover the full - // commitID. - id, err := NewIDFromString(commitID) - if err == nil { - commits = append(commits, &Commit{ - ID: id, - }) - } } } diff --git a/modules/git/repo_commit_test.go b/modules/git/repo_commit_test.go index 5932f31e3c..53760b208e 100644 --- a/modules/git/repo_commit_test.go +++ b/modules/git/repo_commit_test.go @@ -199,40 +199,3 @@ func TestCommitsByFileAndRange(t *testing.T) { assert.Len(t, commits, testCase.ExpectedCommitCount, "file: '%s', page: %d", testCase.File, testCase.Page) } } - -func TestGetCommitsFromIDs(t *testing.T) { - bareRepo1, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare")) - require.NoError(t, err) - - commitIDs := []string{"2839944139e0de9737a044f78b0e4b40d989a9e3", "2839944139e0de9737a044f78b0e4b40d989a9e4"} - - t.Run("Normal", func(t *testing.T) { - commits := bareRepo1.GetCommitsFromIDs(commitIDs, false) - if assert.Len(t, commits, 1) { - assert.Equal(t, "2839944139e0de9737a044f78b0e4b40d989a9e3", commits[0].ID.String()) - assert.Equal(t, "Example User", commits[0].Author.Name) - } - }) - - t.Run("Ignore existence", func(t *testing.T) { - commits := bareRepo1.GetCommitsFromIDs(commitIDs, true) - if assert.Len(t, commits, 2) { - assert.Equal(t, "2839944139e0de9737a044f78b0e4b40d989a9e3", commits[0].ID.String()) - assert.Equal(t, "Example User", commits[0].Author.Name) - - assert.Equal(t, "2839944139e0de9737a044f78b0e4b40d989a9e4", commits[1].ID.String()) - assert.Nil(t, commits[1].Author) - } - }) - - t.Run("Not full commit ID", func(t *testing.T) { - commits := bareRepo1.GetCommitsFromIDs(append(commitIDs, "abba"), true) - if assert.Len(t, commits, 2) { - assert.Equal(t, "2839944139e0de9737a044f78b0e4b40d989a9e3", commits[0].ID.String()) - assert.Equal(t, "Example User", commits[0].Author.Name) - - assert.Equal(t, "2839944139e0de9737a044f78b0e4b40d989a9e4", commits[1].ID.String()) - assert.Nil(t, commits[1].Author) - } - }) -} diff --git a/modules/git/repo_commitgraph.go b/modules/git/repo_commitgraph.go index c3647bd894..492438be37 100644 --- a/modules/git/repo_commitgraph.go +++ b/modules/git/repo_commitgraph.go @@ -11,8 +11,10 @@ import ( // WriteCommitGraph write commit graph to speed up repo access // this requires git v2.18 to be installed func WriteCommitGraph(ctx context.Context, repoPath string) error { - if _, _, err := NewCommand(ctx, "commit-graph", "write").RunStdString(&RunOpts{Dir: repoPath}); err != nil { - return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err) + if CheckGitVersionAtLeast("2.18") == nil { + if _, _, err := NewCommand(ctx, "commit-graph", "write").RunStdString(&RunOpts{Dir: repoPath}); err != nil { + return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err) + } } return nil } diff --git a/modules/git/repo_compare.go b/modules/git/repo_compare.go index 94f1911c4a..373b5befb5 100644 --- a/modules/git/repo_compare.go +++ b/modules/git/repo_compare.go @@ -183,17 +183,6 @@ func (repo *Repository) GetDiffShortStat(base, head string) (numFiles, totalAddi return numFiles, totalAdditions, totalDeletions, err } -// GetCommitStat returns the number of files, total additions and total deletions the commit has. -func (repo *Repository) GetCommitShortStat(commitID string) (numFiles, totalAdditions, totalDeletions int, err error) { - cmd := NewCommand(repo.Ctx, "diff-tree", "--shortstat", "--no-commit-id", "--root").AddDynamicArguments(commitID) - stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path}) - if err != nil { - return 0, 0, 0, err - } - - return parseDiffStat(stdout) -} - // GetDiffShortStat counts number of changed files, number of additions and deletions func GetDiffShortStat(ctx context.Context, repoPath string, trustedArgs TrustedCmdArgs, dynamicArgs ...string) (numFiles, totalAdditions, totalDeletions int, err error) { // Now if we call: diff --git a/modules/git/repo_compare_test.go b/modules/git/repo_compare_test.go index b1ebdf6177..86bd6855a7 100644 --- a/modules/git/repo_compare_test.go +++ b/modules/git/repo_compare_test.go @@ -1,5 +1,4 @@ // Copyright 2018 The Gitea Authors. All rights reserved. -// Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package git @@ -163,83 +162,3 @@ func TestGetCommitFilesChanged(t *testing.T) { assert.ElementsMatch(t, tc.files, changedFiles) } } - -func TestGetCommitShortStat(t *testing.T) { - t.Run("repo1_bare", func(t *testing.T) { - repo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare")) - if err != nil { - require.NoError(t, err) - return - } - defer repo.Close() - - numFiles, totalAddition, totalDeletions, err := repo.GetCommitShortStat("ce064814f4a0d337b333e646ece456cd39fab612") - require.NoError(t, err) - assert.Equal(t, 0, numFiles) - assert.Equal(t, 0, totalAddition) - assert.Equal(t, 0, totalDeletions) - - numFiles, totalAddition, totalDeletions, err = repo.GetCommitShortStat("feaf4ba6bc635fec442f46ddd4512416ec43c2c2") - require.NoError(t, err) - assert.Equal(t, 0, numFiles) - assert.Equal(t, 0, totalAddition) - assert.Equal(t, 0, totalDeletions) - - numFiles, totalAddition, totalDeletions, err = repo.GetCommitShortStat("37991dec2c8e592043f47155ce4808d4580f9123") - require.NoError(t, err) - assert.Equal(t, 1, numFiles) - assert.Equal(t, 1, totalAddition) - assert.Equal(t, 0, totalDeletions) - - numFiles, totalAddition, totalDeletions, err = repo.GetCommitShortStat("6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1") - require.NoError(t, err) - assert.Equal(t, 2, numFiles) - assert.Equal(t, 2, totalAddition) - assert.Equal(t, 0, totalDeletions) - - numFiles, totalAddition, totalDeletions, err = repo.GetCommitShortStat("8006ff9adbf0cb94da7dad9e537e53817f9fa5c0") - require.NoError(t, err) - assert.Equal(t, 2, numFiles) - assert.Equal(t, 2, totalAddition) - assert.Equal(t, 0, totalDeletions) - - numFiles, totalAddition, totalDeletions, err = repo.GetCommitShortStat("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2") - require.NoError(t, err) - assert.Equal(t, 1, numFiles) - assert.Equal(t, 1, totalAddition) - assert.Equal(t, 0, totalDeletions) - - numFiles, totalAddition, totalDeletions, err = repo.GetCommitShortStat("95bb4d39648ee7e325106df01a621c530863a653") - require.NoError(t, err) - assert.Equal(t, 1, numFiles) - assert.Equal(t, 1, totalAddition) - assert.Equal(t, 0, totalDeletions) - }) - - t.Run("repo6_blame_sha256", func(t *testing.T) { - repo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo6_blame_sha256")) - if err != nil { - require.NoError(t, err) - return - } - defer repo.Close() - - numFiles, totalAddition, totalDeletions, err := repo.GetCommitShortStat("e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3") - require.NoError(t, err) - assert.Equal(t, 1, numFiles) - assert.Equal(t, 1, totalAddition) - assert.Equal(t, 0, totalDeletions) - - numFiles, totalAddition, totalDeletions, err = repo.GetCommitShortStat("9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe") - require.NoError(t, err) - assert.Equal(t, 1, numFiles) - assert.Equal(t, 1, totalAddition) - assert.Equal(t, 1, totalDeletions) - - numFiles, totalAddition, totalDeletions, err = repo.GetCommitShortStat("ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc") - require.NoError(t, err) - assert.Equal(t, 1, numFiles) - assert.Equal(t, 6, totalAddition) - assert.Equal(t, 0, totalDeletions) - }) -} diff --git a/modules/git/repo_test.go b/modules/git/repo_test.go index b07fc3732d..c3971b2a5f 100644 --- a/modules/git/repo_test.go +++ b/modules/git/repo_test.go @@ -4,15 +4,7 @@ package git import ( - "bytes" - "encoding/base64" - "io/fs" - "net/http" - "net/http/httptest" - "net/url" - "os" "path/filepath" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -62,80 +54,3 @@ func TestRepoGetDivergingCommits(t *testing.T) { Behind: 2, }, do) } - -func TestCloneCredentials(t *testing.T) { - calledWithoutPassword := false - askpassFile := "" - credentialsFile := "" - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - if req.URL.Path != "/info/refs" { - return - } - - // Get basic authorization. - auth, ok := strings.CutPrefix(req.Header.Get("Authorization"), "Basic ") - if !ok { - w.Header().Set("WWW-Authenticate", `Basic realm="Forgejo"`) - http.Error(w, "require credentials", http.StatusUnauthorized) - return - } - - rawAuth, err := base64.StdEncoding.DecodeString(auth) - require.NoError(t, err) - - user, password, ok := bytes.Cut(rawAuth, []byte{':'}) - assert.True(t, ok) - - // First time around Git tries without password (that's specified in the clone URL). - // It demonstrates it doesn't immediately uses askpass. - if len(password) == 0 { - assert.EqualValues(t, "oauth2", user) - calledWithoutPassword = true - - w.Header().Set("WWW-Authenticate", `Basic realm="Forgejo"`) - http.Error(w, "require credentials", http.StatusUnauthorized) - return - } - - assert.EqualValues(t, "oauth2", user) - assert.EqualValues(t, "some_token", password) - - tmpDir := os.TempDir() - - // Verify that the askpass implementation was used. - files, err := fs.Glob(os.DirFS(tmpDir), "forgejo-askpass*") - require.NoError(t, err) - for _, fileName := range files { - fileContent, err := os.ReadFile(filepath.Join(tmpDir, fileName)) - require.NoError(t, err) - - credentialsPath, ok := bytes.CutPrefix(fileContent, []byte(`exec cat `)) - assert.True(t, ok) - - fileContent, err = os.ReadFile(string(credentialsPath)) - require.NoError(t, err) - assert.EqualValues(t, "some_token", fileContent) - - askpassFile = filepath.Join(tmpDir, fileName) - credentialsFile = string(credentialsPath) - } - })) - - serverURL, err := url.Parse(server.URL) - require.NoError(t, err) - - serverURL.User = url.UserPassword("oauth2", "some_token") - - require.NoError(t, Clone(t.Context(), serverURL.String(), t.TempDir(), CloneRepoOptions{})) - - assert.True(t, calledWithoutPassword) - assert.NotEmpty(t, askpassFile) - assert.NotEmpty(t, credentialsFile) - - // Check that the helper files are gone. - _, err = os.Stat(askpassFile) - require.ErrorIs(t, err, fs.ErrNotExist) - _, err = os.Stat(credentialsFile) - require.ErrorIs(t, err, fs.ErrNotExist) -} diff --git a/modules/git/submodule.go b/modules/git/submodule.go index 4ea97d66eb..b99c81582b 100644 --- a/modules/git/submodule.go +++ b/modules/git/submodule.go @@ -6,124 +6,38 @@ package git import ( "fmt" - "io" "net" "net/url" "path" "regexp" "strings" - - "forgejo.org/modules/setting" - "forgejo.org/modules/util" - - "gopkg.in/ini.v1" //nolint:depguard // used to read .gitmodules ) -// GetSubmodule returns the Submodule of a given path -func (c *Commit) GetSubmodule(path string, entry *TreeEntry) (Submodule, error) { - err := c.readSubmodules() - if err != nil { - // the .gitmodules file exists but could not be read or parsed - return Submodule{}, err - } - - sm, ok := c.submodules[path] - if !ok { - // no info found in .gitmodules: fallback to what we can provide - return Submodule{ - Path: path, - Commit: entry.ID, - }, nil - } - - sm.Commit = entry.ID - return sm, nil -} - -// readSubmodules populates the submodules field by reading the .gitmodules file -func (c *Commit) readSubmodules() error { - if c.submodules != nil { - return nil - } - - entry, err := c.GetTreeEntryByPath(".gitmodules") - if err != nil { - if IsErrNotExist(err) { - c.submodules = make(map[string]Submodule) - return nil - } - return err - } - - rc, _, err := entry.Blob().NewTruncatedReader(10 * 1024) - if err != nil { - return err - } - defer rc.Close() - - c.submodules, err = parseSubmoduleContent(rc) - return err -} - -func parseSubmoduleContent(r io.Reader) (map[string]Submodule, error) { - // https://git-scm.com/docs/gitmodules#_description - // The .gitmodules file, located in the top-level directory of a Git working tree - // is a text file with a syntax matching the requirements of git-config[1]. - // https://git-scm.com/docs/git-config#_configuration_file - - cfg := ini.Empty(ini.LoadOptions{ - InsensitiveKeys: true, // "The variable names are case-insensitive", but "Subsection names are case sensitive" - }) - err := cfg.Append(r) - if err != nil { - return nil, err - } - - sections := cfg.Sections() - submodule := make(map[string]Submodule, len(sections)) - - for _, s := range sections { - sm := parseSubmoduleSection(s) - if sm.Path == "" || sm.URL == "" { - continue - } - submodule[sm.Path] = sm - } - return submodule, nil -} - -func parseSubmoduleSection(s *ini.Section) Submodule { - section, name, _ := strings.Cut(s.Name(), " ") - if !util.ASCIIEqualFold("submodule", section) { // See https://codeberg.org/forgejo/forgejo/pulls/8438#issuecomment-5805251 - return Submodule{} - } - _ = name - - sm := Submodule{} - if key, _ := s.GetKey("path"); key != nil { - sm.Path = key.Value() - } - if key, _ := s.GetKey("url"); key != nil { - sm.URL = key.Value() - } - return sm -} - -// Submodule represents a parsed git submodule reference. -type Submodule struct { - Path string // path property - URL string // upstream URL - Commit ObjectID // upstream Commit-ID -} - -// ResolveUpstreamURL resolves the upstream URL relative to the repo URL. -func (sm Submodule) ResolveUpstreamURL(repoURL string) string { - repoFullName := strings.TrimPrefix(repoURL, setting.AppURL) // currently hacky, but can be dropped when refactoring getRefURL - return getRefURL(sm.URL, setting.AppURL, repoFullName, setting.SSH.Domain) -} - var scpSyntax = regexp.MustCompile(`^([a-zA-Z0-9_]+@)?([a-zA-Z0-9._-]+):(.*)$`) +// SubModule submodule is a reference on git repository +type SubModule struct { + Name string + URL string +} + +// SubModuleFile represents a file with submodule type. +type SubModuleFile struct { + *Commit + + refURL string + refID string +} + +// NewSubModuleFile create a new submodule file +func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile { + return &SubModuleFile{ + Commit: c, + refURL: refURL, + refID: refID, + } +} + func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string { if refURL == "" { return "" @@ -139,7 +53,7 @@ func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string { urlPrefix = strings.TrimSuffix(urlPrefix, "/") - // FIXME: Need to consider branch - which will require changes in parseSubmoduleSection + // FIXME: Need to consider branch - which will require changes in modules/git/commit.go:GetSubModules // Relative url prefix check (according to git submodule documentation) if strings.HasPrefix(refURI, "./") || strings.HasPrefix(refURI, "../") { return urlPrefix + path.Clean(path.Join("/", repoFullName, refURI)) @@ -193,3 +107,13 @@ func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string { return "" } + +// RefURL guesses and returns reference URL. +func (sf *SubModuleFile) RefURL(urlPrefix, repoFullName, sshDomain string) string { + return getRefURL(sf.refURL, urlPrefix, repoFullName, sshDomain) +} + +// RefID returns reference ID. +func (sf *SubModuleFile) RefID() string { + return sf.refID +} diff --git a/modules/git/submodule_test.go b/modules/git/submodule_test.go index 2d27f47456..a396e4ea0d 100644 --- a/modules/git/submodule_test.go +++ b/modules/git/submodule_test.go @@ -4,11 +4,9 @@ package git import ( - "strings" "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestGetRefURL(t *testing.T) { @@ -42,74 +40,3 @@ func TestGetRefURL(t *testing.T) { assert.Equal(t, kase.expect, getRefURL(kase.refURL, kase.prefixURL, kase.parentPath, kase.SSHDomain)) } } - -func Test_parseSubmoduleContent(t *testing.T) { - submoduleFiles := []struct { - fileContent string - expectedPath string - expected Submodule - }{ - { - fileContent: `[submodule "jakarta-servlet"] -url = ../../ALP-pool/jakarta-servlet -path = jakarta-servlet`, - expectedPath: "jakarta-servlet", - expected: Submodule{ - Path: "jakarta-servlet", - URL: "../../ALP-pool/jakarta-servlet", - }, - }, - { - fileContent: `[submodule "jakarta-servlet"] -path = jakarta-servlet -url = ../../ALP-pool/jakarta-servlet`, - expectedPath: "jakarta-servlet", - expected: Submodule{ - Path: "jakarta-servlet", - URL: "../../ALP-pool/jakarta-servlet", - }, - }, - { - fileContent: `[submodule "about/documents"] - path = about/documents - url = git@github.com:example/documents.git - branch = gh-pages -[submodule "custom-name"] - path = manifesto - url = https://github.com/example/manifesto.git -[submodule] - path = relative/url - url = ../such-relative.git -`, - expectedPath: "relative/url", - expected: Submodule{ - Path: "relative/url", - URL: "../such-relative.git", - }, - }, - { - fileContent: `# .gitmodules -# Subsection names are case sensitive -[submodule "Seanpm2001/Degoogle-your-life"] - path = Its-time-to-cut-WideVine-DRM/DeGoogle-Your-Life/submodule.gitmodules - url = https://github.com/seanpm2001/Degoogle-your-life/ - -[submodule "seanpm2001/degoogle-your-life"] - url = https://github.com/seanpm2001/degoogle-your-life/ -# This second section should not be merged with the first, because of casing -`, - expectedPath: "Its-time-to-cut-WideVine-DRM/DeGoogle-Your-Life/submodule.gitmodules", - expected: Submodule{ - Path: "Its-time-to-cut-WideVine-DRM/DeGoogle-Your-Life/submodule.gitmodules", - URL: "https://github.com/seanpm2001/Degoogle-your-life/", - }, - }, - } - for _, kase := range submoduleFiles { - submodule, err := parseSubmoduleContent(strings.NewReader(kase.fileContent)) - require.NoError(t, err) - v, ok := submodule[kase.expectedPath] - assert.True(t, ok) - assert.Equal(t, kase.expected, v) - } -} diff --git a/modules/git/tests/repos/templates_repo/COMMIT_EDITMSG b/modules/git/tests/repos/templates_repo/COMMIT_EDITMSG deleted file mode 100644 index a77fa514de..0000000000 --- a/modules/git/tests/repos/templates_repo/COMMIT_EDITMSG +++ /dev/null @@ -1 +0,0 @@ -Initial diff --git a/modules/git/tests/repos/templates_repo/HEAD b/modules/git/tests/repos/templates_repo/HEAD deleted file mode 100644 index cb089cd89a..0000000000 --- a/modules/git/tests/repos/templates_repo/HEAD +++ /dev/null @@ -1 +0,0 @@ -ref: refs/heads/master diff --git a/modules/git/tests/repos/templates_repo/config b/modules/git/tests/repos/templates_repo/config deleted file mode 100644 index a4ef456cbc..0000000000 --- a/modules/git/tests/repos/templates_repo/config +++ /dev/null @@ -1,5 +0,0 @@ -[core] - repositoryformatversion = 0 - filemode = true - bare = true - logallrefupdates = true diff --git a/modules/git/tests/repos/templates_repo/description b/modules/git/tests/repos/templates_repo/description deleted file mode 100644 index 498b267a8c..0000000000 --- a/modules/git/tests/repos/templates_repo/description +++ /dev/null @@ -1 +0,0 @@ -Unnamed repository; edit this file 'description' to name the repository. diff --git a/modules/git/tests/repos/templates_repo/index b/modules/git/tests/repos/templates_repo/index deleted file mode 100644 index 2b3f95a155..0000000000 Binary files a/modules/git/tests/repos/templates_repo/index and /dev/null differ diff --git a/modules/git/tests/repos/templates_repo/info/exclude b/modules/git/tests/repos/templates_repo/info/exclude deleted file mode 100644 index a5196d1be8..0000000000 --- a/modules/git/tests/repos/templates_repo/info/exclude +++ /dev/null @@ -1,6 +0,0 @@ -# git ls-files --others --exclude-from=.git/info/exclude -# Lines that start with '#' are comments. -# For a project mostly in C, the following would be a good set of -# exclude patterns (uncomment them if you want to use them): -# *.[oa] -# *~ diff --git a/modules/git/tests/repos/templates_repo/info/refs b/modules/git/tests/repos/templates_repo/info/refs deleted file mode 100644 index 8ee4ab3ff8..0000000000 --- a/modules/git/tests/repos/templates_repo/info/refs +++ /dev/null @@ -1 +0,0 @@ -45697427ce0595075c5c8efa42567f050208510d refs/heads/master diff --git a/modules/git/tests/repos/templates_repo/objects/info/commit-graph b/modules/git/tests/repos/templates_repo/objects/info/commit-graph deleted file mode 100644 index 8904092586..0000000000 Binary files a/modules/git/tests/repos/templates_repo/objects/info/commit-graph and /dev/null differ diff --git a/modules/git/tests/repos/templates_repo/objects/info/packs b/modules/git/tests/repos/templates_repo/objects/info/packs deleted file mode 100644 index 5833126b59..0000000000 --- a/modules/git/tests/repos/templates_repo/objects/info/packs +++ /dev/null @@ -1,2 +0,0 @@ -P pack-abb44544ae19d590e95822e963f78d069d27ba9e.pack - diff --git a/modules/git/tests/repos/templates_repo/objects/pack/pack-abb44544ae19d590e95822e963f78d069d27ba9e.bitmap b/modules/git/tests/repos/templates_repo/objects/pack/pack-abb44544ae19d590e95822e963f78d069d27ba9e.bitmap deleted file mode 100644 index 6bd87bf13c..0000000000 Binary files a/modules/git/tests/repos/templates_repo/objects/pack/pack-abb44544ae19d590e95822e963f78d069d27ba9e.bitmap and /dev/null differ diff --git a/modules/git/tests/repos/templates_repo/objects/pack/pack-abb44544ae19d590e95822e963f78d069d27ba9e.idx b/modules/git/tests/repos/templates_repo/objects/pack/pack-abb44544ae19d590e95822e963f78d069d27ba9e.idx deleted file mode 100644 index b530533e1b..0000000000 Binary files a/modules/git/tests/repos/templates_repo/objects/pack/pack-abb44544ae19d590e95822e963f78d069d27ba9e.idx and /dev/null differ diff --git a/modules/git/tests/repos/templates_repo/objects/pack/pack-abb44544ae19d590e95822e963f78d069d27ba9e.pack b/modules/git/tests/repos/templates_repo/objects/pack/pack-abb44544ae19d590e95822e963f78d069d27ba9e.pack deleted file mode 100644 index 6bbcbb6546..0000000000 Binary files a/modules/git/tests/repos/templates_repo/objects/pack/pack-abb44544ae19d590e95822e963f78d069d27ba9e.pack and /dev/null differ diff --git a/modules/git/tests/repos/templates_repo/packed-refs b/modules/git/tests/repos/templates_repo/packed-refs deleted file mode 100644 index eb6e7a8add..0000000000 --- a/modules/git/tests/repos/templates_repo/packed-refs +++ /dev/null @@ -1,2 +0,0 @@ -# pack-refs with: peeled fully-peeled sorted -45697427ce0595075c5c8efa42567f050208510d refs/heads/master diff --git a/modules/git/tests/repos/templates_repo/refs/heads/.gitkeep b/modules/git/tests/repos/templates_repo/refs/heads/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/modules/git/tests/repos/templates_repo/refs/tags/.gitkeep b/modules/git/tests/repos/templates_repo/refs/tags/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/modules/git/tree_blob.go b/modules/git/tree_blob.go index 5c1aa7753d..df339f64b1 100644 --- a/modules/git/tree_blob.go +++ b/modules/git/tree_blob.go @@ -17,6 +17,7 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) { ptree: t, ID: t.ID, name: "", + fullName: "", entryMode: EntryModeTree, }, nil } @@ -54,7 +55,7 @@ func (t *Tree) GetBlobByPath(relpath string) (*Blob, error) { return nil, err } - if !entry.IsDir() && !entry.IsSubmodule() { + if !entry.IsDir() && !entry.IsSubModule() { return entry.Blob(), nil } diff --git a/modules/git/tree_entry.go b/modules/git/tree_entry.go index 8b6c4c467c..d51b7992fe 100644 --- a/modules/git/tree_entry.go +++ b/modules/git/tree_entry.go @@ -21,12 +21,16 @@ type TreeEntry struct { entryMode EntryMode name string - size int64 - sized bool + size int64 + sized bool + fullName string } // Name returns the name of the entry func (te *TreeEntry) Name() string { + if te.fullName != "" { + return te.fullName + } return te.name } @@ -64,8 +68,8 @@ func (te *TreeEntry) Size() int64 { return te.size } -// IsSubmodule if the entry is a submodule -func (te *TreeEntry) IsSubmodule() bool { +// IsSubModule if the entry is a sub module +func (te *TreeEntry) IsSubModule() bool { return te.entryMode == EntryModeCommit } @@ -112,37 +116,32 @@ func (te *TreeEntry) Type() string { } } -// LinkTarget returns the target of the symlink as string. -func (te *TreeEntry) LinkTarget() (string, error) { - if !te.IsLink() { - return "", ErrBadLink{te.Name(), "not a symlink"} - } - - const symlinkLimit = 4096 // according to git config core.longpaths https://stackoverflow.com/a/22575737 - blob := te.Blob() - if blob.Size() > symlinkLimit { - return "", ErrBadLink{te.Name(), "symlink too large"} - } - - rc, size, err := blob.NewTruncatedReader(symlinkLimit) - if err != nil { - return "", err - } - defer rc.Close() - - buf := make([]byte, int(size)) - _, err = io.ReadFull(rc, buf) - return string(buf), err -} - // FollowLink returns the entry pointed to by a symlink func (te *TreeEntry) FollowLink() (*TreeEntry, string, error) { + if !te.IsLink() { + return nil, "", ErrBadLink{te.Name(), "not a symlink"} + } + // read the link - lnk, err := te.LinkTarget() + r, err := te.Blob().DataAsync() if err != nil { return nil, "", err } + closed := false + defer func() { + if !closed { + _ = r.Close() + } + }() + buf := make([]byte, te.Size()) + _, err = io.ReadFull(r, buf) + if err != nil { + return nil, "", err + } + _ = r.Close() + closed = true + lnk := string(buf) t := te.ptree // traverse up directories @@ -210,7 +209,7 @@ func (te *TreeEntry) Tree() *Tree { // GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory ) func (te *TreeEntry) GetSubJumpablePathName() string { - if te.IsSubmodule() || !te.IsDir() { + if te.IsSubModule() || !te.IsDir() { return "" } tree, err := te.ptree.SubTree(te.Name()) @@ -237,7 +236,7 @@ type customSortableEntries struct { var sorter = []func(t1, t2 *TreeEntry, cmp func(s1, s2 string) bool) bool{ func(t1, t2 *TreeEntry, cmp func(s1, s2 string) bool) bool { - return (t1.IsDir() || t1.IsSubmodule()) && !t2.IsDir() && !t2.IsSubmodule() + return (t1.IsDir() || t1.IsSubModule()) && !t2.IsDir() && !t2.IsSubModule() }, func(t1, t2 *TreeEntry, cmp func(s1, s2 string) bool) bool { return cmp(t1.Name(), t2.Name()) diff --git a/modules/graceful/server_http.go b/modules/graceful/server_http.go index 0b2984a953..7c855ac64e 100644 --- a/modules/graceful/server_http.go +++ b/modules/graceful/server_http.go @@ -16,11 +16,6 @@ func newHTTPServer(network, address, name string, handler http.Handler) (*Server Handler: handler, BaseContext: func(net.Listener) context.Context { return GetManager().HammerContext() }, } - // Enable H2C for HTTP server - httpServer.Protocols = new(http.Protocols) - httpServer.Protocols.SetHTTP1(true) - httpServer.Protocols.SetHTTP2(true) - httpServer.Protocols.SetUnencryptedHTTP2(true) server.OnShutdown = func() { httpServer.SetKeepAlivesEnabled(false) } diff --git a/modules/httplib/serve.go b/modules/httplib/serve.go index d385ac21c9..c5f0658d4e 100644 --- a/modules/httplib/serve.go +++ b/modules/httplib/serve.go @@ -99,7 +99,7 @@ func setServeHeadersByFile(r *http.Request, w http.ResponseWriter, filePath stri Filename: path.Base(filePath), } - sniffedType := typesniffer.DetectContentType(mineBuf, opts.Filename) + sniffedType := typesniffer.DetectContentType(mineBuf) // the "render" parameter came from year 2016: 638dd24c, it doesn't have clear meaning, so I think it could be removed later isPlain := sniffedType.IsText() || r.FormValue("render") != "" diff --git a/modules/indexer/code/bleve/bleve.go b/modules/indexer/code/bleve/bleve.go index 4c8b5f2a86..c53b7a2e6d 100644 --- a/modules/indexer/code/bleve/bleve.go +++ b/modules/indexer/code/bleve/bleve.go @@ -177,7 +177,7 @@ func (b *Indexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserErro fileContents, err := io.ReadAll(io.LimitReader(batchReader, size)) if err != nil { return err - } else if !typesniffer.DetectContentType(fileContents, update.Filename).IsText() { + } else if !typesniffer.DetectContentType(fileContents).IsText() { // FIXME: UTF-16 files will probably fail here // Even if the file is not recognized as a "text file", we could still put its name into the indexers to make the filename become searchable, while leave the content to empty. fileContents = nil diff --git a/modules/indexer/code/elasticsearch/elasticsearch.go b/modules/indexer/code/elasticsearch/elasticsearch.go index 9b11f56fb7..3903d77fe0 100644 --- a/modules/indexer/code/elasticsearch/elasticsearch.go +++ b/modules/indexer/code/elasticsearch/elasticsearch.go @@ -144,7 +144,7 @@ func (b *Indexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserErro fileContents, err := io.ReadAll(io.LimitReader(batchReader, size)) if err != nil { return nil, err - } else if !typesniffer.DetectContentType(fileContents, update.Filename).IsText() { + } else if !typesniffer.DetectContentType(fileContents).IsText() { // FIXME: UTF-16 files will probably fail here return nil, nil } diff --git a/modules/indexer/code/search.go b/modules/indexer/code/search.go index 66c9497dab..499b9117c4 100644 --- a/modules/indexer/code/search.go +++ b/modules/indexer/code/search.go @@ -35,7 +35,6 @@ type SearchResultLanguages = internal.SearchResultLanguages type SearchOptions = internal.SearchOptions -// llu:TrKeysSuffix search. var CodeSearchOptions = [2]string{"exact", "union"} type SearchMode = internal.CodeSearchMode diff --git a/modules/indexer/code/search_test.go b/modules/indexer/code/search_test.go index 2413ddec0b..e542b38c24 100644 --- a/modules/indexer/code/search_test.go +++ b/modules/indexer/code/search_test.go @@ -86,9 +86,9 @@ func TestHighlightSearchResultCode(t *testing.T) { Range: [][3]int{{1, 14, 23}}, Code: "func main() {\n\tfmt.Println(\"mark this\")\n}", Result: []template.HTML{ - "func main() {", - "\tfmt.Println("mark this")", - "}", + "func main() {", + "\tfmt.Println("mark this")", + "}", }, }, { @@ -97,9 +97,9 @@ func TestHighlightSearchResultCode(t *testing.T) { Range: [][3]int{{1, 14, 28}}, Code: "func main() {\n\tfmt.Println(\"mark this ๐Ÿ˜Š\")\n}", Result: []template.HTML{ - "func main() {", - "\tfmt.Println("mark this ๐Ÿ˜Š")", - "}", + "func main() {", + "\tfmt.Println("mark this ๐Ÿ˜Š")", + "}", }, }, } diff --git a/modules/indexer/issues/bleve/bleve.go b/modules/indexer/issues/bleve/bleve.go index cb98f722c5..80af7bac45 100644 --- a/modules/indexer/issues/bleve/bleve.go +++ b/modules/indexer/issues/bleve/bleve.go @@ -171,7 +171,7 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( if issueID, err := token.ParseIssueReference(); err == nil { idQuery := inner_bleve.NumericEqualityQuery(issueID, "index") - idQuery.SetBoost(20.0) + idQuery.SetBoost(5.0) innerQ.AddQuery(idQuery) } @@ -198,15 +198,6 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( queries = append(queries, bleve.NewDisjunctionQuery(repoQueries...)) } - if options.PriorityRepoID.Has() { - eq := inner_bleve.NumericEqualityQuery(options.PriorityRepoID.Value(), "repo_id") - eq.SetBoost(10.0) - meh := bleve.NewMatchAllQuery() - meh.SetBoost(0) - should := bleve.NewDisjunctionQuery(eq, meh) - queries = append(queries, should) - } - if options.IsPull.Has() { queries = append(queries, inner_bleve.BoolFieldQuery(options.IsPull.Value(), "is_pull")) } diff --git a/modules/indexer/issues/db/db.go b/modules/indexer/issues/db/db.go index 5f42bce9a1..397daa3265 100644 --- a/modules/indexer/issues/db/db.go +++ b/modules/indexer/issues/db/db.go @@ -53,7 +53,6 @@ func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( cond := builder.NewCond() - var priorityIssueIndex int64 if options.Keyword != "" { repoCond := builder.In("repo_id", options.RepoIDs) if len(options.RepoIDs) == 1 { @@ -83,7 +82,6 @@ func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( builder.Eq{"`index`": issueID}, cond, ) - priorityIssueIndex = issueID } } @@ -91,7 +89,6 @@ func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( if err != nil { return nil, err } - opt.PriorityIssueIndex = priorityIssueIndex // If pagesize == 0, return total count only. It's a special case for search count. if options.Paginator != nil && options.Paginator.PageSize == 0 { diff --git a/modules/indexer/issues/db/options.go b/modules/indexer/issues/db/options.go index 55a471fc8e..4411cc1c37 100644 --- a/modules/indexer/issues/db/options.go +++ b/modules/indexer/issues/db/options.go @@ -78,11 +78,6 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m User: nil, } - if options.PriorityRepoID.Has() { - opts.SortType = "priorityrepo" - opts.PriorityRepoID = options.PriorityRepoID.Value() - } - if len(options.MilestoneIDs) == 1 && options.MilestoneIDs[0] == 0 { opts.MilestoneIDs = []int64{db.NoConditionID} } else { diff --git a/modules/indexer/issues/elasticsearch/elasticsearch.go b/modules/indexer/issues/elasticsearch/elasticsearch.go index 311e92730e..0c4e5fae02 100644 --- a/modules/indexer/issues/elasticsearch/elasticsearch.go +++ b/modules/indexer/issues/elasticsearch/elasticsearch.go @@ -166,7 +166,7 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( } var eitherQ elastic.Query = innerQ if issueID, err := token.ParseIssueReference(); err == nil { - indexQ := elastic.NewTermQuery("index", issueID).Boost(20) + indexQ := elastic.NewTermQuery("index", issueID).Boost(15.0) eitherQ = elastic.NewDisMaxQuery().Query(indexQ).Query(innerQ).TieBreaker(0.5) } switch token.Kind { @@ -189,10 +189,6 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( } query.Must(q) } - if options.PriorityRepoID.Has() { - q := elastic.NewTermQuery("repo_id", options.PriorityRepoID.Value()).Boost(10) - query.Should(q) - } if options.IsPull.Has() { query.Must(elastic.NewTermQuery("is_pull", options.IsPull.Value())) diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go index 21daea3d45..d3b3494672 100644 --- a/modules/indexer/issues/indexer_test.go +++ b/modules/indexer/issues/indexer_test.go @@ -84,7 +84,7 @@ func searchIssueWithKeyword(t *testing.T) { issueIDs, _, err := SearchIssues(t.Context(), &test.opts) require.NoError(t, err) - assert.Equal(t, test.expectedIDs, issueIDs, test.opts.Keyword) + assert.Equal(t, test.expectedIDs, issueIDs) } } diff --git a/modules/indexer/issues/internal/model.go b/modules/indexer/issues/internal/model.go index cdd113212d..6c55405179 100644 --- a/modules/indexer/issues/internal/model.go +++ b/modules/indexer/issues/internal/model.go @@ -75,9 +75,8 @@ type SearchResult struct { type SearchOptions struct { Keyword string // keyword to search - RepoIDs []int64 // repository IDs which the issues belong to - AllPublic bool // if include all public repositories - PriorityRepoID optional.Option[int64] // issues from this repository will be prioritized when SortByScore + RepoIDs []int64 // repository IDs which the issues belong to + AllPublic bool // if include all public repositories IsPull optional.Option[bool] // if the issues is a pull request IsClosed optional.Option[bool] // if the issues is closed diff --git a/modules/indexer/issues/internal/tests/tests.go b/modules/indexer/issues/internal/tests/tests.go index 46014994a0..e7723ea69d 100644 --- a/modules/indexer/issues/internal/tests/tests.go +++ b/modules/indexer/issues/internal/tests/tests.go @@ -772,25 +772,6 @@ var cases = []*testIndexerCase{ } }, }, - { - Name: "PriorityRepoID", - SearchOptions: &internal.SearchOptions{ - IsPull: optional.Some(false), - IsClosed: optional.Some(false), - PriorityRepoID: optional.Some(int64(3)), - Paginator: &db.ListOptionsAll, - SortBy: internal.SortByScore, - }, - Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { - for i, v := range result.Hits { - if i < 7 { - assert.Equal(t, int64(3), data[v.ID].RepoID) - } else { - assert.NotEqual(t, int64(3), data[v.ID].RepoID) - } - } - }, - }, } type testIndexerCase struct { diff --git a/modules/indexer/issues/meilisearch/meilisearch.go b/modules/indexer/issues/meilisearch/meilisearch.go index 9c14e4cbd3..17a8ba2452 100644 --- a/modules/indexer/issues/meilisearch/meilisearch.go +++ b/modules/indexer/issues/meilisearch/meilisearch.go @@ -100,7 +100,7 @@ func (b *Indexer) Index(_ context.Context, issues ...*internal.IndexerData) erro return nil } for _, issue := range issues { - _, err := b.inner.Client.Index(b.inner.VersionedIndexName()).AddDocuments(issue, nil) + _, err := b.inner.Client.Index(b.inner.VersionedIndexName()).AddDocuments(issue) if err != nil { return err } @@ -303,9 +303,21 @@ func doubleQuoteKeyword(k string) string { } func convertHits(searchRes *meilisearch.SearchResponse) ([]internal.Match, error) { - hits := make([]internal.Match, 0) - if err := searchRes.Hits.DecodeInto(&hits); err != nil { - return nil, ErrMalformedResponse + hits := make([]internal.Match, 0, len(searchRes.Hits)) + for _, hit := range searchRes.Hits { + hit, ok := hit.(map[string]any) + if !ok { + return nil, ErrMalformedResponse + } + + issueID, ok := hit["id"].(float64) + if !ok { + return nil, ErrMalformedResponse + } + + hits = append(hits, internal.Match{ + ID: int64(issueID), + }) } return hits, nil } diff --git a/modules/indexer/issues/meilisearch/meilisearch_test.go b/modules/indexer/issues/meilisearch/meilisearch_test.go index 810de77046..7637e8d6b4 100644 --- a/modules/indexer/issues/meilisearch/meilisearch_test.go +++ b/modules/indexer/issues/meilisearch/meilisearch_test.go @@ -46,34 +46,30 @@ func TestMeilisearchIndexer(t *testing.T) { } func TestConvertHits(t *testing.T) { - for _, invalidID := range []string{"\"aa\"", "{\"aa\":\"123\"}", "[\"aa\"]"} { - _, err := convertHits(&meilisearch.SearchResponse{ - Hits: meilisearch.Hits{ - meilisearch.Hit{"id": []byte(invalidID)}, - }, - }) - require.ErrorIs(t, err, ErrMalformedResponse) - } + _, err := convertHits(&meilisearch.SearchResponse{ + Hits: []any{"aa", "bb", "cc", "dd"}, + }) + require.ErrorIs(t, err, ErrMalformedResponse) validResponse := &meilisearch.SearchResponse{ - Hits: meilisearch.Hits{ - meilisearch.Hit{ - "id": []byte("11"), - "title": []byte("\"a title\""), - "content": []byte("\"issue body with no match\""), - "comments": []byte("[\"hey what's up?\", \"I'm currently bowling\", \"nice\"]"), + Hits: []any{ + map[string]any{ + "id": float64(11), + "title": "a title", + "content": "issue body with no match", + "comments": []any{"hey what's up?", "I'm currently bowling", "nice"}, }, - meilisearch.Hit{ - "id": []byte("22"), - "title": []byte("\"Bowling as title\""), - "content": []byte("\"\""), - "comments": []byte("[]"), + map[string]any{ + "id": float64(22), + "title": "Bowling as title", + "content": "", + "comments": []any{}, }, - meilisearch.Hit{ - "id": []byte("33"), - "title": []byte("\"Bowl-ing as fuzzy match\""), - "content": []byte("\"\""), - "comments": []byte("[]"), + map[string]any{ + "id": float64(33), + "title": "Bowl-ing as fuzzy match", + "content": "", + "comments": []any{}, }, }, } diff --git a/modules/issue/template/unmarshal.go b/modules/issue/template/unmarshal.go index 0d80dae009..8df71a3299 100644 --- a/modules/issue/template/unmarshal.go +++ b/modules/issue/template/unmarshal.go @@ -15,7 +15,7 @@ import ( api "forgejo.org/modules/structs" "forgejo.org/modules/util" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) // CouldBe indicates a file with the filename could be a template, diff --git a/modules/keying/keying.go b/modules/keying/keying.go index f39e16aeed..c859e30e9f 100644 --- a/modules/keying/keying.go +++ b/modules/keying/keying.go @@ -58,8 +58,6 @@ var ( ContextPushMirror Context = "pushmirror" // Used for the `two_factor` table. ContextTOTP Context = "totp" - // Used for the `secret` table. - ContextActionSecret Context = "action_secret" ) // Derive *the* key for a given context, this is a deterministic function. diff --git a/modules/label/parser.go b/modules/label/parser.go index 12fc176967..558ae68def 100644 --- a/modules/label/parser.go +++ b/modules/label/parser.go @@ -10,7 +10,7 @@ import ( "forgejo.org/modules/options" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) type labelFile struct { diff --git a/modules/lfs/pointer_scanner.go b/modules/lfs/pointer_scanner.go index 80da8e5222..632ecd19ae 100644 --- a/modules/lfs/pointer_scanner.go +++ b/modules/lfs/pointer_scanner.go @@ -39,7 +39,16 @@ func SearchPointerBlobs(ctx context.Context, repo *git.Repository, pointerChan c go pipeline.BlobsLessThan1024FromCatFileBatchCheck(catFileCheckReader, shasToBatchWriter, &wg) // 1. Run batch-check on all objects in the repository - go pipeline.CatFileBatchCheckAllObjects(ctx, catFileCheckWriter, &wg, basePath, errChan) + if git.CheckGitVersionAtLeast("2.6.0") != nil { + revListReader, revListWriter := io.Pipe() + shasToCheckReader, shasToCheckWriter := io.Pipe() + wg.Add(2) + go pipeline.CatFileBatchCheck(ctx, shasToCheckReader, catFileCheckWriter, &wg, basePath) + go pipeline.BlobsFromRevListObjects(revListReader, shasToCheckWriter, &wg) + go pipeline.RevListAllObjects(ctx, revListWriter, &wg, basePath, errChan) + } else { + go pipeline.CatFileBatchCheckAllObjects(ctx, catFileCheckWriter, &wg, basePath, errChan) + } wg.Wait() close(pointerChan) diff --git a/modules/log/event_format.go b/modules/log/event_format.go index 6835a4ca5b..df6b083a92 100644 --- a/modules/log/event_format.go +++ b/modules/log/event_format.go @@ -13,9 +13,10 @@ import ( type Event struct { Time time.Time - Caller string - Filename string - Line int + GoroutinePid string + Caller string + Filename string + Line int Level Level @@ -224,6 +225,19 @@ func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, ms msg = msg[:len(msg)-1] } + if flags&Lgopid == Lgopid { + if event.GoroutinePid != "" { + buf = append(buf, '[') + if mode.Colorize { + buf = append(buf, ColorBytes(FgHiYellow)...) + } + buf = append(buf, event.GoroutinePid...) + if mode.Colorize { + buf = append(buf, resetBytes...) + } + buf = append(buf, ']', ' ') + } + } buf = append(buf, msg...) if event.Stacktrace != "" && mode.StacktraceLevel <= event.Level { diff --git a/modules/log/event_format_test.go b/modules/log/event_format_test.go index f6f9754300..0c6061eaea 100644 --- a/modules/log/event_format_test.go +++ b/modules/log/event_format_test.go @@ -24,45 +24,48 @@ func TestItoa(t *testing.T) { func TestEventFormatTextMessage(t *testing.T) { res := EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: false, Flags: Flags{defined: true, flags: 0xffffffff}}, &Event{ - Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), - Caller: "caller", - Filename: "filename", - Line: 123, - Level: ERROR, - Stacktrace: "stacktrace", + Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), + Caller: "caller", + Filename: "filename", + Line: 123, + GoroutinePid: "pid", + Level: ERROR, + Stacktrace: "stacktrace", }, "msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue), ) - assert.Equal(t, `<3>[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] msg format: arg0 arg1 + assert.Equal(t, `<3>[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [pid] msg format: arg0 arg1 stacktrace `, string(res)) res = EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: true, Flags: Flags{defined: true, flags: 0xffffffff}}, &Event{ - Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), - Caller: "caller", - Filename: "filename", - Line: 123, - Level: ERROR, - Stacktrace: "stacktrace", + Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), + Caller: "caller", + Filename: "filename", + Line: 123, + GoroutinePid: "pid", + Level: ERROR, + Stacktrace: "stacktrace", }, "msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue), ) - assert.Equal(t, "<3>[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res)) + assert.Equal(t, "<3>[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mpid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res)) } func TestEventFormatTextMessageStd(t *testing.T) { res := EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: false, Flags: Flags{defined: true, flags: LstdFlags}}, &Event{ - Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), - Caller: "caller", - Filename: "filename", - Line: 123, - Level: ERROR, - Stacktrace: "stacktrace", + Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), + Caller: "caller", + Filename: "filename", + Line: 123, + GoroutinePid: "pid", + Level: ERROR, + Stacktrace: "stacktrace", }, "msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue), ) @@ -74,12 +77,13 @@ func TestEventFormatTextMessageStd(t *testing.T) { res = EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: true, Flags: Flags{defined: true, flags: LstdFlags}}, &Event{ - Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), - Caller: "caller", - Filename: "filename", - Line: 123, - Level: ERROR, - Stacktrace: "stacktrace", + Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), + Caller: "caller", + Filename: "filename", + Line: 123, + GoroutinePid: "pid", + Level: ERROR, + Stacktrace: "stacktrace", }, "msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue), ) @@ -92,12 +96,13 @@ func TestEventFormatTextMessageJournal(t *testing.T) { // the proper way here is to attach the backtrace as structured metadata, but we can't do that via stderr res := EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: false, Flags: Flags{defined: true, flags: LjournaldFlags}}, &Event{ - Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), - Caller: "caller", - Filename: "filename", - Line: 123, - Level: ERROR, - Stacktrace: "stacktrace", + Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), + Caller: "caller", + Filename: "filename", + Line: 123, + GoroutinePid: "pid", + Level: ERROR, + Stacktrace: "stacktrace", }, "msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue), ) diff --git a/modules/log/event_writer.go b/modules/log/event_writer.go index 32b5b582c5..4b77e488de 100644 --- a/modules/log/event_writer.go +++ b/modules/log/event_writer.go @@ -26,7 +26,6 @@ type WriterMode struct { Flags Flags Expression string - Exclusion string StacktraceLevel Level diff --git a/modules/log/event_writer_base.go b/modules/log/event_writer_base.go index 4de2b953c7..9189ca4e90 100644 --- a/modules/log/event_writer_base.go +++ b/modules/log/event_writer_base.go @@ -68,14 +68,6 @@ func (b *EventWriterBaseImpl) Run(ctx context.Context) { } } - var exclusionRegexp *regexp.Regexp - if b.Mode.Exclusion != "" { - var err error - if exclusionRegexp, err = regexp.Compile(b.Mode.Exclusion); err != nil { - FallbackErrorf("unable to compile exclusion %q for writer %q: %v", b.Mode.Exclusion, b.Name, err) - } - } - handlePaused := func() { if pause := b.GetPauseChan(); pause != nil { select { @@ -103,13 +95,6 @@ func (b *EventWriterBaseImpl) Run(ctx context.Context) { continue } } - if exclusionRegexp != nil { - fileLineCaller := fmt.Sprintf("%s:%d:%s", event.Origin.Filename, event.Origin.Line, event.Origin.Caller) - matched := exclusionRegexp.MatchString(fileLineCaller) || exclusionRegexp.MatchString(event.Origin.MsgSimpleText) - if matched { - continue - } - } var err error switch msg := event.Msg.(type) { diff --git a/modules/log/event_writer_buffer_test.go b/modules/log/event_writer_buffer_test.go index d1e37c3673..ba9455ba69 100644 --- a/modules/log/event_writer_buffer_test.go +++ b/modules/log/event_writer_buffer_test.go @@ -31,49 +31,3 @@ func TestBufferLogger(t *testing.T) { logger.Close() assert.Contains(t, bufferWriter.Buffer.String(), expected) } - -func TestBufferLoggerWithExclusion(t *testing.T) { - prefix := "ExclusionPrefix " - level := log.INFO - message := "something" - - bufferWriter := log.NewEventWriterBuffer("test-buffer", log.WriterMode{ - Level: level, - Prefix: prefix, - Exclusion: message, - }) - - logger := log.NewLoggerWithWriters(t.Context(), "test", bufferWriter) - - logger.SendLogEvent(&log.Event{ - Level: log.INFO, - MsgSimpleText: message, - }) - logger.Close() - assert.NotContains(t, bufferWriter.Buffer.String(), message) -} - -func TestBufferLoggerWithExpressionAndExclusion(t *testing.T) { - prefix := "BothPrefix " - level := log.INFO - expression := ".*foo.*" - exclusion := ".*bar.*" - - bufferWriter := log.NewEventWriterBuffer("test-buffer", log.WriterMode{ - Level: level, - Prefix: prefix, - Expression: expression, - Exclusion: exclusion, - }) - - logger := log.NewLoggerWithWriters(t.Context(), "test", bufferWriter) - - logger.SendLogEvent(&log.Event{Level: log.INFO, MsgSimpleText: "foo expression"}) - logger.SendLogEvent(&log.Event{Level: log.INFO, MsgSimpleText: "bar exclusion"}) - logger.SendLogEvent(&log.Event{Level: log.INFO, MsgSimpleText: "foo bar both"}) - logger.SendLogEvent(&log.Event{Level: log.INFO, MsgSimpleText: "none"}) - logger.Close() - - assert.Contains(t, bufferWriter.Buffer.String(), "foo expression") - assert.NotContains(t, bufferWriter.Buffer.String(), "bar") -} diff --git a/modules/log/flags.go b/modules/log/flags.go index 1e4fe830c1..afce30680d 100644 --- a/modules/log/flags.go +++ b/modules/log/flags.go @@ -30,6 +30,7 @@ const ( LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone Llevelinitial // Initial character of the provided level in brackets, eg. [I] for info Llevel // Provided level in brackets [INFO] + Lgopid // the Goroutine-PID of the context Llevelprefix // printk-style logging prefixes as documented in sd-daemon(3), used by journald Lmedfile = Lshortfile | Llongfile // last 20 characters of the filename @@ -56,6 +57,7 @@ var flagFromString = map[string]uint32{ "levelinitial": Llevelinitial, "level": Llevel, "levelprefix": Llevelprefix, + "gopid": Lgopid, "medfile": Lmedfile, "stdflags": LstdFlags, @@ -80,6 +82,7 @@ var flagComboToString = []struct { {LUTC, "utc"}, {Llevelinitial, "levelinitial"}, {Llevel, "level"}, + {Lgopid, "gopid"}, } func (f Flags) Bits() uint32 { diff --git a/modules/log/flags_test.go b/modules/log/flags_test.go index f39fe440e2..1af9a58ed6 100644 --- a/modules/log/flags_test.go +++ b/modules/log/flags_test.go @@ -15,7 +15,9 @@ import ( func TestFlags(t *testing.T) { assert.Equal(t, Ldefault, Flags{}.Bits()) assert.EqualValues(t, 0, FlagsFromString("").Bits()) - assert.Equal(t, Ldate|Ltime, FlagsFromString("date,time").Bits()) + assert.Equal(t, Lgopid, FlagsFromString("", Lgopid).Bits()) + assert.EqualValues(t, 0, FlagsFromString("none", Lgopid).Bits()) + assert.Equal(t, Ldate|Ltime, FlagsFromString("date,time", Lgopid).Bits()) assert.Equal(t, "stdflags", FlagsFromString("stdflags").String()) assert.Equal(t, "medfile", FlagsFromString("medfile").String()) diff --git a/modules/log/groutinelabel.go b/modules/log/groutinelabel.go new file mode 100644 index 0000000000..cd5fb96d52 --- /dev/null +++ b/modules/log/groutinelabel.go @@ -0,0 +1,21 @@ +//go:build !go1.24 + +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package log + +import "unsafe" + +//go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel +func runtime_getProfLabel() unsafe.Pointer //nolint + +type labelMap map[string]string + +func getGoroutineLabels() map[string]string { + l := (*labelMap)(runtime_getProfLabel()) + if l == nil { + return nil + } + return *l +} diff --git a/modules/log/groutinelabel_go1.24.go b/modules/log/groutinelabel_go1.24.go new file mode 100644 index 0000000000..e849811bc2 --- /dev/null +++ b/modules/log/groutinelabel_go1.24.go @@ -0,0 +1,38 @@ +//go:build go1.24 + +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package log + +import "unsafe" + +//go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel +func runtime_getProfLabel() unsafe.Pointer //nolint + +// Struct definitions copied from: https://github.com/golang/go/blob/ca63101df47a4467bc80faa654fc19d68e583952/src/runtime/pprof/label.go +type label struct { + key string + value string +} + +type LabelSet struct { + list []label +} + +type labelMap struct { + LabelSet +} + +func getGoroutineLabels() map[string]string { + l := (*labelMap)(runtime_getProfLabel()) + if l == nil { + return nil + } + + m := make(map[string]string, len(l.list)) + for _, label := range l.list { + m[label.key] = label.value + } + return m +} diff --git a/modules/log/groutinelabel_test.go b/modules/log/groutinelabel_test.go new file mode 100644 index 0000000000..98d7b4e129 --- /dev/null +++ b/modules/log/groutinelabel_test.go @@ -0,0 +1,33 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package log + +import ( + "context" + "runtime/pprof" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_getGoroutineLabels(t *testing.T) { + pprof.Do(t.Context(), pprof.Labels(), func(ctx context.Context) { + currentLabels := getGoroutineLabels() + pprof.ForLabels(ctx, func(key, value string) bool { + assert.Equal(t, value, currentLabels[key]) + return true + }) + + pprof.Do(ctx, pprof.Labels("Test_getGoroutineLabels", "Test_getGoroutineLabels_child1"), func(ctx context.Context) { + currentLabels := getGoroutineLabels() + pprof.ForLabels(ctx, func(key, value string) bool { + assert.Equal(t, value, currentLabels[key]) + return true + }) + if assert.NotNil(t, currentLabels) { + assert.Equal(t, "Test_getGoroutineLabels_child1", currentLabels["Test_getGoroutineLabels"]) + } + }) + }) +} diff --git a/modules/log/logger_impl.go b/modules/log/logger_impl.go index 76d7e6a821..b21e800f52 100644 --- a/modules/log/logger_impl.go +++ b/modules/log/logger_impl.go @@ -200,6 +200,11 @@ func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) { event.Stacktrace = Stack(skip + 1) } + labels := getGoroutineLabels() + if labels != nil { + event.GoroutinePid = labels["pid"] + } + // get a simple text message without color msgArgs := make([]any, len(logArgs)) copy(msgArgs, logArgs) diff --git a/modules/log/logger_test.go b/modules/log/logger_test.go index 99045b0f4f..6d6ceb69d7 100644 --- a/modules/log/logger_test.go +++ b/modules/log/logger_test.go @@ -143,19 +143,3 @@ func TestLoggerExpressionFilter(t *testing.T) { assert.Equal(t, []string{"foo\n", "foo bar\n", "by filename\n"}, w1.GetLogs()) } - -func TestLoggerExclusionFilter(t *testing.T) { - logger := NewLoggerWithWriters(t.Context(), "test") - - w1 := newDummyWriter("dummy-1", DEBUG, 0) - w1.Mode.Exclusion = "foo.*" - logger.AddWriters(w1) - - logger.Info("foo") - logger.Info("bar") - logger.Info("foo bar") - logger.SendLogEvent(&Event{Level: INFO, Filename: "foo.go", MsgSimpleText: "by filename"}) - logger.Close() - - assert.Equal(t, []string{"bar\n"}, w1.GetLogs()) -} diff --git a/modules/log/stack.go b/modules/log/stack.go index a8d26d1fc3..9b22e92867 100644 --- a/modules/log/stack.go +++ b/modules/log/stack.go @@ -32,7 +32,7 @@ func Stack(skip int) string { } // Print equivalent of debug.Stack() - _, _ = fmt.Fprintf(buf, "\t%s:%d (0x%x)\n", filename, lineNumber, programCounter) + _, _ = fmt.Fprintf(buf, "%s:%d (0x%x)\n", filename, lineNumber, programCounter) // Now try to print the offending line if filename != lastFilename { data, err := os.ReadFile(filename) @@ -44,7 +44,7 @@ func Stack(skip int) string { lines = bytes.Split(data, []byte{'\n'}) lastFilename = filename } - _, _ = fmt.Fprintf(buf, "\t\t%s: %s\n", functionName(programCounter), source(lines, lineNumber)) + _, _ = fmt.Fprintf(buf, "\t%s: %s\n", functionName(programCounter), source(lines, lineNumber)) } return buf.String() } diff --git a/modules/markup/file_preview.go b/modules/markup/file_preview.go index dab6057cf4..8b1442ed08 100644 --- a/modules/markup/file_preview.go +++ b/modules/markup/file_preview.go @@ -25,7 +25,7 @@ import ( ) // filePreviewPattern matches "http://domain/org/repo/src/commit/COMMIT/filepath#L1-L2" -var filePreviewPattern = regexp.MustCompile(`https?://((?:\S+/){3})src/commit/([0-9a-f]{4,64})/(\S+)#(L\d+(?:-L?\d+)?)`) +var filePreviewPattern = regexp.MustCompile(`https?://((?:\S+/){3})src/commit/([0-9a-f]{4,64})/(\S+)#(L\d+(?:-L\d+)?)`) type FilePreview struct { fileContent []template.HTML @@ -78,17 +78,17 @@ func newFilePreview(ctx *RenderContext, node *html.Node, locale translation.Loca commitSha := node.Data[m[4]:m[5]] filePath := node.Data[m[6]:m[7]] - hash := node.Data[m[8]:m[9]] 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#" + hash + 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] preview.end = m[1] diff --git a/modules/markup/html.go b/modules/markup/html.go index 58021f5cb5..7961c5c930 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -557,13 +557,9 @@ func createCodeLink(href, content, class string) *html.Node { a.Attr = append(a.Attr, html.Attribute{Key: "class", Val: class}) } - unescaped, err := url.QueryUnescape(content) - if err != nil { - unescaped = content - } text := &html.Node{ Type: html.TextNode, - Data: unescaped, + Data: content, } code := &html.Node{ @@ -1146,7 +1142,7 @@ func emojiShortCodeProcessor(ctx *RenderContext, node *html.Node) { converted := emoji.FromAlias(alias) if converted == nil { // check if this is a custom reaction - if setting.UI.CustomEmojisLookup.Contains(alias) { + if _, exist := setting.UI.CustomEmojisMap[alias]; exist { replaceContent(node, m[0], m[1], createCustomEmoji(alias)) node = node.NextSibling.NextSibling start = 0 diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 11a6290ca3..2bc929bb04 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -91,9 +91,6 @@ func TestRender_Commits(t *testing.T) { test(sha[:14]+".", `

`+expected14+`.

`) test(sha[:14]+",", `

`+expected14+`,

`) test("["+sha[:14]+"]", `

[`+expected14+`]

`) - - fileStrangeChars := util.URLJoin(repo, "src", "commit", "eeb243c3395e1921c5d90e73bd739827251fc99d", "path", "to", "file%20%23.txt") - test(fileStrangeChars, `

eeb243c339/path/to/file #.txt

`) } func TestRender_CrossReferences(t *testing.T) { @@ -361,7 +358,7 @@ func TestRender_emoji(t *testing.T) { test( ":custom-emoji:", `

:custom-emoji:

`) - setting.UI.CustomEmojisLookup.Add("custom-emoji") + setting.UI.CustomEmojisMap["custom-emoji"] = ":custom-emoji:" test( ":custom-emoji:", `

:custom-emoji:

`) @@ -746,11 +743,11 @@ func TestRender_FilePreview(t *testing.T) { ``+ ``+ ``+ - `B`+"\n"+``+ + `B`+"\n"+``+ ``+ ``+ ``+ - `C`+"\n"+``+ + `C`+"\n"+``+ ``+ ``+ ``+ @@ -780,11 +777,11 @@ func TestRender_FilePreview(t *testing.T) { ``+ ``+ ``+ - `B`+"\n"+``+ + `B`+"\n"+``+ ``+ ``+ ``+ - `C`+"\n"+``+ + `C`+"\n"+``+ ``+ ``+ ``+ @@ -859,11 +856,11 @@ func TestRender_FilePreview(t *testing.T) { ``+ ``+ ``+ - `B`+"\n"+``+ + `B`+"\n"+``+ ``+ ``+ ``+ - `C`+"\n"+``+ + `C`+"\n"+``+ ``+ ``+ ``+ @@ -890,11 +887,11 @@ func TestRender_FilePreview(t *testing.T) { ``+ ``+ ``+ - `B`+"\n"+``+ + `B`+"\n"+``+ ``+ ``+ ``+ - `C`+"\n"+``+ + `C`+"\n"+``+ ``+ ``+ ``+ @@ -923,11 +920,11 @@ func TestRender_FilePreview(t *testing.T) { ``+ ``+ ``+ - `B`+"\n"+``+ + `B`+"\n"+``+ ``+ ``+ ``+ - `C`+"\n"+``+ + `C`+"\n"+``+ ``+ ``+ ``+ @@ -948,11 +945,11 @@ func TestRender_FilePreview(t *testing.T) { ``+ ``+ ``+ - `B`+"\n"+``+ + `B`+"\n"+``+ ``+ ``+ ``+ - `C`+"\n"+``+ + `C`+"\n"+``+ ``+ ``+ ``+ @@ -979,11 +976,11 @@ func TestRender_FilePreview(t *testing.T) { ``+ ``+ ``+ - `B`+"\n"+``+ + `B`+"\n"+``+ ``+ ``+ ``+ - `C`+"\n"+``+ + `C`+"\n"+``+ ``+ ``+ ``+ @@ -1004,11 +1001,11 @@ func TestRender_FilePreview(t *testing.T) { ``+ ``+ ``+ - `B`+"\n"+``+ + `B`+"\n"+``+ ``+ ``+ ``+ - `C`+"\n"+``+ + `C`+"\n"+``+ ``+ ``+ ``+ @@ -1029,11 +1026,11 @@ func TestRender_FilePreview(t *testing.T) { ``+ ``+ ``+ - `B`+"\n"+``+ + `B`+"\n"+``+ ``+ ``+ ``+ - `C`+"\n"+``+ + `C`+"\n"+``+ ``+ ``+ ``+ @@ -1112,39 +1109,6 @@ func TestRender_FilePreview(t *testing.T) { ) }) - t.Run("rendered file with lines L1-2 instead of L1-L2", func(t *testing.T) { - testRender( - commitFileURL+"#L1-2", - `

`+ - `
`+ - `
`+ - `
`+ - `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) { @@ -1165,11 +1129,11 @@ func TestRender_FilePreview(t *testing.T) { ``+ ``+ ``+ - `B`+"\n"+``+ + `B`+"\n"+``+ ``+ ``+ ``+ - `C`+"\n"+``+ + `C`+"\n"+``+ ``+ ``+ ``+ diff --git a/modules/markup/markdown/convertyaml.go b/modules/markup/markdown/convertyaml.go index 8e5a49d931..1675b68be2 100644 --- a/modules/markup/markdown/convertyaml.go +++ b/modules/markup/markdown/convertyaml.go @@ -6,7 +6,7 @@ package markdown import ( "github.com/yuin/goldmark/ast" east "github.com/yuin/goldmark/extension/ast" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) func nodeToTable(meta *yaml.Node) ast.Node { diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 8a3da3b08f..d229afa8e3 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -9,8 +9,6 @@ import ( "strings" "forgejo.org/modules/markup" - "forgejo.org/modules/markup/common" - markdownutil "forgejo.org/modules/markup/markdown/util" "forgejo.org/modules/setting" "github.com/yuin/goldmark/ast" @@ -37,8 +35,8 @@ func (g *ASTTransformer) applyElementDir(n ast.Node) { func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) { firstChild := node.FirstChild() tocMode := "" - ctx := pc.Get(markdownutil.RenderContextKey).(*markup.RenderContext) - rc := pc.Get(markdownutil.RenderConfigKey).(*RenderConfig) + ctx := pc.Get(renderContextKey).(*markup.RenderContext) + rc := pc.Get(renderConfigKey).(*RenderConfig) tocList := make([]markup.Header, 0, 20) if rc.yamlNode != nil { @@ -75,18 +73,6 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa } case *ast.CodeSpan: g.transformCodeSpan(ctx, v, reader) - case *common.Footnote: - if scope, found := ctx.Metas["scope"]; found { - v.Name = fmt.Appendf(v.Name, "-%s", scope) - } - case *common.FootnoteLink: - if scope, found := ctx.Metas["scope"]; found { - v.Name = fmt.Appendf(v.Name, "-%s", scope) - } - case *common.FootnoteBackLink: - if scope, found := ctx.Metas["scope"]; found { - v.Name = fmt.Appendf(v.Name, "-%s", scope) - } } return ast.WalkContinue, nil }) diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index 2b19e0f1c9..e811d29994 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -16,7 +16,6 @@ import ( "forgejo.org/modules/markup/common" "forgejo.org/modules/markup/markdown/callout" "forgejo.org/modules/markup/markdown/math" - markdownutil "forgejo.org/modules/markup/markdown/util" "forgejo.org/modules/setting" giteautil "forgejo.org/modules/util" @@ -35,6 +34,11 @@ var ( specMarkdownOnce sync.Once ) +var ( + renderContextKey = parser.NewContextKey() + renderConfigKey = parser.NewContextKey() +) + type limitWriter struct { w io.Writer sum int64 @@ -60,7 +64,7 @@ func (l *limitWriter) Write(data []byte) (int, error) { // newParserContext creates a parser.Context with the render context set func newParserContext(ctx *markup.RenderContext) parser.Context { pc := parser.NewContext(parser.WithIDs(newPrefixedIDs())) - pc.Set(markdownutil.RenderContextKey, ctx) + pc.Set(renderContextKey, ctx) return pc } @@ -188,7 +192,7 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer) } rc.metaLength = metaLength - pc.Set(markdownutil.RenderConfigKey, rc) + pc.Set(renderConfigKey, rc) if err := converter.Convert(buf, lw, parser.WithContext(pc)); err != nil { log.Error("Unable to render: %v", err) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 7c13494a67..f7955115e0 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -561,14 +561,6 @@ func TestMathBlock(t *testing.T) { "test $$a$$", `

test a

` + nl, }, - { - `\[ -[\triangle ABC] = \sqrt{s(s-a)(s-b)(s-c)} -\]`, - `

[
-[\triangle ABC] = \sqrt{s(s-a)(s-b)(s-c)}
-]

` + nl, - }, } for _, test := range testcases { @@ -576,32 +568,6 @@ func TestMathBlock(t *testing.T) { require.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase) } - - t.Run("Wiki context", func(t *testing.T) { - testcases := []struct { - testcase string - expected string - }{ - { - "$a$", - `

a

` + nl, - }, - { - `\[ -[\triangle ABC] = \sqrt{s(s-a)(s-b)(s-c)} -\]`, - `

-[\triangle ABC] = \sqrt{s(s-a)(s-b)(s-c)}
-
` + nl, - }, - } - - for _, test := range testcases { - res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext, IsWiki: true}, test.testcase) - require.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) - assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase) - } - }) } func TestFootnote(t *testing.T) { @@ -802,49 +768,6 @@ Citation needed[^0].`, } } -func TestFootnoteWithScope(t *testing.T) { - testcases := []struct { - testcase string - expected string - }{ - { - `Citation needed[^0]. -[^0]: Source`, - `

Citation needed1.

-
-
-
    -
  1. -

    Source โ†ฉ๏ธŽ

    -
  2. -
-
-`, - }, { - `[^0]: Source - -Citation needed[^0].`, - `

Citation needed1.

-
-
-
    -
  1. -

    Source โ†ฉ๏ธŽ

    -
  2. -
-
-`, - }, - } - - for _, test := range testcases { - metas := map[string]string{"scope": "comment-999"} - res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext, Metas: metas}, test.testcase) - require.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) - assert.Equal(t, test.expected, string(res), "Unexpected result in testcase %q", test.testcase) - } -} - func TestTaskList(t *testing.T) { testcases := []struct { testcase string @@ -882,27 +805,6 @@ foo: bar } } -func TestRenderCheckList(t *testing.T) { - input := `- [ ] a -- [x] b -1. [x] a -2. [ ] b -5. [ ] e` - expected := `
    -
  • a
  • -
  • b
  • -
-
    -
  1. a
  2. -
  3. b
  4. -
  5. e
  6. -
-` - res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, input) - require.NoError(t, err) - assert.Equal(t, template.HTML(expected), res) -} - func TestRenderLinks(t *testing.T) { input := ` space @mention-user${SPACE}${SPACE} /just/a/path.bin diff --git a/modules/markup/markdown/math/block_parser.go b/modules/markup/markdown/math/block_parser.go index b0fe1d588a..527df84975 100644 --- a/modules/markup/markdown/math/block_parser.go +++ b/modules/markup/markdown/math/block_parser.go @@ -6,9 +6,6 @@ package math import ( "bytes" - "forgejo.org/modules/markup" - markdownutil "forgejo.org/modules/markup/markdown/util" - "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/text" @@ -64,13 +61,6 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex return node, parser.Close | parser.NoChildren } - ctx := pc.Get(markdownutil.RenderContextKey).(*markup.RenderContext) - if ctx.IsWiki { - reader.Advance(segment.Len() - 1) - segment.Start += 2 - node.Lines().Append(segment) - return node, parser.NoChildren - } return nil, parser.NoChildren } diff --git a/modules/markup/markdown/meta.go b/modules/markup/markdown/meta.go index 5bdc680e9e..e76b253ecd 100644 --- a/modules/markup/markdown/meta.go +++ b/modules/markup/markdown/meta.go @@ -9,7 +9,7 @@ import ( "unicode" "unicode/utf8" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) func isYAMLSeparator(line []byte) bool { diff --git a/modules/markup/markdown/renderconfig.go b/modules/markup/markdown/renderconfig.go index 8c278137dc..5c3eb1beec 100644 --- a/modules/markup/markdown/renderconfig.go +++ b/modules/markup/markdown/renderconfig.go @@ -10,7 +10,7 @@ import ( "forgejo.org/modules/markup" "github.com/yuin/goldmark/ast" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) // RenderConfig represents rendering configuration for this file diff --git a/modules/markup/markdown/renderconfig_test.go b/modules/markup/markdown/renderconfig_test.go index 478f57443e..c53acdc77a 100644 --- a/modules/markup/markdown/renderconfig_test.go +++ b/modules/markup/markdown/renderconfig_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) func TestRenderConfig_UnmarshalYAML(t *testing.T) { diff --git a/modules/markup/markdown/util/text.go b/modules/markup/markdown/util/text.go index db6e432e79..8a42e5835b 100644 --- a/modules/markup/markdown/util/text.go +++ b/modules/markup/markdown/util/text.go @@ -7,7 +7,6 @@ import ( "bytes" "github.com/yuin/goldmark/ast" - "github.com/yuin/goldmark/parser" ) func textOfChildren(n ast.Node, src []byte, b *bytes.Buffer) { @@ -25,8 +24,3 @@ func Text(n ast.Node, src []byte) []byte { textOfChildren(n, src, &b) return b.Bytes() } - -var ( - RenderContextKey = parser.NewContextKey() - RenderConfigKey = parser.NewContextKey() -) diff --git a/modules/markup/orgmode/orgmode_test.go b/modules/markup/orgmode/orgmode_test.go index 71157dc7c7..cdaa9f18ce 100644 --- a/modules/markup/orgmode/orgmode_test.go +++ b/modules/markup/orgmode/orgmode_test.go @@ -152,9 +152,9 @@ func HelloWorld() { } #+end_src `, `
-
// HelloWorld prints "Hello World"
-func HelloWorld() {
-	fmt.Println("Hello World")
-}
+
// HelloWorld prints "Hello World"
+func HelloWorld() {
+	fmt.Println("Hello World")
+}
`) } diff --git a/modules/markup/renderer.go b/modules/markup/renderer.go index 08502e12ab..a622d75085 100644 --- a/modules/markup/renderer.go +++ b/modules/markup/renderer.go @@ -248,14 +248,15 @@ type nopCloser struct { func (nopCloser) Close() error { return nil } func renderIFrame(ctx *RenderContext, output io.Writer) error { - // set height="300", otherwise if the postMessage mechanism breaks, we are left with a 0-height iframe + // set height="0" ahead, otherwise the scrollHeight would be max(150, realHeight) // at the moment, only "allow-scripts" is allowed for sandbox mode. // "allow-same-origin" should never be used, it leads to XSS attack, and it makes the JS in iframe can access parent window's config and CSRF token // TODO: when using dark theme, if the rendered content doesn't have proper style, the default text color is black, which is not easy to read _, err := io.WriteString(output, fmt.Sprintf(` `, setting.AppSubURL, @@ -316,12 +317,6 @@ func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Wr if err1 := renderer.Render(ctx, input, pw); err1 != nil { return err1 } - - if r, ok := renderer.(ExternalRenderer); ok && r.DisplayInIFrame() { - // Append a short script to the iframe's contents, which will communicate the scroll height of the embedded document via postMessage, either once loaded (in case the containing page loads first) in response to a postMessage from external.js, in case the iframe loads first - // We use '*' as a target origin for postMessage, because can be certain we are embedded on the same domain, due to X-Frame-Options configured elsewhere. (Plus, the offsetHeight of an embedded document is likely not sensitive data anyway.) - _, _ = pw.Write([]byte("")) - } _ = pw.Close() wg.Wait() diff --git a/modules/migration/file_format.go b/modules/migration/file_format.go index af5f806444..8851ad6de7 100644 --- a/modules/migration/file_format.go +++ b/modules/migration/file_format.go @@ -13,7 +13,7 @@ import ( "forgejo.org/modules/log" "github.com/santhosh-tekuri/jsonschema/v6" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) // Load project data from file, with optional validation diff --git a/modules/optional/serialization.go b/modules/optional/serialization.go index 2e2ccd6786..86c1c97341 100644 --- a/modules/optional/serialization.go +++ b/modules/optional/serialization.go @@ -6,7 +6,7 @@ package optional import ( "forgejo.org/modules/json" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) func (o *Option[T]) UnmarshalJSON(data []byte) error { diff --git a/modules/optional/serialization_test.go b/modules/optional/serialization_test.go index 5da0923a78..14bf3b7814 100644 --- a/modules/optional/serialization_test.go +++ b/modules/optional/serialization_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) type testSerializationStruct struct { diff --git a/modules/packages/arch/metadata.go b/modules/packages/arch/metadata.go index ca352c828c..f967bd25a0 100644 --- a/modules/packages/arch/metadata.go +++ b/modules/packages/arch/metadata.go @@ -7,7 +7,6 @@ import ( "archive/tar" "bufio" "bytes" - "context" "encoding/hex" "errors" "fmt" @@ -20,7 +19,7 @@ import ( "forgejo.org/modules/util" "forgejo.org/modules/validation" - "github.com/mholt/archives" + "github.com/mholt/archiver/v3" ) // Arch Linux Packages @@ -110,61 +109,55 @@ func ParsePackage(r *packages.HashedBuffer) (*Package, error) { return nil, err } - var tarball archives.Extractor + var tarball archiver.Reader var tarballType string if bytes.Equal(header[:len(magicZSTD)], magicZSTD) { tarballType = "zst" - tarball = archives.CompressedArchive{ - Compression: archives.Zstd{}, - Extraction: archives.Tar{}, - } + tarball = archiver.NewTarZstd() } else if bytes.Equal(header[:len(magicXZ)], magicXZ) { tarballType = "xz" - tarball = archives.CompressedArchive{ - Compression: archives.Xz{}, - Extraction: archives.Tar{}, - } + tarball = archiver.NewTarXz() } else if bytes.Equal(header[:len(magicGZ)], magicGZ) { tarballType = "gz" - tarball = archives.CompressedArchive{ - Compression: archives.Gz{}, - Extraction: archives.Tar{}, - } + tarball = archiver.NewTarGz() } else { return nil, errors.New("not supported compression") } + err = tarball.Open(r, 0) + if err != nil { + return nil, err + } + defer tarball.Close() var pkg *Package var mTree bool files := make([]string, 0) - err = tarball.Extract(context.TODO(), r, func(ctx context.Context, file archives.FileInfo) error { + for { + f, err := tarball.Read() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } // ref:https://gitlab.archlinux.org/pacman/pacman/-/blob/91546004903eea5d5267d59898a6029ba1d64031/lib/libalpm/add.c#L529-L533 - if !strings.HasPrefix(file.Name(), ".") { - files = append(files, (file.Header.(*tar.Header)).Name) + if !strings.HasPrefix(f.Name(), ".") { + files = append(files, (f.Header.(*tar.Header)).Name) } - switch file.Name() { + switch f.Name() { case ".PKGINFO": - f, err := file.Open() - if err != nil { - return err - } - defer f.Close() - pkg, err = ParsePackageInfo(tarballType, f) if err != nil { - return err + _ = f.Close() + return nil, err } case ".MTREE": mTree = true } - - return nil - }) - if err != nil { - return nil, err + _ = f.Close() } if pkg == nil { diff --git a/modules/packages/arch/metadata_test.go b/modules/packages/arch/metadata_test.go index fbdc9e5ddc..16c1c1637d 100644 --- a/modules/packages/arch/metadata_test.go +++ b/modules/packages/arch/metadata_test.go @@ -5,7 +5,7 @@ package arch import ( "bytes" - "io/fs" + "errors" "os" "strings" "testing" @@ -14,7 +14,7 @@ import ( "forgejo.org/modules/packages" - "github.com/mholt/archives" + "github.com/mholt/archiver/v3" "github.com/stretchr/testify/require" ) @@ -25,7 +25,7 @@ pkgbase = b pkgver = 1-2 arch = x86_64 ` - mapfs := fstest.MapFS{ + fs := fstest.MapFS{ "pkginfo": &fstest.MapFile{ Data: []byte(PKGINFO), Mode: os.ModePerm, @@ -39,111 +39,65 @@ arch = x86_64 } // Test .PKGINFO file - pinf, err := mapfs.Stat("pkginfo") + pinf, err := fs.Stat("pkginfo") + require.NoError(t, err) + + pfile, err := fs.Open("pkginfo") + require.NoError(t, err) + + parcname, err := archiver.NameInArchive(pinf, ".PKGINFO", ".PKGINFO") require.NoError(t, err) // Test .MTREE file - minf, err := mapfs.Stat("mtree") + minf, err := fs.Stat("mtree") require.NoError(t, err) - files := []archives.FileInfo{ - { - FileInfo: pinf, - NameInArchive: ".PKGINFO", - Open: func() (fs.File, error) { - return mapfs.Open("pkginfo") + mfile, err := fs.Open("mtree") + require.NoError(t, err) + + marcname, err := archiver.NameInArchive(minf, ".MTREE", ".MTREE") + require.NoError(t, err) + + t.Run("normal archive", func(t *testing.T) { + var buf bytes.Buffer + + archive := archiver.NewTarZstd() + archive.Create(&buf) + + err = archive.Write(archiver.File{ + FileInfo: archiver.FileInfo{ + FileInfo: pinf, + CustomName: parcname, }, - }, - { - FileInfo: minf, - NameInArchive: ".MTREE", - Open: func() (fs.File, error) { - return mapfs.Open("mtree") + ReadCloser: pfile, + }) + require.NoError(t, errors.Join(pfile.Close(), err)) + + err = archive.Write(archiver.File{ + FileInfo: archiver.FileInfo{ + FileInfo: minf, + CustomName: marcname, }, - }, - } - - t.Run("normal zst archive", func(t *testing.T) { - var buf bytes.Buffer - archive := archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Zstd{}, - } - archive.Archive(t.Context(), &buf, files) + ReadCloser: mfile, + }) + require.NoError(t, errors.Join(mfile.Close(), archive.Close(), err)) reader, err := packages.CreateHashedBufferFromReader(&buf) - require.NoError(t, err) - defer reader.Close() - pkg, err := ParsePackage(reader) - - require.Equal(t, "zst", pkg.CompressType) - require.Equal(t, "a", pkg.Name) - require.Equal(t, "b", pkg.VersionMetadata.Base) - require.Equal(t, "x86_64", pkg.FileMetadata.Arch) - require.Equal(t, "1-2", pkg.Version) - - require.NoError(t, err) - }) - - t.Run("normal xz archive", func(t *testing.T) { - var buf bytes.Buffer - archive := archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Xz{}, + if err != nil { + t.Fatal(err) } - archive.Archive(t.Context(), &buf, files) - - reader, err := packages.CreateHashedBufferFromReader(&buf) - require.NoError(t, err) defer reader.Close() - pkg, err := ParsePackage(reader) - - require.Equal(t, "xz", pkg.CompressType) - require.Equal(t, "a", pkg.Name) - require.Equal(t, "b", pkg.VersionMetadata.Base) - require.Equal(t, "x86_64", pkg.FileMetadata.Arch) - require.Equal(t, "1-2", pkg.Version) - - require.NoError(t, err) - }) - - t.Run("normal gz archive", func(t *testing.T) { - var buf bytes.Buffer - archive := archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Gz{}, - } - archive.Archive(t.Context(), &buf, files) - - reader, err := packages.CreateHashedBufferFromReader(&buf) - require.NoError(t, err) - defer reader.Close() - pkg, err := ParsePackage(reader) - - require.Equal(t, "gz", pkg.CompressType) - require.Equal(t, "a", pkg.Name) - require.Equal(t, "b", pkg.VersionMetadata.Base) - require.Equal(t, "x86_64", pkg.FileMetadata.Arch) - require.Equal(t, "1-2", pkg.Version) + _, err = ParsePackage(reader) require.NoError(t, err) }) t.Run("missing .PKGINFO", func(t *testing.T) { var buf bytes.Buffer - archive := archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Zstd{}, - } - archive.Archive(t.Context(), &buf, []archives.FileInfo{ - { - FileInfo: minf, - NameInArchive: ".MTREE", - Open: func() (fs.File, error) { - return mapfs.Open("mtree") - }, - }, - }) + + archive := archiver.NewTarZstd() + archive.Create(&buf) + require.NoError(t, archive.Close()) reader, err := packages.CreateHashedBufferFromReader(&buf) require.NoError(t, err) @@ -157,20 +111,21 @@ arch = x86_64 t.Run("missing .MTREE", func(t *testing.T) { var buf bytes.Buffer - archive := archives.CompressedArchive{ - Archival: archives.Tar{}, - Compression: archives.Zstd{}, - } - archive.Archive(t.Context(), &buf, []archives.FileInfo{ - { - FileInfo: pinf, - NameInArchive: ".PKGINFO", - Open: func() (fs.File, error) { - return mapfs.Open("pkginfo") - }, - }, - }) + pfile, err := fs.Open("pkginfo") + require.NoError(t, err) + + archive := archiver.NewTarZstd() + archive.Create(&buf) + + err = archive.Write(archiver.File{ + FileInfo: archiver.FileInfo{ + FileInfo: pinf, + CustomName: parcname, + }, + ReadCloser: pfile, + }) + require.NoError(t, errors.Join(pfile.Close(), archive.Close(), err)) reader, err := packages.CreateHashedBufferFromReader(&buf) require.NoError(t, err) diff --git a/modules/packages/debian/metadata.go b/modules/packages/debian/metadata.go index 1729a2206e..e44801654b 100644 --- a/modules/packages/debian/metadata.go +++ b/modules/packages/debian/metadata.go @@ -46,7 +46,7 @@ var ( // https://www.debian.org/doc/debian-policy/ch-controlfields.html#source namePattern = regexp.MustCompile(`\A[a-z0-9][a-z0-9+-.]+\z`) // https://www.debian.org/doc/debian-policy/ch-controlfields.html#version - versionPattern = regexp.MustCompile(`\A(?:[1-9]?[0-9]:)?[a-zA-Z0-9.+~]+(?:-[a-zA-Z0-9.+-~]+)?\z`) + versionPattern = regexp.MustCompile(`\A(?:[0-9]:)?[a-zA-Z0-9.+~]+(?:-[a-zA-Z0-9.+-~]+)?\z`) ) type Package struct { diff --git a/modules/packages/debian/metadata_test.go b/modules/packages/debian/metadata_test.go index 079b9c19c8..cfcbc57ee0 100644 --- a/modules/packages/debian/metadata_test.go +++ b/modules/packages/debian/metadata_test.go @@ -167,14 +167,6 @@ func TestParseControlFile(t *testing.T) { require.ErrorIs(t, err, ErrInvalidArchitecture) }) - t.Run("ValidVersionEpoch", func(t *testing.T) { - for _, version := range []string{"0:1.2.3-test", "1:1.2.3-test", "9:1.2.3-test", "10:1.2.3-test", "37:1.2.3-test", "99:1.2.3-test"} { - p, err := ParseControlFile(buildContent(packageName, version, packageArchitecture)) - require.NoError(t, err) - assert.NotNil(t, p) - } - }) - t.Run("Valid", func(t *testing.T) { content := buildContent(packageName, packageVersion, packageArchitecture) full := content.String() diff --git a/modules/packages/helm/metadata.go b/modules/packages/helm/metadata.go index 4d3eaaa40c..19a30c5ffa 100644 --- a/modules/packages/helm/metadata.go +++ b/modules/packages/helm/metadata.go @@ -13,7 +13,7 @@ import ( "forgejo.org/modules/validation" "github.com/hashicorp/go-version" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) var ( diff --git a/modules/packages/pub/metadata.go b/modules/packages/pub/metadata.go index e1d4286f97..f8afdf7218 100644 --- a/modules/packages/pub/metadata.go +++ b/modules/packages/pub/metadata.go @@ -14,7 +14,7 @@ import ( "forgejo.org/modules/validation" "github.com/hashicorp/go-version" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) var ( diff --git a/modules/packages/rubygems/metadata.go b/modules/packages/rubygems/metadata.go index 9d3fd18f12..6d021a17ab 100644 --- a/modules/packages/rubygems/metadata.go +++ b/modules/packages/rubygems/metadata.go @@ -13,7 +13,7 @@ import ( "forgejo.org/modules/util" "forgejo.org/modules/validation" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) var ( diff --git a/modules/private/hook.go b/modules/private/hook.go index 89d44119ea..2d64c1dec9 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -11,7 +11,6 @@ import ( "forgejo.org/modules/git" "forgejo.org/modules/git/pushoptions" - "forgejo.org/modules/log" "forgejo.org/modules/repository" "forgejo.org/modules/setting" ) @@ -47,7 +46,7 @@ func (o *HookOptions) GetGitPushOptions() pushoptions.Interface { // SSHLogOption ssh log options type SSHLogOption struct { - Level log.Level + IsError bool Message string } @@ -122,9 +121,9 @@ func SetDefaultBranch(ctx context.Context, ownerName, repoName, branch string) R } // SSHLog sends ssh error log response -func SSHLog(ctx context.Context, level log.Level, msg string) error { +func SSHLog(ctx context.Context, isErr bool, msg string) error { reqURL := setting.LocalURL + "api/internal/ssh/log" - req := newInternalRequest(ctx, reqURL, "POST", &SSHLogOption{Level: level, Message: msg}) + req := newInternalRequest(ctx, reqURL, "POST", &SSHLogOption{IsError: isErr, Message: msg}) _, extra := requestJSONResp(req, &ResponseText{}) return extra.Error } diff --git a/modules/setting/config_provider.go b/modules/setting/config_provider.go index 6325199637..19f3b9008a 100644 --- a/modules/setting/config_provider.go +++ b/modules/setting/config_provider.go @@ -6,7 +6,6 @@ package setting import ( "errors" "fmt" - "math" "os" "path/filepath" "strconv" @@ -16,7 +15,6 @@ import ( "forgejo.org/modules/log" "forgejo.org/modules/util" - "github.com/dustin/go-humanize" "gopkg.in/ini.v1" //nolint:depguard ) @@ -322,16 +320,6 @@ func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting any) { } } -// mustBytes returns -1 on parse error, or value out of range 0 to math.MaxInt64 -func mustBytes(section ConfigSection, key string) int64 { - value := section.Key(key).String() - bytes, err := humanize.ParseBytes(value) - if err != nil || bytes > math.MaxInt64 { - return -1 - } - return int64(bytes) -} - // DeprecatedWarnings contains the warning message for various deprecations, including: setting option, file/folder, etc var DeprecatedWarnings []string @@ -343,14 +331,6 @@ func deprecatedSetting(rootCfg ConfigProvider, oldSection, oldKey, newSection, n } } -func deprecatedSettingWarning(rootCfg ConfigProvider, oldSection, oldKey, newSection, newKey string) { //nolint:unparam - if rootCfg.Section(oldSection).HasKey(oldKey) { - msg := fmt.Sprintf("Deprecated config option `[%s]` `%s` present. Use `[%s]` `%s` instead.", oldSection, oldKey, newSection, newKey) - log.Error("%v", msg) - DeprecatedWarnings = append(DeprecatedWarnings, msg) - } -} - // deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini func deprecatedSettingDB(rootCfg ConfigProvider, oldSection, oldKey string) { if rootCfg.Section(oldSection).HasKey(oldKey) { diff --git a/modules/setting/config_provider_test.go b/modules/setting/config_provider_test.go index 3588784b81..3b99911f38 100644 --- a/modules/setting/config_provider_test.go +++ b/modules/setting/config_provider_test.go @@ -155,24 +155,3 @@ func TestDisableSaving(t *testing.T) { require.NoError(t, err) assert.Equal(t, "k1 = a\nk2 = y\nk3 = z\n", string(bs)) } - -func TestMustBytes(t *testing.T) { - test := func(value string) int64 { - cfg, err := NewConfigProviderFromData("[test]") - require.NoError(t, err) - sec := cfg.Section("test") - sec.NewKey("VALUE", value) - - return mustBytes(sec, "VALUE") - } - - assert.EqualValues(t, -1, test("")) - assert.EqualValues(t, -1, test("-1")) - assert.EqualValues(t, 0, test("0")) - assert.EqualValues(t, 1, test("1")) - assert.EqualValues(t, 10000, test("10000")) - assert.EqualValues(t, 1000000, test("1 mb")) - assert.EqualValues(t, 1048576, test("1mib")) - assert.EqualValues(t, 1782579, test("1.7mib")) - assert.EqualValues(t, -1, test("1 yib")) // too large -} diff --git a/modules/setting/cron_test.go b/modules/setting/cron_test.go index ba73c4039d..cabfb3a325 100644 --- a/modules/setting/cron_test.go +++ b/modules/setting/cron_test.go @@ -42,56 +42,3 @@ EXTEND = true assert.Equal(t, "white rabbit", extended.Second) assert.True(t, extended.Extend) } - -// Test_getCronSettings2 tests that getCronSettings can not handle two levels of embedding -func Test_getCronSettings2(t *testing.T) { - type BaseStruct struct { - Enabled bool - RunAtStart bool - Schedule string - } - - type Extended struct { - BaseStruct - Extend bool - } - type Extended2 struct { - Extended - Third string - } - - iniStr := ` -[cron.test] -ENABLED = TRUE -RUN_AT_START = TRUE -SCHEDULE = @every 1h -EXTEND = true -THIRD = white rabbit -` - cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) - - extended := &Extended2{ - Extended: Extended{ - BaseStruct: BaseStruct{ - Enabled: false, - RunAtStart: false, - Schedule: "@every 72h", - }, - Extend: false, - }, - Third: "black rabbit", - } - - _, err = getCronSettings(cfg, "test", extended) - require.NoError(t, err) - - // This confirms the first level of embedding works - assert.Equal(t, "white rabbit", extended.Third) - assert.True(t, extended.Extend) - - // This confirms 2 levels of embedding doesn't work - assert.False(t, extended.Enabled) - assert.False(t, extended.RunAtStart) - assert.Equal(t, "@every 72h", extended.Schedule) -} diff --git a/modules/setting/incoming_email.go b/modules/setting/incoming_email.go index a890a4a328..e592220de6 100644 --- a/modules/setting/incoming_email.go +++ b/modules/setting/incoming_email.go @@ -44,14 +44,9 @@ func loadIncomingEmailFrom(rootCfg ConfigProvider) { if sec.HasKey("USER") && !sec.HasKey("USERNAME") { IncomingEmail.Username = sec.Key("USER").String() } - if sec.HasKey("PASSWD") && !sec.HasKey("PASSWORD") { - sec.Key("PASSWORD").SetValue(sec.Key("PASSWD").String()) + IncomingEmail.Password = sec.Key("PASSWD").String() } - if sec.HasKey("PASSWD_URI") && !sec.HasKey("PASSWORD_URI") { - sec.Key("PASSWORD_URI").SetValue(sec.Key("PASSWD_URI").String()) - } - IncomingEmail.Password = loadSecret(sec, "PASSWORD_URI", "PASSWORD") // Infer Port if not set if IncomingEmail.Port == 0 { diff --git a/modules/setting/incoming_email_test.go b/modules/setting/incoming_email_test.go index 4ea740bafd..6d181cae3c 100644 --- a/modules/setting/incoming_email_test.go +++ b/modules/setting/incoming_email_test.go @@ -4,8 +4,6 @@ package setting import ( - "os" - "path/filepath" "testing" "github.com/stretchr/testify/assert" @@ -37,22 +35,6 @@ func Test_loadIncomingEmailFrom(t *testing.T) { assert.Equal(t, "y0u'll n3v3r gUess th1S!!1", IncomingEmail.Password) }) - t.Run("Secrets", func(t *testing.T) { - uri := filepath.Join(t.TempDir(), "email_incoming_password") - - if err := os.WriteFile(uri, []byte("th1S gUess n3v3r y0u'll!!1"), 0o644); err != nil { - t.Fatal(err) - } - - cfg, sec := makeBaseConfig() - sec.NewKey("PASSWORD_URI", "file:"+uri) - - IncomingEmail.Password = "" - loadIncomingEmailFrom(cfg) - - assert.Equal(t, "th1S gUess n3v3r y0u'll!!1", IncomingEmail.Password) - }) - t.Run("Port settings", func(t *testing.T) { t.Run("no port, no tls", func(t *testing.T) { defer resetIncomingEmailPort()() diff --git a/modules/setting/log.go b/modules/setting/log.go index ecc591fd35..0747ac4dac 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -23,6 +23,8 @@ type LogGlobalConfig struct { StacktraceLogLevel log.Level BufferLen int + EnableSSHLog bool + AccessLogTemplate string RequestIDHeaders []string } @@ -45,6 +47,8 @@ func loadLogGlobalFrom(rootCfg ConfigProvider) { } Log.RootPath = util.FilePathJoinAbs(Log.RootPath) + Log.EnableSSHLog = sec.Key("ENABLE_SSH_LOG").MustBool(false) + Log.AccessLogTemplate = sec.Key("ACCESS_LOG_TEMPLATE").MustString(accessLogTemplateDefault) Log.RequestIDHeaders = sec.Key("REQUEST_ID_HEADERS").Strings(",") } @@ -52,83 +56,41 @@ func loadLogGlobalFrom(rootCfg ConfigProvider) { func prepareLoggerConfig(rootCfg ConfigProvider) { sec := rootCfg.Section("log") - // Priority: `LOGGER_DEFAULT_MODE` -> `logger.default.MODE` - deprecatedSettingWarning(rootCfg, "log", "logger.default.MODE", "log", "LOGGER_DEFAULT_MODE") - hasNoValue := !sec.HasKey("LOGGER_DEFAULT_MODE") - if hasNoValue && sec.HasKey("logger.default.MODE") { - sec.Key("LOGGER_DEFAULT_MODE").SetValue(sec.Key("logger.default.MODE").String()) - hasNoValue = false - } - if hasNoValue { - sec.Key("LOGGER_DEFAULT_MODE").SetValue(",") // use default logger + if !sec.HasKey("logger.default.MODE") { + sec.Key("logger.default.MODE").MustString(",") } - // Priority: `ENABLE_ACCESS_LOG` -> `LOGGER_ACCESS_MODE` -> `logger.access.MODE` -> `ACCESS` - deprecatedSettingWarning(rootCfg, "log", "ACCESS", "log", "LOGGER_ACCESS_MODE") - deprecatedSettingWarning(rootCfg, "log", "ENABLE_ACCESS_LOG", "log", "LOGGER_ACCESS_MODE") - deprecatedSettingWarning(rootCfg, "log", "logger.access.MODE", "log", "LOGGER_ACCESS_MODE") - hasNoValue = !sec.HasKey("LOGGER_ACCESS_MODE") - if hasNoValue && sec.HasKey("logger.access.MODE") { - sec.Key("LOGGER_ACCESS_MODE").SetValue(sec.Key("logger.access.MODE").String()) - hasNoValue = false - } - if val := sec.Key("ACCESS").String(); hasNoValue && val != "" { - sec.Key("LOGGER_ACCESS_MODE").SetValue(val) + deprecatedSetting(rootCfg, "log", "ACCESS", "log", "logger.access.MODE", "1.21") + deprecatedSetting(rootCfg, "log", "ENABLE_ACCESS_LOG", "log", "logger.access.MODE", "1.21") + if val := sec.Key("ACCESS").String(); val != "" { + sec.Key("logger.access.MODE").MustString(val) } if sec.HasKey("ENABLE_ACCESS_LOG") && !sec.Key("ENABLE_ACCESS_LOG").MustBool() { - sec.Key("LOGGER_ACCESS_MODE").SetValue("") + sec.Key("logger.access.MODE").SetValue("") } - // Priority: `DISABLE_ROUTER_LOG` -> `LOGGER_ROUTER_MODE` -> `logger.router.MODE` -> `ROUTER` - deprecatedSettingWarning(rootCfg, "log", "ROUTER", "log", "LOGGER_ROUTER_MODE") - deprecatedSettingWarning(rootCfg, "log", "DISABLE_ROUTER_LOG", "log", "LOGGER_ROUTER_MODE") - deprecatedSettingWarning(rootCfg, "log", "logger.router.MODE", "log", "LOGGER_ROUTER_MODE") - hasNoValue = !sec.HasKey("LOGGER_ROUTER_MODE") - if hasNoValue && sec.HasKey("logger.router.MODE") { - sec.Key("LOGGER_ROUTER_MODE").SetValue(sec.Key("logger.router.MODE").String()) - hasNoValue = false + deprecatedSetting(rootCfg, "log", "ROUTER", "log", "logger.router.MODE", "1.21") + deprecatedSetting(rootCfg, "log", "DISABLE_ROUTER_LOG", "log", "logger.router.MODE", "1.21") + if val := sec.Key("ROUTER").String(); val != "" { + sec.Key("logger.router.MODE").MustString(val) } - if val := sec.Key("ROUTER").String(); hasNoValue && val != "" { - sec.Key("LOGGER_ROUTER_MODE").SetValue(val) - hasNoValue = false + if !sec.HasKey("logger.router.MODE") { + sec.Key("logger.router.MODE").MustString(",") // use default logger } if sec.HasKey("DISABLE_ROUTER_LOG") && sec.Key("DISABLE_ROUTER_LOG").MustBool() { - sec.Key("LOGGER_ROUTER_MODE").SetValue("") - hasNoValue = false - } - if hasNoValue { - sec.Key("LOGGER_ROUTER_MODE").SetValue(",") // use default logger + sec.Key("logger.router.MODE").SetValue("") } - // Priority: `ENABLE_XORM_LOG` -> `LOGGER_XORM_MODE` -> `logger.xorm.MODE` -> `XORM` - deprecatedSettingWarning(rootCfg, "log", "XORM", "log", "LOGGER_XORM_MODE") - deprecatedSettingWarning(rootCfg, "log", "ENABLE_XORM_LOG", "log", "LOGGER_XORM_MODE") - deprecatedSettingWarning(rootCfg, "log", "logger.xorm.MODE", "log", "LOGGER_XORM_MODE") - hasNoValue = !sec.HasKey("LOGGER_XORM_MODE") - if hasNoValue && sec.HasKey("logger.xorm.MODE") { - sec.Key("LOGGER_XORM_MODE").SetValue(sec.Key("logger.xorm.MODE").String()) - hasNoValue = false + deprecatedSetting(rootCfg, "log", "XORM", "log", "logger.xorm.MODE", "1.21") + deprecatedSetting(rootCfg, "log", "ENABLE_XORM_LOG", "log", "logger.xorm.MODE", "1.21") + if val := sec.Key("XORM").String(); val != "" { + sec.Key("logger.xorm.MODE").MustString(val) } - if val := sec.Key("XORM").String(); hasNoValue && val != "" { - sec.Key("LOGGER_XORM_MODE").SetValue(val) - hasNoValue = false + if !sec.HasKey("logger.xorm.MODE") { + sec.Key("logger.xorm.MODE").MustString(",") // use default logger } if sec.HasKey("ENABLE_XORM_LOG") && !sec.Key("ENABLE_XORM_LOG").MustBool() { - sec.Key("LOGGER_XORM_MODE").SetValue("") - hasNoValue = false - } - if hasNoValue { - sec.Key("LOGGER_XORM_MODE").SetValue(",") // use default logger - } - - // Priority: `LOGGER_SSH_MODE` -> `ENABLE_SSH_LOG` - deprecatedSettingWarning(rootCfg, "log", "ENABLE_SSH_LOG", "log", "LOGGER_SSH_MODE") - if !sec.HasKey("LOGGER_SSH_MODE") && sec.HasKey("ENABLE_SSH_LOG") { - if sec.Key("ENABLE_SSH_LOG").MustBool() { - sec.Key("LOGGER_SSH_MODE").SetValue(",") // use default logger - } else { - sec.Key("LOGGER_SSH_MODE").SetValue("") // disable ssh logger - } + sec.Key("logger.xorm.MODE").SetValue("") } } @@ -171,7 +133,6 @@ func loadLogModeByName(rootCfg ConfigProvider, loggerName, modeName string) (wri writerMode.StacktraceLevel = log.LevelFromString(ConfigInheritedKeyString(sec, "STACKTRACE_LEVEL", Log.StacktraceLogLevel.String())) writerMode.Prefix = ConfigInheritedKeyString(sec, "PREFIX") writerMode.Expression = ConfigInheritedKeyString(sec, "EXPRESSION") - writerMode.Exclusion = ConfigInheritedKeyString(sec, "EXCLUSION") // flags are updated and set below switch writerType { @@ -251,19 +212,18 @@ func initManagedLoggers(manager *log.LoggerManager, cfg ConfigProvider) { initLoggerByName(manager, cfg, "access") initLoggerByName(manager, cfg, "router") initLoggerByName(manager, cfg, "xorm") - initLoggerByName(manager, cfg, "ssh") } func initLoggerByName(manager *log.LoggerManager, rootCfg ConfigProvider, loggerName string) { sec := rootCfg.Section("log") - key := "LOGGER_" + strings.ToUpper(loggerName) + "_MODE" + keyPrefix := "logger." + loggerName - disabled := sec.HasKey(key) && sec.Key(key).String() == "" + disabled := sec.HasKey(keyPrefix+".MODE") && sec.Key(keyPrefix+".MODE").String() == "" if disabled { return } - modeVal := sec.Key(key).String() + modeVal := sec.Key(keyPrefix + ".MODE").String() if modeVal == "," { modeVal = Log.Mode } diff --git a/modules/setting/log_test.go b/modules/setting/log_test.go index 1e523d50d7..eda6dc36af 100644 --- a/modules/setting/log_test.go +++ b/modules/setting/log_test.go @@ -10,13 +10,16 @@ import ( "forgejo.org/modules/json" "forgejo.org/modules/log" - "forgejo.org/modules/test" "github.com/stretchr/testify/require" ) func initLoggersByConfig(t *testing.T, config string) (*log.LoggerManager, func()) { - defer test.MockVariableValue(&Log, LogGlobalConfig{})() + oldLogConfig := Log + Log = LogGlobalConfig{} + defer func() { + Log = oldLogConfig + }() cfg, err := NewConfigProviderFromData(config) require.NoError(t, err) @@ -26,17 +29,6 @@ func initLoggersByConfig(t *testing.T, config string) (*log.LoggerManager, func( return manager, manager.Close } -func initLoggerConfig(t *testing.T, config string) ConfigProvider { - defer test.MockVariableValue(&Log, LogGlobalConfig{})() - - cfg, err := NewConfigProviderFromData(config) - require.NoError(t, err) - - prepareLoggerConfig(cfg) - - return cfg -} - func toJSON(v any) string { b, _ := json.MarshalIndent(v, "", "\t") return string(b) @@ -52,7 +44,6 @@ func TestLogConfigDefault(t *testing.T) { "BufferLen": 10000, "Colorize": false, "Expression": "", - "Exclusion": "", "Flags": "stdflags", "Level": "info", "Prefix": "", @@ -92,7 +83,6 @@ logger.xorm.MODE = "BufferLen": 10000, "Colorize": false, "Expression": "", - "Exclusion": "", "Flags": "stdflags", "Level": "info", "Prefix": "", @@ -131,7 +121,6 @@ MODE = console "BufferLen": 10000, "Colorize": false, "Expression": "", - "Exclusion": "", "Flags": "stdflags", "Level": "info", "Prefix": "", @@ -179,7 +168,6 @@ ACCESS = file "BufferLen": 10000, "Colorize": false, "Expression": "", - "Exclusion": "", "Flags": "stdflags", "Level": "info", "Prefix": "", @@ -203,7 +191,6 @@ ACCESS = file "BufferLen": 10000, "Colorize": false, "Expression": "", - "Exclusion": "", "Flags": "none", "Level": "info", "Prefix": "", @@ -251,8 +238,8 @@ ENABLE_ACCESS_LOG = false func TestLogConfigNewConfig(t *testing.T) { manager, managerClose := initLoggersByConfig(t, ` [log] -LOGGER_ACCESS_MODE = console -LOGGER_XORM_MODE = console, console-1 +logger.access.MODE = console +logger.xorm.MODE = console, console-1 [log.console] LEVEL = warn @@ -270,7 +257,6 @@ STDERR = true "BufferLen": 10000, "Colorize": false, "Expression": "", - "Exclusion": "", "Flags": "stdflags", "Level": "warn", "Prefix": "", @@ -284,7 +270,6 @@ STDERR = true "BufferLen": 10000, "Colorize": false, "Expression": "", - "Exclusion": "", "Flags": "stdflags", "Level": "error", "Prefix": "", @@ -302,7 +287,6 @@ STDERR = true "BufferLen": 10000, "Colorize": false, "Expression": "", - "Exclusion": "", "Flags": "none", "Level": "warn", "Prefix": "", @@ -339,7 +323,6 @@ MODE = file LEVEL = error STACKTRACE_LEVEL = fatal EXPRESSION = filter -EXCLUSION = not FLAGS = medfile PREFIX = "[Prefix] " FILE_NAME = file-xxx.log @@ -358,7 +341,6 @@ COMPRESSION_LEVEL = 4 "BufferLen": 10, "Colorize": false, "Expression": "", - "Exclusion": "", "Flags": "stdflags", "Level": "info", "Prefix": "", @@ -378,7 +360,6 @@ COMPRESSION_LEVEL = 4 "BufferLen": 10, "Colorize": false, "Expression": "filter", - "Exclusion": "not", "Flags": "medfile", "Level": "error", "Prefix": "[Prefix] ", @@ -403,216 +384,3 @@ COMPRESSION_LEVEL = 4 expected = strings.ReplaceAll(expected, "$FILENAME-1", tempPath("file-xxx.log")) require.JSONEq(t, expected, toJSON(dump)) } - -func TestLegacyLoggerMigrations(t *testing.T) { - type Cases = []struct { - name string - cfg string - exp string - } - - runCases := func(t *testing.T, key string, cases Cases) { - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - cfg := initLoggerConfig(t, c.cfg) - require.Equal(t, c.exp, cfg.Section("log").Key(key).String()) - }) - } - } - - t.Run("default", func(t *testing.T) { - runCases(t, "LOGGER_DEFAULT_MODE", Cases{ - { - "uses default value for default logger", - "", - ",", - }, - { - "uses logger.default.MODE for default logger", - `[log] -logger.default.MODE = file -`, - "file", - }, - }) - }) - - t.Run("access", func(t *testing.T) { - runCases(t, "LOGGER_ACCESS_MODE", Cases{ - { - "uses default value for access logger", - "", - "", - }, - { - "uses ACCESS for access logger", - `[log] -ACCESS = file -`, - "file", - }, - { - "ENABLE_ACCESS_LOG=true doesn't change access logger", - `[log] -ENABLE_ACCESS_LOG = true -logger.access.MODE = console -`, - "console", - }, - { - "ENABLE_ACCESS_LOG=false disables access logger", - `[log] -ENABLE_ACCESS_LOG = false -logger.access.MODE = console -`, - "", - }, - { - "logger.access.MODE has precedence over ACCESS for access logger", - `[log] -ACCESS = file -logger.access.MODE = console -`, - "console", - }, - { - "LOGGER_ACCESS_MODE has precedence over logger.access.MODE for access logger", - `[log] -LOGGER_ACCESS_MODE = file -logger.access.MODE = console -`, - "file", - }, - { - "ENABLE_ACCESS_LOG doesn't enable access logger", - `[log] -ENABLE_ACCESS_LOG = true -`, - "", // should be `,` - }, - }) - }) - - t.Run("router", func(t *testing.T) { - runCases(t, "LOGGER_ROUTER_MODE", Cases{ - { - "uses default value for router logger", - "", - ",", - }, - { - "uses ROUTER for router logger", - `[log] -ROUTER = file -`, - "file", - }, - { - "DISABLE_ROUTER_LOG=false doesn't change router logger", - `[log] -ROUTER = file -DISABLE_ROUTER_LOG = false -`, - "file", - }, - { - "DISABLE_ROUTER_LOG=true disables router logger", - `[log] -DISABLE_ROUTER_LOG = true -logger.router.MODE = console -`, - "", - }, - { - "logger.router.MODE as precedence over ROUTER for router logger", - `[log] -ROUTER = file -logger.router.MODE = console -`, - "console", - }, - { - "LOGGER_ROUTER_MODE has precedence over logger.router.MODE for router logger", - `[log] -LOGGER_ROUTER_MODE = file -logger.router.MODE = console -`, - "file", - }, - }) - }) - - t.Run("xorm", func(t *testing.T) { - runCases(t, "LOGGER_XORM_MODE", Cases{ - { - "uses default value for xorm logger", - "", - ",", - }, - { - "uses XORM for xorm logger", - `[log] -XORM = file -`, - "file", - }, - { - "ENABLE_XORM_LOG=true doesn't change xorm logger", - `[log] -ENABLE_XORM_LOG = true -logger.xorm.MODE = console -`, - "console", - }, - { - "ENABLE_XORM_LOG=false disables xorm logger", - `[log] -ENABLE_XORM_LOG = false -logger.xorm.MODE = console -`, - "", - }, - { - "logger.xorm.MODE has precedence over XORM for xorm logger", - `[log] -XORM = file -logger.xorm.MODE = console -`, - "console", - }, - { - "LOGGER_XORM_MODE has precedence over logger.xorm.MODE for xorm logger", - `[log] -LOGGER_XORM_MODE = file -logger.xorm.MODE = console -`, - "file", - }, - }) - }) - - t.Run("ssh", func(t *testing.T) { - runCases(t, "LOGGER_SSH_MODE", Cases{ - { - "uses default value for ssh logger", - "", - "", - }, - { - "deprecated config can enable logger", - `[log] -ENABLE_SSH_LOG = true -`, - ",", - }, - { - "check priority", - `[log] -LOGGER_SSH_MODE = file -ENABLE_SSH_LOG = true -`, - "file", - }, - }) - }) -} diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index b43484a90f..9c004c6ce0 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -147,10 +147,6 @@ func loadMailerFrom(rootCfg ConfigProvider) { if sec.HasKey("PASSWORD") && !sec.HasKey("PASSWD") { sec.Key("PASSWD").SetValue(sec.Key("PASSWORD").String()) } - if sec.HasKey("PASSWORD_URI") && !sec.HasKey("PASSWD_URI") { - sec.Key("PASSWD_URI").SetValue(sec.Key("PASSWORD_URI").String()) - } - sec.Key("PASSWD").SetValue(loadSecret(sec, "PASSWD_URI", "PASSWD")) // Set default values & validate sec.Key("NAME").MustString(AppName) diff --git a/modules/setting/mailer_test.go b/modules/setting/mailer_test.go index 47eaf3ffbb..4523cc91dd 100644 --- a/modules/setting/mailer_test.go +++ b/modules/setting/mailer_test.go @@ -4,8 +4,6 @@ package setting import ( - "os" - "path/filepath" "testing" "github.com/stretchr/testify/assert" @@ -54,24 +52,6 @@ func Test_loadMailerFrom(t *testing.T) { assert.Equal(t, "y0u'll n3v3r gUess th1S!!1", MailService.Passwd) }) - t.Run("Secrets", func(t *testing.T) { - uri := filepath.Join(t.TempDir(), "mailer_passwd") - - if err := os.WriteFile(uri, []byte("th1S gUess n3v3r y0u'll!!1"), 0o644); err != nil { - t.Fatal(err) - } - - cfg, _ := NewConfigProviderFromData("") - sec := cfg.Section("mailer") - sec.NewKey("ENABLED", "true") - sec.NewKey("PASSWD_URI", "file:"+uri) - - MailService.Passwd = "" - loadMailerFrom(cfg) - - assert.Equal(t, "th1S gUess n3v3r y0u'll!!1", MailService.Passwd) - }) - t.Run("sendmail argument sanitization", func(t *testing.T) { cfg, _ := NewConfigProviderFromData("") sec := cfg.Section("mailer") diff --git a/modules/setting/moderation.go b/modules/setting/moderation.go index 799efed761..5f35a284d6 100644 --- a/modules/setting/moderation.go +++ b/modules/setting/moderation.go @@ -3,28 +3,13 @@ package setting -import ( - "fmt" - "time" -) - // Moderation settings var Moderation = struct { - Enabled bool `ini:"ENABLED"` - KeepResolvedReportsFor time.Duration `ini:"KEEP_RESOLVED_REPORTS_FOR"` + Enabled bool `ini:"ENABLED"` }{ Enabled: false, } -func loadModerationFrom(rootCfg ConfigProvider) error { - sec := rootCfg.Section("moderation") - err := sec.MapTo(&Moderation) - if err != nil { - return fmt.Errorf("failed to map Moderation settings: %v", err) - } - - // keep reports for one week by default. Since time.Duration stops at the unit of an hour - // we are using the value of 24 (hours) * 7 (days) which gives us the value of 168 - Moderation.KeepResolvedReportsFor = sec.Key("KEEP_RESOLVED_REPORTS_FOR").MustDuration(168 * time.Hour) - return nil +func loadModerationFrom(rootCfg ConfigProvider) { + mustMapSetting(rootCfg, "moderation", &Moderation) } diff --git a/modules/setting/packages.go b/modules/setting/packages.go index ba4768c66b..87e41fb5a0 100644 --- a/modules/setting/packages.go +++ b/modules/setting/packages.go @@ -5,9 +5,12 @@ package setting import ( "fmt" + "math" "net/url" "os" "path/filepath" + + "github.com/dustin/go-humanize" ) // Package registry settings @@ -107,3 +110,17 @@ func loadPackagesFrom(rootCfg ConfigProvider) (err error) { Packages.LimitSizeAlt = mustBytes(sec, "LIMIT_SIZE_ALT") return nil } + +func mustBytes(section ConfigSection, key string) int64 { + const noLimit = "-1" + + value := section.Key(key).MustString(noLimit) + if value == noLimit { + return -1 + } + bytes, err := humanize.ParseBytes(value) + if err != nil || bytes > math.MaxInt64 { + return -1 + } + return int64(bytes) +} diff --git a/modules/setting/packages_test.go b/modules/setting/packages_test.go index a2cfdc6e35..85a4656da0 100644 --- a/modules/setting/packages_test.go +++ b/modules/setting/packages_test.go @@ -10,6 +10,27 @@ import ( "github.com/stretchr/testify/require" ) +func TestMustBytes(t *testing.T) { + test := func(value string) int64 { + cfg, err := NewConfigProviderFromData("[test]") + require.NoError(t, err) + sec := cfg.Section("test") + sec.NewKey("VALUE", value) + + return mustBytes(sec, "VALUE") + } + + assert.EqualValues(t, -1, test("")) + assert.EqualValues(t, -1, test("-1")) + assert.EqualValues(t, 0, test("0")) + assert.EqualValues(t, 1, test("1")) + assert.EqualValues(t, 10000, test("10000")) + assert.EqualValues(t, 1000000, test("1 mb")) + assert.EqualValues(t, 1048576, test("1mib")) + assert.EqualValues(t, 1782579, test("1.7mib")) + assert.EqualValues(t, -1, test("1 yib")) // too large +} + func Test_getStorageInheritNameSectionTypeForPackages(t *testing.T) { // packages storage inherits from storage if nothing configured iniStr := ` diff --git a/modules/setting/quota.go b/modules/setting/quota.go index 01b3f16bbd..05e14baa9c 100644 --- a/modules/setting/quota.go +++ b/modules/setting/quota.go @@ -23,7 +23,4 @@ var Quota = struct { func loadQuotaFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "quota", &Quota) - - sec := rootCfg.Section("quota.default") - Quota.Default.Total = mustBytes(sec, "TOTAL") } diff --git a/modules/setting/quota_test.go b/modules/setting/quota_test.go deleted file mode 100644 index baec9ccb4b..0000000000 --- a/modules/setting/quota_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package setting - -import ( - "fmt" - "testing" - - "forgejo.org/modules/test" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestConfigQuotaDefaultTotal(t *testing.T) { - iniStr := `` - cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) - loadQuotaFrom(cfg) - - assert.False(t, Quota.Enabled) - assert.EqualValues(t, -1, Quota.Default.Total) - - testSets := []struct { - iniTotal string - expectTotal int64 - }{ - {"0", 0}, - {"5000", 5000}, - {"12,345,678", 12_345_678}, - {"2k", 2000}, - {"2MiB", 2 * 1024 * 1024}, - {"3G", 3_000_000_000}, - {"3GiB", 3 * 1024 * 1024 * 1024}, - {"9EB", 9_000_000_000_000_000_000}, - {"42EB", -1}, - {"-1", -1}, - {"-42", -1}, - {"-1MiB", -1}, - {"hello", -1}, - {"unlimited", -1}, - } - - for _, testSet := range testSets { - t.Run(testSet.iniTotal, func(t *testing.T) { - defer test.MockVariableValue(&Quota.Default.Total, -404)() - - iniStr := fmt.Sprintf(` -[quota] -ENABLED = true -[quota.default] -TOTAL = %s`, testSet.iniTotal) - - cfg, err := NewConfigProviderFromData(iniStr) - require.NoError(t, err) - loadQuotaFrom(cfg) - - assert.True(t, Quota.Enabled) - assert.Equal(t, testSet.expectTotal, Quota.Default.Total) - }) - } -} diff --git a/modules/setting/security.go b/modules/setting/security.go index c591a7c90a..f3480d1056 100644 --- a/modules/setting/security.go +++ b/modules/setting/security.go @@ -20,7 +20,6 @@ var ( SecretKey string InternalToken string // internal access token LogInRememberDays int - GlobalTwoFactorRequirement TwoFactorRequirementType CookieRememberName string ReverseProxyAuthUser string ReverseProxyAuthEmail string @@ -114,8 +113,6 @@ func loadSecurityFrom(rootCfg ConfigProvider) { } keying.Init([]byte(SecretKey)) - GlobalTwoFactorRequirement = NewTwoFactorRequirementType(sec.Key("GLOBAL_TWO_FACTOR_REQUIREMENT").String()) - CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible") ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER") @@ -171,42 +168,6 @@ func loadSecurityFrom(rootCfg ConfigProvider) { // warn if the setting is set to false explicitly if sectionHasDisableQueryAuthToken && !DisableQueryAuthToken { - log.Warn("Enabling Query API Auth tokens is not recommended. DISABLE_QUERY_AUTH_TOKEN will be removed in Forgejo v13.0.0.") + log.Warn("Enabling Query API Auth tokens is not recommended. DISABLE_QUERY_AUTH_TOKEN will default to true in gitea 1.23 and will be removed in gitea 1.24.") } } - -type TwoFactorRequirementType string - -// llu:TrKeysSuffix admin.config.global_2fa_requirement. -const ( - NoneTwoFactorRequirement TwoFactorRequirementType = "none" - AllTwoFactorRequirement TwoFactorRequirementType = "all" - AdminTwoFactorRequirement TwoFactorRequirementType = "admin" -) - -func NewTwoFactorRequirementType(twoFactorRequirement string) TwoFactorRequirementType { - switch twoFactorRequirement { - case AllTwoFactorRequirement.String(): - return AllTwoFactorRequirement - case AdminTwoFactorRequirement.String(): - return AdminTwoFactorRequirement - default: - return NoneTwoFactorRequirement - } -} - -func (r TwoFactorRequirementType) String() string { - return string(r) -} - -func (r TwoFactorRequirementType) IsNone() bool { - return r == NoneTwoFactorRequirement -} - -func (r TwoFactorRequirementType) IsAll() bool { - return r == AllTwoFactorRequirement -} - -func (r TwoFactorRequirementType) IsAdmin() bool { - return r == AdminTwoFactorRequirement -} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 9644d9b83b..75c24580b2 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -140,10 +140,6 @@ func loadCommonSettingsFrom(cfg ConfigProvider) error { if err := loadActionsFrom(cfg); err != nil { return err } - if err := loadModerationFrom(cfg); err != nil { - return err - } - loadUIFrom(cfg) loadAdminFrom(cfg) loadAPIFrom(cfg) @@ -225,6 +221,7 @@ func LoadSettings() { loadProjectFrom(CfgProvider) loadMimeTypeMapFrom(CfgProvider) loadF3From(CfgProvider) + loadModerationFrom(CfgProvider) } // LoadSettingsForInstall initializes the settings for install diff --git a/modules/setting/ui.go b/modules/setting/ui.go index 9dafe350eb..2e6a3df4c6 100644 --- a/modules/setting/ui.go +++ b/modules/setting/ui.go @@ -31,7 +31,7 @@ var UI = struct { Reactions []string ReactionsLookup container.Set[string] `ini:"-"` CustomEmojis []string - CustomEmojisLookup container.Set[string] `ini:"-"` + CustomEmojisMap map[string]string `ini:"-"` SearchRepoDescription bool OnlyShowRelevantRepos bool ExploreDefaultSort string `ini:"EXPLORE_PAGING_DEFAULT_SORT"` @@ -87,6 +87,7 @@ var UI = struct { Themes: []string{`forgejo-auto`, `forgejo-light`, `forgejo-dark`, `gitea-auto`, `gitea-light`, `gitea-dark`, `forgejo-auto-deuteranopia-protanopia`, `forgejo-light-deuteranopia-protanopia`, `forgejo-dark-deuteranopia-protanopia`, `forgejo-auto-tritanopia`, `forgejo-light-tritanopia`, `forgejo-dark-tritanopia`}, Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`, `forgejo`}, + CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:", "forgejo": ":forgejo:"}, ExploreDefaultSort: "recentupdate", PreferredTimestampTense: "mixed", @@ -162,6 +163,8 @@ func loadUIFrom(rootCfg ConfigProvider) { for _, reaction := range UI.Reactions { UI.ReactionsLookup.Add(reaction) } - UI.CustomEmojisLookup = make(container.Set[string]) - UI.CustomEmojisLookup.AddMultiple(UI.CustomEmojis...) + UI.CustomEmojisMap = make(map[string]string) + for _, emoji := range UI.CustomEmojis { + UI.CustomEmojisMap[emoji] = ":" + emoji + ":" + } } diff --git a/modules/ssh/init.go b/modules/ssh/init.go index 09b96a7d8a..1ccd95b18b 100644 --- a/modules/ssh/init.go +++ b/modules/ssh/init.go @@ -15,8 +15,6 @@ import ( "forgejo.org/modules/setting" ) -var logger = log.GetManager().GetLogger("ssh") - func Init() error { if setting.SSH.Disabled { builtinUnused() diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 502fcd070f..19cac0b603 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -61,10 +61,10 @@ func sessionHandler(session ssh.Session) { command := session.RawCommand() - logger.Trace("SSH: Payload: %v", command) + log.Trace("SSH: Payload: %v", command) args := []string{"--config=" + setting.CustomConf, "serv", "key-" + keyID} - logger.Trace("SSH: Arguments: %v", args) + log.Trace("SSH: Arguments: %v", args) ctx, cancel := context.WithCancel(session.Context()) defer cancel() @@ -87,21 +87,21 @@ func sessionHandler(session ssh.Session) { stdout, err := cmd.StdoutPipe() if err != nil { - logger.Error("SSH: StdoutPipe: %v", err) + log.Error("SSH: StdoutPipe: %v", err) return } defer stdout.Close() stderr, err := cmd.StderrPipe() if err != nil { - logger.Error("SSH: StderrPipe: %v", err) + log.Error("SSH: StderrPipe: %v", err) return } defer stderr.Close() stdin, err := cmd.StdinPipe() if err != nil { - logger.Error("SSH: StdinPipe: %v", err) + log.Error("SSH: StdinPipe: %v", err) return } defer stdin.Close() @@ -112,14 +112,14 @@ func sessionHandler(session ssh.Session) { wg.Add(2) if err = cmd.Start(); err != nil { - logger.Error("SSH: Start: %v", err) + log.Error("SSH: Start: %v", err) return } go func() { defer stdin.Close() if _, err := io.Copy(stdin, session); err != nil { - logger.Error("Failed to write session to stdin. %s", err) + log.Error("Failed to write session to stdin. %s", err) } }() @@ -127,7 +127,7 @@ func sessionHandler(session ssh.Session) { defer wg.Done() defer stdout.Close() if _, err := io.Copy(session, stdout); err != nil { - logger.Error("Failed to write stdout to session. %s", err) + log.Error("Failed to write stdout to session. %s", err) } }() @@ -135,7 +135,7 @@ func sessionHandler(session ssh.Session) { defer wg.Done() defer stderr.Close() if _, err := io.Copy(session.Stderr(), stderr); err != nil { - logger.Error("Failed to write stderr to session. %s", err) + log.Error("Failed to write stderr to session. %s", err) } }() @@ -149,41 +149,41 @@ func sessionHandler(session ssh.Session) { // Cannot use errors.Is here because ExitError doesn't implement Is // Thus errors.Is will do equality test NOT type comparison if _, ok := err.(*exec.ExitError); !ok { - logger.Error("SSH: Wait: %v", err) + log.Error("SSH: Wait: %v", err) } } if err := session.Exit(getExitStatusFromError(err)); err != nil && !errors.Is(err, io.EOF) { - logger.Error("Session failed to exit. %s", err) + log.Error("Session failed to exit. %s", err) } } func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { - if logger.LevelEnabled(log.DEBUG) { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary - logger.Debug("Handle Public Key: Fingerprint: %s from %s", gossh.FingerprintSHA256(key), ctx.RemoteAddr()) + if log.IsDebug() { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary + log.Debug("Handle Public Key: Fingerprint: %s from %s", gossh.FingerprintSHA256(key), ctx.RemoteAddr()) } if ctx.User() != setting.SSH.BuiltinServerUser { - logger.Warn("Invalid SSH username %s - must use %s for all git operations via ssh", ctx.User(), setting.SSH.BuiltinServerUser) - logger.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) + log.Warn("Invalid SSH username %s - must use %s for all git operations via ssh", ctx.User(), setting.SSH.BuiltinServerUser) + log.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) return false } // check if we have a certificate if cert, ok := key.(*gossh.Certificate); ok { - if logger.LevelEnabled(log.DEBUG) { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary - logger.Debug("Handle Certificate: %s Fingerprint: %s is a certificate", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) + if log.IsDebug() { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary + log.Debug("Handle Certificate: %s Fingerprint: %s is a certificate", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) } if len(setting.SSH.TrustedUserCAKeys) == 0 { - logger.Warn("Certificate Rejected: No trusted certificate authorities for this server") - logger.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) + log.Warn("Certificate Rejected: No trusted certificate authorities for this server") + log.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) return false } if cert.CertType != gossh.UserCert { - logger.Warn("Certificate Rejected: Not a user certificate") - logger.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) + log.Warn("Certificate Rejected: Not a user certificate") + log.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) return false } @@ -193,10 +193,10 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { pkey, err := asymkey_model.SearchPublicKeyByContentExact(ctx, principal) if err != nil { if asymkey_model.IsErrKeyNotExist(err) { - logger.Debug("Principal Rejected: %s Unknown Principal: %s", ctx.RemoteAddr(), principal) + log.Debug("Principal Rejected: %s Unknown Principal: %s", ctx.RemoteAddr(), principal) continue principalLoop } - logger.Error("SearchPublicKeyByContentExact: %v", err) + log.Error("SearchPublicKeyByContentExact: %v", err) return false } @@ -215,8 +215,8 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { // check the CA of the cert if !c.IsUserAuthority(cert.SignatureKey) { - if logger.LevelEnabled(log.DEBUG) { - logger.Debug("Principal Rejected: %s Untrusted Authority Signature Fingerprint %s for Principal: %s", ctx.RemoteAddr(), gossh.FingerprintSHA256(cert.SignatureKey), principal) + if log.IsDebug() { + log.Debug("Principal Rejected: %s Untrusted Authority Signature Fingerprint %s for Principal: %s", ctx.RemoteAddr(), gossh.FingerprintSHA256(cert.SignatureKey), principal) } continue principalLoop } @@ -224,14 +224,14 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { // validate the cert for this principal if err := c.CheckCert(principal, cert); err != nil { // User is presenting an invalid certificate - STOP any further processing - logger.Error("Invalid Certificate KeyID %s with Signature Fingerprint %s presented for Principal: %s from %s", cert.KeyId, gossh.FingerprintSHA256(cert.SignatureKey), principal, ctx.RemoteAddr()) - logger.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) + log.Error("Invalid Certificate KeyID %s with Signature Fingerprint %s presented for Principal: %s from %s", cert.KeyId, gossh.FingerprintSHA256(cert.SignatureKey), principal, ctx.RemoteAddr()) + log.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) return false } - if logger.LevelEnabled(log.DEBUG) { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary - logger.Debug("Successfully authenticated: %s Certificate Fingerprint: %s Principal: %s", ctx.RemoteAddr(), gossh.FingerprintSHA256(key), principal) + if log.IsDebug() { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary + log.Debug("Successfully authenticated: %s Certificate Fingerprint: %s Principal: %s", ctx.RemoteAddr(), gossh.FingerprintSHA256(key), principal) } if ctx.Permissions().Extensions == nil { ctx.Permissions().Extensions = map[string]string{} @@ -241,28 +241,28 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { return true } - logger.Warn("From %s Fingerprint: %s is a certificate, but no valid principals found", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) - logger.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) + log.Warn("From %s Fingerprint: %s is a certificate, but no valid principals found", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) + log.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) return false } - if logger.LevelEnabled(log.DEBUG) { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary - logger.Debug("Handle Public Key: %s Fingerprint: %s is not a certificate", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) + if log.IsDebug() { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary + log.Debug("Handle Public Key: %s Fingerprint: %s is not a certificate", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) } pkey, err := asymkey_model.SearchPublicKeyByContent(ctx, strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key)))) if err != nil { if asymkey_model.IsErrKeyNotExist(err) { - logger.Warn("Unknown public key: %s from %s", gossh.FingerprintSHA256(key), ctx.RemoteAddr()) - logger.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) + log.Warn("Unknown public key: %s from %s", gossh.FingerprintSHA256(key), ctx.RemoteAddr()) + log.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) return false } - logger.Error("SearchPublicKeyByContent: %v", err) + log.Error("SearchPublicKeyByContent: %v", err) return false } - if logger.LevelEnabled(log.DEBUG) { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary - logger.Debug("Successfully authenticated: %s Public Key Fingerprint: %s", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) + if log.IsDebug() { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary + log.Debug("Successfully authenticated: %s Public Key Fingerprint: %s", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) } if ctx.Permissions().Extensions == nil { ctx.Permissions().Extensions = map[string]string{} @@ -276,9 +276,9 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { // - this mainly exists to give a nice function name in logging func sshConnectionFailed(conn net.Conn, err error) { // Log the underlying error with a specific message - logger.Warn("Failed connection from %s with error: %v", conn.RemoteAddr(), err) + log.Warn("Failed connection from %s with error: %v", conn.RemoteAddr(), err) // Log with the standard failed authentication from message for simpler fail2ban configuration - logger.Warn("Failed authentication attempt from %s", conn.RemoteAddr()) + log.Warn("Failed authentication attempt from %s", conn.RemoteAddr()) } // Listen starts a SSH server listens on given port. @@ -317,22 +317,22 @@ func Listen(host string, port int, ciphers, keyExchanges, macs []string) { filePath := filepath.Dir(setting.SSH.ServerHostKeys[0]) if err := os.MkdirAll(filePath, os.ModePerm); err != nil { - logger.Error("Failed to create dir %s: %v", filePath, err) + log.Error("Failed to create dir %s: %v", filePath, err) } err := GenKeyPair(setting.SSH.ServerHostKeys[0]) if err != nil { log.Fatal("Failed to generate private key: %v", err) } - logger.Trace("New private key is generated: %s", setting.SSH.ServerHostKeys[0]) + log.Trace("New private key is generated: %s", setting.SSH.ServerHostKeys[0]) keys = append(keys, setting.SSH.ServerHostKeys[0]) } for _, key := range keys { - logger.Info("Adding SSH host key: %s", key) + log.Info("Adding SSH host key: %s", key) err := srv.SetOption(ssh.HostKeyFile(key)) if err != nil { - logger.Error("Failed to set Host Key. %s", err) + log.Error("Failed to set Host Key. %s", err) } } @@ -359,7 +359,7 @@ func GenKeyPair(keyPath string) error { } defer func() { if err = f.Close(); err != nil { - logger.Error("Close: %v", err) + log.Error("Close: %v", err) } }() @@ -380,7 +380,7 @@ func GenKeyPair(keyPath string) error { } defer func() { if err = p.Close(); err != nil { - logger.Error("Close: %v", err) + log.Error("Close: %v", err) } }() _, err = p.Write(public) diff --git a/modules/ssh/ssh_graceful.go b/modules/ssh/ssh_graceful.go index 98ddc18ae7..825313ab1c 100644 --- a/modules/ssh/ssh_graceful.go +++ b/modules/ssh/ssh_graceful.go @@ -20,12 +20,12 @@ func listen(server *ssh.Server) { if err != nil { select { case <-graceful.GetManager().IsShutdown(): - logger.Critical("Failed to start SSH server: %v", err) + log.Critical("Failed to start SSH server: %v", err) default: log.Fatal("Failed to start SSH server: %v", err) } } - logger.Info("SSH Listener: %s Closed", server.Addr) + log.Info("SSH Listener: %s Closed", server.Addr) } // builtinUnused informs our cleanup routine that we will not be using a ssh port diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 8d4f9d6627..bf51a1642a 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -76,13 +76,8 @@ var getBucketVersioning = func(ctx context.Context, minioClient *minio.Client, b return err } -var initializationTimeout = 30 * time.Second - // NewMinioStorage returns a minio storage func NewMinioStorage(ctx context.Context, cfg *setting.Storage) (ObjectStorage, error) { - initCtx, cancel := context.WithTimeout(ctx, initializationTimeout) - defer cancel() - config := cfg.MinioConfig if config.ChecksumAlgorithm != "" && config.ChecksumAlgorithm != "default" && config.ChecksumAlgorithm != "md5" { return nil, fmt.Errorf("invalid minio checksum algorithm: %s", config.ChecksumAlgorithm) @@ -117,7 +112,7 @@ func NewMinioStorage(ctx context.Context, cfg *setting.Storage) (ObjectStorage, // Otherwise even if the request itself fails (403, 404, etc), the code should still continue because the parameters seem "good" enough. // Keep in mind that GetBucketVersioning requires "owner" to really succeed, so it can't be used to check the existence. // Not using "BucketExists (HeadBucket)" because it doesn't include detailed failure reasons. - err = getBucketVersioning(initCtx, minioClient, config.Bucket) + err = getBucketVersioning(ctx, minioClient, config.Bucket) if err != nil { errResp, ok := err.(minio.ErrorResponse) if !ok { @@ -130,13 +125,13 @@ func NewMinioStorage(ctx context.Context, cfg *setting.Storage) (ObjectStorage, } // Check to see if we already own this bucket - exists, err := minioClient.BucketExists(initCtx, config.Bucket) + exists, err := minioClient.BucketExists(ctx, config.Bucket) if err != nil { return nil, convertMinioErr(err) } if !exists { - if err := minioClient.MakeBucket(initCtx, config.Bucket, minio.MakeBucketOptions{ + if err := minioClient.MakeBucket(ctx, config.Bucket, minio.MakeBucketOptions{ Region: config.Location, }); err != nil { return nil, convertMinioErr(err) diff --git a/modules/storage/minio_test.go b/modules/storage/minio_test.go index 18fe91edfb..ec1b2fc77a 100644 --- a/modules/storage/minio_test.go +++ b/modules/storage/minio_test.go @@ -9,10 +9,8 @@ import ( "net/http/httptest" "os" "testing" - "time" "forgejo.org/modules/setting" - "forgejo.org/modules/test" "github.com/minio/minio-go/v7" "github.com/stretchr/testify/assert" @@ -219,41 +217,3 @@ func TestMinioCredentials(t *testing.T) { }) }) } - -func TestNewMinioStorageInitializationTimeout(t *testing.T) { - defer test.MockVariableValue(&getBucketVersioning, func(ctx context.Context, minioClient *minio.Client, bucket string) error { - select { - case <-ctx.Done(): - return ctx.Err() - case <-time.After(1 * time.Millisecond): - return minio.ErrorResponse{ - StatusCode: http.StatusBadRequest, - Code: "TestError", - Message: "Mocked error for testing", - } - } - })() - - settings := &setting.Storage{ - MinioConfig: setting.MinioStorageConfig{ - Endpoint: "localhost", - AccessKeyID: "123456", - SecretAccessKey: "12345678", - Bucket: "bucket", - Location: "us-east-1", - }, - } - - // Verify that we reach `getBucketVersioning` and return the error from our mock. - storage, err := NewMinioStorage(t.Context(), settings) - require.ErrorContains(t, err, "Mocked error for testing") - assert.Nil(t, storage) - - defer test.MockVariableValue(&initializationTimeout, 1*time.Nanosecond)() - - // Now that the timeout is super low, verify that we get a context deadline exceeded error from our mock. - storage, err = NewMinioStorage(t.Context(), settings) - require.Error(t, err) - require.ErrorIs(t, err, context.DeadlineExceeded, "err must be a context deadline exceeded error, but was %v", err) - assert.Nil(t, storage) -} diff --git a/modules/storage/storage_test.go b/modules/storage/storage_test.go index 76589d941a..af3dd9520e 100644 --- a/modules/storage/storage_test.go +++ b/modules/storage/storage_test.go @@ -5,7 +5,6 @@ package storage import ( "bytes" - "io" "testing" "forgejo.org/modules/setting" @@ -14,39 +13,22 @@ import ( "github.com/stretchr/testify/require" ) -type spyCloser struct { - io.Reader - closed int -} - -func (s *spyCloser) Close() error { - s.closed++ - return nil -} - -var _ io.ReadCloser = &spyCloser{} - func testStorageIterator(t *testing.T, typStr Type, cfg *setting.Storage) { l, err := NewStorage(typStr, cfg) require.NoError(t, err) - testFiles := []struct { - path, content string - size int64 - }{ - {"a/1.txt", "a1", -1}, - {"/a/1.txt", "aa1", -1}, // same as above, but with leading slash that will be trim - {"ab/1.txt", "ab1", 3}, - {"b/1.txt", "b1", 2}, // minio closes when the size is set - {"b/2.txt", "b2", -1}, - {"b/3.txt", "b3", -1}, - {"b/x 4.txt", "bx4", -1}, + testFiles := [][]string{ + {"a/1.txt", "a1"}, + {"/a/1.txt", "aa1"}, // same as above, but with leading slash that will be trim + {"ab/1.txt", "ab1"}, + {"b/1.txt", "b1"}, + {"b/2.txt", "b2"}, + {"b/3.txt", "b3"}, + {"b/x 4.txt", "bx4"}, } for _, f := range testFiles { - sc := &spyCloser{bytes.NewBufferString(f.content), 0} - _, err = l.Save(f.path, sc, f.size) + _, err = l.Save(f[0], bytes.NewBufferString(f[1]), -1) require.NoError(t, err) - assert.Equal(t, 0, sc.closed) } expectedList := map[string][]string{ diff --git a/modules/structs/activitypub.go b/modules/structs/activitypub.go index 0cc257ff95..117eb0bed2 100644 --- a/modules/structs/activitypub.go +++ b/modules/structs/activitypub.go @@ -1,5 +1,4 @@ // Copyright 2022 The Gitea Authors. All rights reserved. -// Copyright 2024 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package structs @@ -8,15 +7,3 @@ package structs type ActivityPub struct { Context string `json:"@context"` } - -type APRemoteFollowOption struct { - Target string `json:"target"` -} - -type APPersonFollowItem struct { - ActorID string `json:"actor_id"` - Note string `json:"note"` - - OriginalURL string `json:"original_url"` - OriginalItem string `json:"original_item"` -} diff --git a/modules/structs/issue.go b/modules/structs/issue.go index 7b7397dc4b..a67bdcf50e 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) // StateType issue state type diff --git a/modules/structs/issue_test.go b/modules/structs/issue_test.go index 7adb843206..2003e22e0a 100644 --- a/modules/structs/issue_test.go +++ b/modules/structs/issue_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.yaml.in/yaml/v3" + "gopkg.in/yaml.v3" ) func TestIssueTemplate_Type(t *testing.T) { diff --git a/modules/structs/mirror.go b/modules/structs/mirror.go index 4909ae20ca..1b6566803a 100644 --- a/modules/structs/mirror.go +++ b/modules/structs/mirror.go @@ -13,7 +13,6 @@ type CreatePushMirrorOption struct { Interval string `json:"interval"` SyncOnCommit bool `json:"sync_on_commit"` UseSSH bool `json:"use_ssh"` - BranchFilter string `json:"branch_filter"` } // PushMirror represents information of a push mirror @@ -30,6 +29,4 @@ type PushMirror struct { Interval string `json:"interval"` SyncOnCommit bool `json:"sync_on_commit"` PublicKey string `json:"public_key"` - - BranchFilter string `json:"branch_filter"` } diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 01cbf26f61..c9cd729cf3 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -327,7 +327,6 @@ const ( GitBucketService // 7 gitbucket service CodebaseService // 8 codebase service ForgejoService // 9 forgejo service - PagureService // 10 pagure service ) // Name represents the service type's name @@ -355,8 +354,6 @@ func (gt GitServiceType) Title() string { return "Codebase" case ForgejoService: return "Forgejo" - case PagureService: - return "Pagure" case PlainGitService: return "Git" } @@ -415,7 +412,6 @@ var SupportedFullGitService = []GitServiceType{ OneDevService, GitBucketService, CodebaseService, - PagureService, } // RepoTransfer represents a pending repo transfer diff --git a/modules/templates/context.go b/modules/templates/context.go deleted file mode 100644 index d2b896391b..0000000000 --- a/modules/templates/context.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later - -package templates - -import ( - "context" - - "forgejo.org/modules/translation" -) - -type Context struct { - context.Context - Locale translation.Locale - AvatarUtils *AvatarUtils - Data map[string]any -} - -var _ context.Context = Context{} - -func NewContext(ctx context.Context) *Context { - return &Context{Context: ctx} -} diff --git a/modules/templates/context_test.go b/modules/templates/context_test.go deleted file mode 100644 index d854fbf0ff..0000000000 --- a/modules/templates/context_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2025 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-or-later -package templates - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestContext(t *testing.T) { - type ctxKey struct{} - - // Test that the original context is used for its context functions. - ctx := NewContext(context.WithValue(t.Context(), ctxKey{}, "there")) - assert.Equal(t, "there", ctx.Value(ctxKey{})) -} diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 848d4b4ad4..02b175e6f6 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -6,8 +6,6 @@ package templates import ( - "bytes" - "context" "fmt" "html" "html/template" @@ -31,23 +29,6 @@ func NewFuncMap() template.FuncMap { return map[string]any{ "ctx": func() any { return nil }, // template context function - "ExecuteTemplate": func(ctx context.Context, tmplName string, args any) template.HTML { - h := HTMLRenderer() - tmpl, err := h.TemplateLookup(tmplName, ctx) - if err != nil { - panic("Template not found: " + tmplName) - } - - buf := bytes.Buffer{} - if err := tmpl.Execute(&buf, args); err != nil { - panic("Error while executing template") - } - - // We can safely return this as `template.HTML` as html/template will - // already make sure it's sanitized. - return template.HTML(buf.String()) - }, - "DumpVar": dumpVar, // ----------------------------------------------------------------- @@ -147,8 +128,8 @@ func NewFuncMap() template.FuncMap { "AllowedReactions": func() []string { return setting.UI.Reactions }, - "CustomEmojis": func() []string { - return setting.UI.CustomEmojis + "CustomEmojis": func() map[string]string { + return setting.UI.CustomEmojisMap }, "MetaAuthor": func() string { return setting.UI.Meta.Author @@ -207,7 +188,6 @@ func NewFuncMap() template.FuncMap { "RenderMarkdownToHtml": RenderMarkdownToHtml, "RenderLabel": RenderLabel, "RenderLabels": RenderLabels, - "RenderUser": RenderUser, "RenderReviewRequest": RenderReviewRequest, // ----------------------------------------------------------------- diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go index bec8d5f5e3..a4d7a82eea 100644 --- a/modules/templates/util_render.go +++ b/modules/templates/util_render.go @@ -7,7 +7,6 @@ import ( "context" "encoding/hex" "fmt" - "html" "html/template" "math" "net/url" @@ -16,18 +15,18 @@ import ( "unicode" issues_model "forgejo.org/models/issues" - user_model "forgejo.org/models/user" "forgejo.org/modules/emoji" "forgejo.org/modules/log" "forgejo.org/modules/markup" "forgejo.org/modules/markup/markdown" "forgejo.org/modules/setting" + "forgejo.org/modules/translation" "forgejo.org/modules/util" ) // RenderCommitMessage renders commit message with XSS-safe and special links. func RenderCommitMessage(ctx context.Context, msg string, metas map[string]string) template.HTML { - cleanMsg := html.EscapeString(msg) + cleanMsg := template.HTMLEscapeString(msg) // we can safely assume that it will not return any error, since there // shouldn't be any special HTML. fullMessage, err := markup.RenderCommitMessage(&markup.RenderContext{ @@ -64,7 +63,7 @@ func RenderCommitMessageLinkSubject(ctx context.Context, msg, urlDefault string, Ctx: ctx, DefaultLink: urlDefault, Metas: metas, - }, html.EscapeString(msgLine)) + }, template.HTMLEscapeString(msgLine)) if err != nil { log.Error("RenderCommitMessageSubject: %v", err) return template.HTML("") @@ -89,7 +88,7 @@ func RenderCommitBody(ctx context.Context, msg string, metas map[string]string) renderedMessage, err := markup.RenderCommitMessage(&markup.RenderContext{ Ctx: ctx, Metas: metas, - }, html.EscapeString(msgLine)) + }, template.HTMLEscapeString(msgLine)) if err != nil { log.Error("RenderCommitMessage: %v", err) return "" @@ -123,7 +122,7 @@ func RenderIssueTitle(ctx context.Context, text string, metas map[string]string) renderedText, err := markup.RenderIssueTitle(&markup.RenderContext{ Ctx: ctx, Metas: metas, - }, html.EscapeString(text)) + }, template.HTMLEscapeString(text)) if err != nil { log.Error("RenderIssueTitle: %v", err) return template.HTML("") @@ -133,7 +132,7 @@ func RenderIssueTitle(ctx context.Context, text string, metas map[string]string) // RenderRefIssueTitle renders referenced issue/pull title with defined post processors func RenderRefIssueTitle(ctx context.Context, text string) template.HTML { - renderedText, err := markup.RenderRefIssueTitle(&markup.RenderContext{Ctx: ctx}, html.EscapeString(text)) + renderedText, err := markup.RenderRefIssueTitle(&markup.RenderContext{Ctx: ctx}, template.HTMLEscapeString(text)) if err != nil { log.Error("RenderRefIssueTitle: %v", err) return "" @@ -144,18 +143,18 @@ func RenderRefIssueTitle(ctx context.Context, text string) template.HTML { // RenderLabel renders a label // locale is needed due to an import cycle with our context providing the `Tr` function -func RenderLabel(ctx *Context, label *issues_model.Label) template.HTML { +func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML { var ( archivedCSSClass string textColor = util.ContrastColor(label.Color) labelScope = label.ExclusiveScope() ) - description := emoji.ReplaceAliases(html.EscapeString(label.Description)) + description := emoji.ReplaceAliases(template.HTMLEscapeString(label.Description)) if label.IsArchived() { archivedCSSClass = "archived-label" - description = ctx.Locale.TrString("repo.issues.archived_label_description", description) + description = locale.TrString("repo.issues.archived_label_description", description) } if labelScope == "" { @@ -213,7 +212,7 @@ func RenderLabel(ctx *Context, label *issues_model.Label) template.HTML { // RenderEmoji renders html text with emoji post processors func RenderEmoji(ctx context.Context, text string) template.HTML { renderedText, err := markup.RenderEmoji(&markup.RenderContext{Ctx: ctx}, - html.EscapeString(text)) + template.HTMLEscapeString(text)) if err != nil { log.Error("RenderEmoji: %v", err) return template.HTML("") @@ -245,7 +244,7 @@ func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //n return output } -func RenderLabels(ctx *Context, labels []*issues_model.Label, repoLink string, isPull bool) template.HTML { +func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issues_model.Label, repoLink string, isPull bool) template.HTML { htmlCode := `` for _, label := range labels { // Protect against nil value in labels - shouldn't happen but would cause a panic if so @@ -258,34 +257,16 @@ func RenderLabels(ctx *Context, labels []*issues_model.Label, repoLink string, i issuesOrPull = "pulls" } htmlCode += fmt.Sprintf("%s ", - repoLink, issuesOrPull, label.ID, RenderLabel(ctx, label)) + repoLink, issuesOrPull, label.ID, RenderLabel(ctx, locale, label)) } htmlCode += "" return template.HTML(htmlCode) } -func RenderUser(ctx context.Context, user user_model.User) template.HTML { - if user.ID > 0 { - return template.HTML(fmt.Sprintf( - "%s", - user.HomeLink(), html.EscapeString(user.GetDisplayName()))) - } - return template.HTML(fmt.Sprintf("%s", - html.EscapeString(user.GetDisplayName()))) -} - -func RenderReviewRequest(ctx context.Context, users []issues_model.RequestReviewTarget) template.HTML { +func RenderReviewRequest(users []issues_model.RequestReviewTarget) template.HTML { usernames := make([]string, 0, len(users)) for _, user := range users { - if user.ID() > 0 { - usernames = append(usernames, fmt.Sprintf( - "%s", - user.Link(ctx), html.EscapeString(user.Name()))) - } else { - usernames = append(usernames, fmt.Sprintf( - "%s", - html.EscapeString(user.Name()))) - } + usernames = append(usernames, template.HTMLEscapeString(user.Name())) } htmlCode := `` diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go index 3cfd572491..62e063213c 100644 --- a/modules/templates/util_render_test.go +++ b/modules/templates/util_render_test.go @@ -10,11 +10,7 @@ import ( "forgejo.org/models/db" issues_model "forgejo.org/models/issues" - org_model "forgejo.org/models/organization" "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" - "forgejo.org/modules/setting" - "forgejo.org/modules/test" "forgejo.org/modules/translation" "github.com/stretchr/testify/assert" @@ -219,70 +215,9 @@ func TestRenderLabels(t *testing.T) { tr := &translation.MockLocale{} label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) - labelScoped := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 7}) - labelMalicious := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 11}) - labelArchived := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 12}) - ctx := NewContext(t.Context()) - ctx.Locale = tr - - rendered := RenderLabels(ctx, []*issues_model.Label{label}, "user2/repo1", false) - assert.Contains(t, rendered, "user2/repo1/issues?labels=1") - assert.Contains(t, rendered, ">label1<") - assert.Contains(t, rendered, "title='First label'") - rendered = RenderLabels(ctx, []*issues_model.Label{label}, "user2/repo1", true) - assert.Contains(t, rendered, "user2/repo1/pulls?labels=1") - assert.Contains(t, rendered, ">label1<") - rendered = RenderLabels(ctx, []*issues_model.Label{labelScoped}, "user2/repo1", false) - assert.Contains(t, rendered, "user2/repo1/issues?labels=7") - assert.Contains(t, rendered, ">scope<") - assert.Contains(t, rendered, ">label1<") - rendered = RenderLabels(ctx, []*issues_model.Label{labelMalicious}, "user2/repo1", false) - assert.Contains(t, rendered, "user2/repo1/issues?labels=11") - assert.Contains(t, rendered, "> <script>malicious</script> <") - assert.Contains(t, rendered, ">'?&<") - assert.Contains(t, rendered, "title='Malicious label ' <script>malicious</script>'") - rendered = RenderLabels(ctx, []*issues_model.Label{labelArchived}, "user2/repo1", false) - assert.Contains(t, rendered, "user2/repo1/issues?labels=12") - assert.Contains(t, rendered, ">archived label<><") - assert.Contains(t, rendered, "title='repo.issues.archived_label_description'") -} - -func TestRenderUser(t *testing.T) { - unittest.PrepareTestEnv(t) - - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) - ghost := user_model.NewGhostUser() - - assert.Contains(t, RenderUser(db.DefaultContext, *user), - "user2") - assert.Contains(t, RenderUser(db.DefaultContext, *org), - "org3") - assert.Contains(t, RenderUser(db.DefaultContext, *ghost), - "Ghost") - - defer test.MockVariableValue(&setting.UI.DefaultShowFullName, true)() - assert.Contains(t, RenderUser(db.DefaultContext, *user), - "< U<se>r Tw<o > ><") - assert.Contains(t, RenderUser(db.DefaultContext, *org), - "<<<< >> >> > >> > >>> >>") - assert.Contains(t, RenderUser(db.DefaultContext, *ghost), - "Ghost") -} - -func TestRenderReviewRequest(t *testing.T) { - unittest.PrepareTestEnv(t) - - target1 := issues_model.RequestReviewTarget{User: &user_model.User{ID: 1, Name: "user1", FullName: "User "}} - target2 := issues_model.RequestReviewTarget{Team: &org_model.Team{ID: 2, Name: "Team2", OrgID: 3}} - target3 := issues_model.RequestReviewTarget{Team: org_model.NewGhostTeam()} - assert.Contains(t, RenderReviewRequest(db.DefaultContext, []issues_model.RequestReviewTarget{target1, target2, target3}), - "user1, "+ - "Team2, "+ - "Ghost team") - - defer test.MockVariableValue(&setting.UI.DefaultShowFullName, true)() - assert.Contains(t, RenderReviewRequest(db.DefaultContext, []issues_model.RequestReviewTarget{target1}), - "User <One>") + assert.Contains(t, RenderLabels(db.DefaultContext, tr, []*issues_model.Label{label}, "user2/repo1", false), + "user2/repo1/issues?labels=1") + assert.Contains(t, RenderLabels(db.DefaultContext, tr, []*issues_model.Label{label}, "user2/repo1", true), + "user2/repo1/pulls?labels=1") } diff --git a/modules/test/distant_federation_server_mock.go b/modules/test/distant_federation_server_mock.go index ea8a69e9b4..9bd908e2b9 100644 --- a/modules/test/distant_federation_server_mock.go +++ b/modules/test/distant_federation_server_mock.go @@ -10,79 +10,56 @@ import ( "net/http/httptest" "strings" "testing" - - "forgejo.org/modules/util" ) type FederationServerMockPerson struct { - ID int64 - Name string - PubKey string - PrivKey string + ID int64 + Name string + PubKey string } type FederationServerMockRepository struct { ID int64 } -type ApActorMock struct { - PrivKey string - PubKey string -} type FederationServerMock struct { - ApActor ApActorMock Persons []FederationServerMockPerson Repositories []FederationServerMockRepository LastPost string } func NewFederationServerMockPerson(id int64, name string) FederationServerMockPerson { - priv, pub, _ := util.GenerateKeyPair(3072) return FederationServerMockPerson{ - ID: id, - Name: name, - PubKey: pub, - PrivKey: priv, + ID: id, + Name: name, + PubKey: `"-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA18H5s7N6ItZUAh9tneII\nIuZdTTa3cZlLa/9ejWAHTkcp3WLW+/zbsumlMrWYfBy2/yTm56qasWt38iY4D6ul\n` + + `CPiwhAqX3REvVq8tM79a2CEqZn9ka6vuXoDgBg/sBf/BUWqf7orkjUXwk/U0Egjf\nk5jcurF4vqf1u+rlAHH37dvSBaDjNj6Qnj4OP12bjfaY/yvs7+jue/eNXFHjzN4E\n` + + `T2H4B/yeKTJ4UuAwTlLaNbZJul2baLlHelJPAsxiYaziVuV5P+IGWckY6RSerRaZ\nAkc4mmGGtjAyfN9aewe+lNVfwS7ElFx546PlLgdQgjmeSwLX8FWxbPE5A/PmaXCs\n` + + `nx+nou+3dD7NluULLtdd7K+2x02trObKXCAzmi5/Dc+yKTzpFqEz+hLNCz7TImP/\ncK//NV9Q+X67J9O27baH9R9ZF4zMw8rv2Pg0WLSw1z7lLXwlgIsDapeMCsrxkVO4\n` + + `LXX5AQ1xQNtlssnVoUBqBrvZsX2jUUKUocvZqMGuE4hfAgMBAAE=\n-----END PUBLIC KEY-----\n"`, } } -func (p *FederationServerMockPerson) KeyID(host string) string { - return fmt.Sprintf("%[1]v/api/v1/activitypub/user-id/%[2]v#main-key", host, p.ID) -} - func NewFederationServerMockRepository(id int64) FederationServerMockRepository { return FederationServerMockRepository{ ID: id, } } -func NewApActorMock() ApActorMock { - priv, pub, _ := util.GenerateKeyPair(1024) - return ApActorMock{ - PrivKey: priv, - PubKey: pub, - } -} - -func (u *ApActorMock) KeyID(host string) string { - return fmt.Sprintf("%[1]v/api/v1/activitypub/actor#main-key", host) -} - func (p FederationServerMockPerson) marshal(host string) string { return fmt.Sprintf(`{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],`+ - `"id":"http://%[1]v/api/v1/activitypub/user-id/%[2]v",`+ + `"id":"http://%[1]v/api/activitypub/user-id/%[2]v",`+ `"type":"Person",`+ `"icon":{"type":"Image","mediaType":"image/png","url":"http://%[1]v/avatars/1bb05d9a5f6675ed0272af9ea193063c"},`+ `"url":"http://%[1]v/%[2]v",`+ - `"inbox":"http://%[1]v/api/v1/activitypub/user-id/%[2]v/inbox",`+ - `"outbox":"http://%[1]v/api/v1/activitypub/user-id/%[2]v/outbox",`+ + `"inbox":"http://%[1]v/api/activitypub/user-id/%[2]v/inbox",`+ + `"outbox":"http://%[1]v/api/activitypub/user-id/%[2]v/outbox",`+ `"preferredUsername":"%[3]v",`+ - `"publicKey":{"id":"http://%[1]v/api/v1/activitypub/user-id/%[2]v#main-key",`+ - `"owner":"http://%[1]v/api/v1/activitypub/user-id/%[2]v",`+ - `"publicKeyPem":%[4]q}}`, host, p.ID, p.Name, p.PubKey) + `"publicKey":{"id":"http://%[1]v/api/activitypub/user-id/%[2]v#main-key",`+ + `"owner":"http://%[1]v/api/activitypub/user-id/%[2]v",`+ + `"publicKeyPem":%[4]v}}`, host, p.ID, p.Name, p.PubKey) } func NewFederationServerMock() *FederationServerMock { return &FederationServerMock{ - ApActor: NewApActorMock(), Persons: []FederationServerMockPerson{ NewFederationServerMockPerson(15, "stargoose1"), NewFederationServerMockPerson(30, "stargoose2"), @@ -94,18 +71,8 @@ func NewFederationServerMock() *FederationServerMock { } } -func (mock *FederationServerMock) recordLastPost(t *testing.T, req *http.Request) { - buf := new(strings.Builder) - _, err := io.Copy(buf, req.Body) - if err != nil { - t.Errorf("Error reading body: %q", err) - } - mock.LastPost = strings.ReplaceAll(buf.String(), req.Host, "DISTANT_FEDERATION_HOST") -} - func (mock *FederationServerMock) DistantServer(t *testing.T) *httptest.Server { federatedRoutes := http.NewServeMux() - federatedRoutes.HandleFunc("/.well-known/nodeinfo", func(res http.ResponseWriter, req *http.Request) { // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/.well-known/nodeinfo @@ -120,28 +87,30 @@ func (mock *FederationServerMock) DistantServer(t *testing.T) *httptest.Server { `"protocols":["activitypub"],"services":{"inbound":[],"outbound":["rss2.0"]},`+ `"openRegistrations":true,"usage":{"users":{"total":14,"activeHalfyear":2}},"metadata":{}}`) }) - for _, person := range mock.Persons { federatedRoutes.HandleFunc(fmt.Sprintf("/api/v1/activitypub/user-id/%v", person.ID), func(res http.ResponseWriter, req *http.Request) { // curl -H "Accept: application/json" https://federated-repo.prod.meissa.de/api/v1/activitypub/user-id/2 fmt.Fprint(res, person.marshal(req.Host)) }) - federatedRoutes.HandleFunc(fmt.Sprintf("POST /api/v1/activitypub/user-id/%v/inbox", person.ID), - func(res http.ResponseWriter, req *http.Request) { - mock.recordLastPost(t, req) - }) } - for _, repository := range mock.Repositories { - federatedRoutes.HandleFunc(fmt.Sprintf("POST /api/v1/activitypub/repository-id/%v/inbox", repository.ID), + federatedRoutes.HandleFunc(fmt.Sprintf("/api/v1/activitypub/repository-id/%v/inbox", repository.ID), func(res http.ResponseWriter, req *http.Request) { - mock.recordLastPost(t, req) + if req.Method != "POST" { + t.Errorf("POST expected at: %q", req.URL.EscapedPath()) + } + buf := new(strings.Builder) + _, err := io.Copy(buf, req.Body) + if err != nil { + t.Errorf("Error reading body: %q", err) + } + mock.LastPost = buf.String() }) } federatedRoutes.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) { - t.Errorf("Unhandled %v request: %q", req.Method, req.URL.EscapedPath()) + t.Errorf("Unhandled request: %q", req.URL.EscapedPath()) }) federatedSrv := httptest.NewServer(federatedRoutes) return federatedSrv diff --git a/modules/translation/plural_rules.go b/modules/translation/plural_rules.go index 587ee48850..59665da255 100644 --- a/modules/translation/plural_rules.go +++ b/modules/translation/plural_rules.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MIT // Some useful links: -// https://codeberg.org/forgejo/forgejo/src/branch/forgejo/web_src/js/webcomponents/relative-time.js // https://www.unicode.org/cldr/charts/46/supplemental/language_plural_rules.html // https://translate.codeberg.org/languages/$LANGUAGE_CODE/#information // https://github.com/WeblateOrg/language-data/blob/main/languages.csv @@ -17,7 +16,7 @@ import ( "forgejo.org/modules/translation/i18n" ) -// The constants refer to indices below in `PluralRules` and also in web_src/js/webcomponents/relative-time.js, keep them in sync! +// The constants refer to indices below in `PluralRules` and also in i18n.js, keep them in sync! const ( PluralRuleDefault = 0 PluralRuleBengali = 1 diff --git a/modules/typesniffer/typesniffer.go b/modules/typesniffer/typesniffer.go index 8cb1513a88..262feb2b05 100644 --- a/modules/typesniffer/typesniffer.go +++ b/modules/typesniffer/typesniffer.go @@ -124,7 +124,7 @@ func (ct SniffedType) GetMimeType() string { } // DetectContentType extends http.DetectContentType with more content types. Defaults to text/unknown if input is empty. -func DetectContentType(data []byte, filename string) SniffedType { +func DetectContentType(data []byte) SniffedType { if len(data) == 0 { return SniffedType{"text/unknown"} } @@ -176,13 +176,6 @@ func DetectContentType(data []byte, filename string) SniffedType { } } - if ct == "application/octet-stream" && - filename != "" && - !strings.HasSuffix(strings.ToUpper(filename), ".LCOM") && - bytes.Contains(data, []byte("(DEFINE-FILE-INFO ")) { - ct = "text/vnd.interlisp" - } - // GLTF is unsupported by http.DetectContentType // hexdump -n 4 -C glTF.glb if bytes.HasPrefix(data, []byte("glTF")) { @@ -193,7 +186,7 @@ func DetectContentType(data []byte, filename string) SniffedType { } // DetectContentTypeFromReader guesses the content type contained in the reader. -func DetectContentTypeFromReader(r io.Reader, filename string) (SniffedType, error) { +func DetectContentTypeFromReader(r io.Reader) (SniffedType, error) { buf := make([]byte, sniffLen) n, err := util.ReadAtMost(r, buf) if err != nil { @@ -201,5 +194,5 @@ func DetectContentTypeFromReader(r io.Reader, filename string) (SniffedType, err } buf = buf[:n] - return DetectContentType(buf, filename), nil + return DetectContentType(buf), nil } diff --git a/modules/typesniffer/typesniffer_test.go b/modules/typesniffer/typesniffer_test.go index d2b7ed4f21..176d3658bb 100644 --- a/modules/typesniffer/typesniffer_test.go +++ b/modules/typesniffer/typesniffer_test.go @@ -16,63 +16,63 @@ import ( func TestDetectContentTypeLongerThanSniffLen(t *testing.T) { // Pre-condition: Shorter than sniffLen detects SVG. - assert.Equal(t, "image/svg+xml", DetectContentType([]byte(``), "").contentType) + assert.Equal(t, "image/svg+xml", DetectContentType([]byte(``)).contentType) // Longer than sniffLen detects something else. - assert.NotEqual(t, "image/svg+xml", DetectContentType([]byte(``), "").contentType) + assert.NotEqual(t, "image/svg+xml", DetectContentType([]byte(``)).contentType) } func TestIsTextFile(t *testing.T) { - assert.True(t, DetectContentType([]byte{}, "").IsText()) - assert.True(t, DetectContentType([]byte("lorem ipsum"), "").IsText()) + assert.True(t, DetectContentType([]byte{}).IsText()) + assert.True(t, DetectContentType([]byte("lorem ipsum")).IsText()) } func TestIsSvgImage(t *testing.T) { - assert.True(t, DetectContentType([]byte(""), "").IsSvgImage()) - assert.True(t, DetectContentType([]byte(" "), "").IsSvgImage()) - assert.True(t, DetectContentType([]byte(``), "").IsSvgImage()) - assert.True(t, DetectContentType([]byte(``), "").IsSvgImage()) + assert.True(t, DetectContentType([]byte("")).IsSvgImage()) + assert.True(t, DetectContentType([]byte(" ")).IsSvgImage()) + assert.True(t, DetectContentType([]byte(``)).IsSvgImage()) + assert.True(t, DetectContentType([]byte(``)).IsSvgImage()) assert.True(t, DetectContentType([]byte(` - `), "").IsSvgImage()) + `)).IsSvgImage()) assert.True(t, DetectContentType([]byte(` - `), "").IsSvgImage()) + `)).IsSvgImage()) assert.True(t, DetectContentType([]byte(` - `), "").IsSvgImage()) + `)).IsSvgImage()) assert.True(t, DetectContentType([]byte(` - `), "").IsSvgImage()) + `)).IsSvgImage()) assert.True(t, DetectContentType([]byte(` - `), "").IsSvgImage()) + `)).IsSvgImage()) assert.True(t, DetectContentType([]byte(` - `), "").IsSvgImage()) + `)).IsSvgImage()) assert.True(t, DetectContentType([]byte(` - `), "").IsSvgImage()) + `)).IsSvgImage()) assert.True(t, DetectContentType([]byte(` - `), "").IsSvgImage()) + `)).IsSvgImage()) // the DetectContentType should work for incomplete data, because only beginning bytes are used for detection - assert.True(t, DetectContentType([]byte(`....`), "").IsSvgImage()) + assert.True(t, DetectContentType([]byte(`....`)).IsSvgImage()) - assert.False(t, DetectContentType([]byte{}, "").IsSvgImage()) - assert.False(t, DetectContentType([]byte("svg"), "").IsSvgImage()) - assert.False(t, DetectContentType([]byte(""), "").IsSvgImage()) - assert.False(t, DetectContentType([]byte("text"), "").IsSvgImage()) - assert.False(t, DetectContentType([]byte(""), "").IsSvgImage()) - assert.False(t, DetectContentType([]byte(``), "").IsSvgImage()) + assert.False(t, DetectContentType([]byte{}).IsSvgImage()) + assert.False(t, DetectContentType([]byte("svg")).IsSvgImage()) + assert.False(t, DetectContentType([]byte("")).IsSvgImage()) + assert.False(t, DetectContentType([]byte("text")).IsSvgImage()) + assert.False(t, DetectContentType([]byte("")).IsSvgImage()) + assert.False(t, DetectContentType([]byte(``)).IsSvgImage()) assert.False(t, DetectContentType([]byte(` - `), "").IsSvgImage()) + `)).IsSvgImage()) assert.False(t, DetectContentType([]byte(` - `), "").IsSvgImage()) + `)).IsSvgImage()) assert.False(t, DetectContentType([]byte(` @@ -80,7 +80,7 @@ func TestIsSvgImage(t *testing.T) { -`), "").IsSvgImage()) +`)).IsSvgImage()) assert.False(t, DetectContentType([]byte(` -`), "").IsSvgImage()) - assert.False(t, DetectContentType([]byte(``), "").IsSvgImage()) - assert.False(t, DetectContentType([]byte(``), "").IsSvgImage()) +`)).IsSvgImage()) + assert.False(t, DetectContentType([]byte(``)).IsSvgImage()) + assert.False(t, DetectContentType([]byte(``)).IsSvgImage()) } func TestIsPDF(t *testing.T) { pdf, _ := base64.StdEncoding.DecodeString("JVBERi0xLjYKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVhbQp4nF3NPwsCMQwF8D2f4s2CNYk1baF0EHRwOwg4iJt/NsFb/PpevUE4Mjwe") - assert.True(t, DetectContentType(pdf, "").IsPDF()) - assert.False(t, DetectContentType([]byte("plain text"), "").IsPDF()) + assert.True(t, DetectContentType(pdf).IsPDF()) + assert.False(t, DetectContentType([]byte("plain text")).IsPDF()) } func TestIsVideo(t *testing.T) { mp4, _ := base64.StdEncoding.DecodeString("AAAAGGZ0eXBtcDQyAAAAAGlzb21tcDQyAAEI721vb3YAAABsbXZoZAAAAADaBlwX2gZcFwAAA+gA") - assert.True(t, DetectContentType(mp4, "").IsVideo()) - assert.False(t, DetectContentType([]byte("plain text"), "").IsVideo()) + assert.True(t, DetectContentType(mp4).IsVideo()) + assert.False(t, DetectContentType([]byte("plain text")).IsVideo()) } func TestIsAudio(t *testing.T) { mp3, _ := base64.StdEncoding.DecodeString("SUQzBAAAAAABAFRYWFgAAAASAAADbWFqb3JfYnJhbmQAbXA0MgBUWFhYAAAAEQAAA21pbm9yX3Zl") - assert.True(t, DetectContentType(mp3, "").IsAudio()) - assert.False(t, DetectContentType([]byte("plain text"), "").IsAudio()) + assert.True(t, DetectContentType(mp3).IsAudio()) + assert.False(t, DetectContentType([]byte("plain text")).IsAudio()) - assert.True(t, DetectContentType([]byte("ID3Toy\000"), "").IsAudio()) - assert.True(t, DetectContentType([]byte("ID3Toy\n====\t* hi ๐ŸŒž, ..."), "").IsText()) // test ID3 tag for plain text - assert.True(t, DetectContentType([]byte("ID3Toy\n====\t* hi ๐ŸŒž, ..."+"๐ŸŒ›"[0:2]), "").IsText()) // test ID3 tag with incomplete UTF8 char + assert.True(t, DetectContentType([]byte("ID3Toy\000")).IsAudio()) + assert.True(t, DetectContentType([]byte("ID3Toy\n====\t* hi ๐ŸŒž, ...")).IsText()) // test ID3 tag for plain text + assert.True(t, DetectContentType([]byte("ID3Toy\n====\t* hi ๐ŸŒž, ..."+"๐ŸŒ›"[0:2])).IsText()) // test ID3 tag with incomplete UTF8 char } func TestIsGLB(t *testing.T) { glb, _ := hex.DecodeString("676c5446") - assert.True(t, DetectContentType(glb, "").IsGLB()) - assert.True(t, DetectContentType(glb, "").Is3DModel()) - assert.False(t, DetectContentType([]byte("plain text"), "").IsGLB()) - assert.False(t, DetectContentType([]byte("plain text"), "").Is3DModel()) + assert.True(t, DetectContentType(glb).IsGLB()) + assert.True(t, DetectContentType(glb).Is3DModel()) + assert.False(t, DetectContentType([]byte("plain text")).IsGLB()) + assert.False(t, DetectContentType([]byte("plain text")).Is3DModel()) } func TestDetectContentTypeFromReader(t *testing.T) { mp3, _ := base64.StdEncoding.DecodeString("SUQzBAAAAAABAFRYWFgAAAASAAADbWFqb3JfYnJhbmQAbXA0MgBUWFhYAAAAEQAAA21pbm9yX3Zl") - st, err := DetectContentTypeFromReader(bytes.NewReader(mp3), "") + st, err := DetectContentTypeFromReader(bytes.NewReader(mp3)) require.NoError(t, err) assert.True(t, st.IsAudio()) } func TestDetectContentTypeOgg(t *testing.T) { oggAudio, _ := hex.DecodeString("4f67675300020000000000000000352f0000000000007dc39163011e01766f72626973000000000244ac0000000000000071020000000000b8014f6767530000") - st, err := DetectContentTypeFromReader(bytes.NewReader(oggAudio), "") + st, err := DetectContentTypeFromReader(bytes.NewReader(oggAudio)) require.NoError(t, err) assert.True(t, st.IsAudio()) oggVideo, _ := hex.DecodeString("4f676753000200000000000000007d9747ef000000009b59daf3012a807468656f7261030201001e00110001e000010e00020000001e00000001000001000001") - st, err = DetectContentTypeFromReader(bytes.NewReader(oggVideo), "") + st, err = DetectContentTypeFromReader(bytes.NewReader(oggVideo)) require.NoError(t, err) assert.True(t, st.IsVideo()) } @@ -148,7 +148,7 @@ func TestDetectContentTypeAvif(t *testing.T) { avifImage, err := hex.DecodeString("000000206674797061766966") require.NoError(t, err) - st, err := DetectContentTypeFromReader(bytes.NewReader(avifImage), "") + st, err := DetectContentTypeFromReader(bytes.NewReader(avifImage)) require.NoError(t, err) assert.True(t, st.IsImage()) @@ -158,24 +158,10 @@ func TestDetectContentTypeModelGLB(t *testing.T) { glb, err := hex.DecodeString("676c5446") require.NoError(t, err) - st, err := DetectContentTypeFromReader(bytes.NewReader(glb), "") + st, err := DetectContentTypeFromReader(bytes.NewReader(glb)) require.NoError(t, err) // print st for debugging assert.Equal(t, "model/gltf-binary", st.GetMimeType()) assert.True(t, st.IsGLB()) } - -func TestDetectInterlisp(t *testing.T) { - interlisp, err := base64.StdEncoding.DecodeString("ICAKKERFRklORS1GSUxFLUlORk8gHlBBQ0tBR0UgIklOVEVSTElTUCIgHlJFQURUQUJMRSAiSU5URVJMSVNQIiAeQkFTRSAxMCkKCgYB") - require.NoError(t, err) - st, err := DetectContentTypeFromReader(bytes.NewReader(interlisp), "test") - require.NoError(t, err) - assert.True(t, st.IsText()) - st, err = DetectContentTypeFromReader(bytes.NewReader(interlisp), "") - require.NoError(t, err) - assert.False(t, st.IsText()) - st, err = DetectContentTypeFromReader(bytes.NewReader(interlisp), "test.lcom") - require.NoError(t, err) - assert.False(t, st.IsText()) -} diff --git a/modules/util/shellquote_test.go b/modules/util/shellquote_test.go index 6c1b778a08..969998c592 100644 --- a/modules/util/shellquote_test.go +++ b/modules/util/shellquote_test.go @@ -3,11 +3,7 @@ package util -import ( - "testing" - - "github.com/stretchr/testify/assert" -) +import "testing" func TestShellEscape(t *testing.T) { tests := []struct { @@ -83,23 +79,13 @@ func TestShellEscape(t *testing.T) { "Single quotes don't need to escape except for '...", "~/ ${gitea} `gitea` (gitea) !gitea! \"gitea\" \\gitea\\ 'gitea'", "~/' ${gitea} `gitea` (gitea) !gitea! \"gitea\" \\gitea\\ '\\''gitea'\\'", - }, { - "Inline command", - "some`echo foo`thing", - "\"some\\`echo foo\\`thing\"", - }, { - "Substitution", - `;${HOME}`, - `";\${HOME}"`, - }, { - "ANSI Escape codes (not escaped)", - "\033[31;1;4mHello\033[0m", - "\"\x1b[31;1;4mHello\x1b[0m\"", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.want, ShellEscape(tt.toEscape)) + if got := ShellEscape(tt.toEscape); got != tt.want { + t.Errorf("ShellEscape(%q):\nGot: %s\nWanted: %s", tt.toEscape, got, tt.want) + } }) } } diff --git a/modules/validation/email.go b/modules/validation/email.go index 7960a80a1f..8e1ffc203d 100644 --- a/modules/validation/email.go +++ b/modules/validation/email.go @@ -72,23 +72,16 @@ func validateEmailBasic(email string) error { } func validateEmailDomain(email string) error { - if _, ok := IsEmailDomainAllowed(email); !ok { + if !IsEmailDomainAllowed(email) { return ErrEmailInvalid{email} } return nil } -func IsEmailDomainAllowed(email string) (validEmail, ok bool) { - // Normalized the address. This strips for example comments which could be - // used to smuggle a different domain - parsedAddress, err := mail.ParseAddress(email) - if err != nil { - return false, false - } - - return true, isEmailDomainAllowedInternal( - parsedAddress.Address, +func IsEmailDomainAllowed(email string) bool { + return isEmailDomainAllowedInternal( + email, setting.Service.EmailDomainAllowList, setting.Service.EmailDomainBlockList) } diff --git a/modules/validation/email_test.go b/modules/validation/email_test.go index 28158cae53..b7ee766ddb 100644 --- a/modules/validation/email_test.go +++ b/modules/validation/email_test.go @@ -67,3 +67,8 @@ func TestEmailAddressValidate(t *testing.T) { }) } } + +func TestEmailDomainAllowList(t *testing.T) { + res := IsEmailDomainAllowed("someuser@localhost.localdomain") + assert.True(t, res) +} diff --git a/modules/validation/validatable.go b/modules/validation/validatable.go index 7bcca03bf8..4500f6e53d 100644 --- a/modules/validation/validatable.go +++ b/modules/validation/validatable.go @@ -45,7 +45,7 @@ func IsValid(v Validateable) (bool, error) { func ValidateIDExists(value ap.Item, name string) []string { if value == nil { - return []string{fmt.Sprintf("Field %v must not be nil", name)} + return []string{fmt.Sprintf("%v should not be nil", name)} } return ValidateNotEmpty(value.GetID().String(), name) } @@ -76,12 +76,12 @@ func ValidateNotEmpty(value any, name string) []string { if isValid { return []string{} } - return []string{fmt.Sprintf("Value %v should not be empty", name)} + return []string{fmt.Sprintf("%v should not be empty", name)} } func ValidateMaxLen(value string, maxLen int, name string) []string { if utf8.RuneCountInString(value) > maxLen { - return []string{fmt.Sprintf("Value %v is longer than expected length %v", name, maxLen)} + return []string{fmt.Sprintf("Value %v was longer than %v", name, maxLen)} } return []string{} } diff --git a/options/locale/locale_ar.ini b/options/locale/locale_ar.ini index 23351d9cbf..ca74a477ce 100644 --- a/options/locale/locale_ar.ini +++ b/options/locale/locale_ar.ini @@ -23,7 +23,9 @@ explore = ุฅูƒุชุดู return_to_forgejo = ุงู„ุนูˆุฏุฉ ุฅู„ู‰ ููˆุฑุฌูŠูˆ write = ุงูƒุชุจ webauthn_error_unknown = ุญุฏุซ ุฎุทุฃ ุบูŠุฑ ู…ุนุฑูˆู. ู…ู† ูุถู„ูƒ ุญุงูˆู„ ู…ุฌุฏุฏุงู‹. +webauthn_reload = ุฅุนุงุฏุฉ ุชุญู…ูŠู„ twofa = ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ +account_settings = ุฅุนุฏุงุฏุงุช ุงู„ุญุณุงุจ version = ุงู„ุฅุตุฏุงุฑ copy_success = ุชู… ุงู„ู†ุณุฎ! help = ู…ุณุงุนุฏุฉ @@ -64,6 +66,7 @@ webauthn_unsupported_browser = ู…ุชุตูุญูƒ ู„ุง ูŠุฏุนู… ูˆูŠุจ ุขูˆุซู† ุญุงู„ copy = ุงู†ุณุฎ enabled = ู…ูููŽุนู‘ูŽู„ rerun = ุฃุนูุฏ ุงู„ุชุดุบูŠู„ +new_org = ู…ู†ุธู…ุฉ ุฌุฏูŠุฏุฉ milestones = ุฃู‡ุฏุงู webauthn_error_insecure = ูˆูŠุจ ุขูˆุซู† ูŠุฏุนู… ูู‚ุท ุงู„ุงุชุตุงู„ุงุช ุงู„ุขู…ู†ุฉ. ู„ู„ุงุฎุชุจุงุฑ ุนู„ู‰ HTTPุŒ ูŠู…ูƒู†ูƒ ุงุณุชุฎุฏุงู… "localhost" ุฃูˆ "127.0.0.1" show_timestamps = ุฅุธู‡ุงุฑ ุงู„ุทูˆุงุจุน ุงู„ุฒู…ู†ูŠุฉ @@ -86,9 +89,12 @@ new_project_column = ุนู…ูˆุฏ ุฌุฏูŠุฏ add = ุฃุถู active_stopwatch = ู…ุชุชุจู‘ูุน ูˆู‚ุช ุงู„ู†ุดุงุท organization = ู…ู†ุธู…ุฉ +new_migrate = ุชุฑุญูŠู„ ุฌุฏูŠุฏ save = ุงุญูุธ sign_in_with_provider = ุณุฌู„ ุงู„ุฏุฎูˆู„ ุจู€ %s ok = ูˆุงูู‚ +manage_org = ุฅุฏุงุฑุฉ ุงู„ู…ู†ุธู…ุงุช +new_repo = ู…ุณุชูˆุฏุน ุฌุฏูŠุฏ webauthn_error_unable_to_process = ุงู„ุฎุงุฏู… ู„ุง ูŠู…ูƒู†ู‡ ู…ุนุงู„ุฌุฉ ุทู„ุจูƒ. register = ุณุฌู„ mirror = ู…ุฑุขุฉ @@ -138,9 +144,10 @@ new_migrate.title = ุงู†ุชู‚ุงู„ ุฌุฏูŠุฏ new_org.title = ู…ู†ุธู…ุฉ ุฌุฏูŠุฏุฉ new_repo.link = ู…ุณุชูˆุฏุน ุฌุฏูŠุฏ new_migrate.link = ุงู†ุชู‚ุงู„ ุฌุฏูŠุฏ -copy_path = ู†ุณุฎ ุงู„ู…ุณุงุฑ -test = ุงุฎุชุจุงุฑ + new_org.link = ู…ู†ุธู…ุฉ ุฌุฏูŠุฏุฉ +test = ุงุฎุชุจุงุฑ +copy_path = ู†ุณุฎ ุงู„ู…ุณุงุฑ error413 = ู„ู‚ุฏ ุงุณุชู†ูุฏุช ุญุตุชูƒ. [install] @@ -160,7 +167,7 @@ ssl_mode = SSL db_title = ุฅุนุฏุงุฏุงุช ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช install = ุงู„ุชุซุจูŠุช allow_dots_in_usernames = ุงู„ุณู…ุงุญ ู„ู„ู…ุณุชุฎุฏู…ูŠู† ุจูˆุถุน ู†ู‚ุงุท ููŠ ุฃุณู…ุงุฆู‡ู…. ู„ุง ูŠุคุซุฑ ุนู„ู‰ ุงู„ุญุณุงุจุงุช ุงู„ู…ูˆุฌูˆุฏุฉ. -enable_update_checker_helper_forgejo = ูŠูุญุต ุฏูˆุฑูŠุงู‹ ู„ู†ุณุฎ ุฌุฏูŠุฏุฉ ู…ู† ููˆุฑุฌูŠูˆ ุนู† ุทุฑูŠู‚ ุงู„ุชุญู‚ู‚ ู…ู† ุณุฌู„ TXT DNS ุนู†ุฏ release.forgejo.org. +enable_update_checker_helper_forgejo = ูŠูุญุต ุฏูˆุฑูŠุงู‹ ู„ู†ุณุฎ ุฌุฏูŠุฏุฉ ู…ู† ููˆุฑุฌูŠูˆ ุนู† ุทุฑูŠู‚ ุงู„ุชุญู‚ู‚ ู…ู† ุณุฌู„ DNS TXT ุนู†ุฏ release.forgejo.org. db_schema_helper = ุงุชุฑูƒู‡ ูุงุฑุบุงู‹ ู„ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช ุงู„ุงูุชุฑุงุถูŠุฉ ("ุนุงู…"). db_type = ู†ูˆุน ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช reinstall_confirm_check_1 = ุงู„ุจูŠุงู†ุงุช ุงู„ู…ุดูุฑุฉ ุจูˆุงุณุทุฉ SECRET_KEY ููŠ ู…ูู„ูŽูู‘ app.ini ู‚ุฏ ุชููู‚ุฏ: ู‚ุฏ ู„ุง ูŠุชู…ูƒู† ุงู„ู…ุณุชุฎุฏู…ูˆู† ู…ู† ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุจุงุณุชุฎุฏุงู… ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ (2FA/OTP) ูˆ ุงู„ู…ุฑุงูŠุงุช ู‚ุฏ ู„ุง ุชุนู…ู„ ุจุงู„ุดูƒู„ ุงู„ุตุญูŠุญ. ู…ู† ุฎู„ุงู„ ุชุญุฏูŠุฏ ู‡ุฐุง ุงู„ู…ุฑุจุน ุฃู†ุช ุชุคูƒุฏ ุฃู† ู…ูู„ูŽูู‘ app.ini ุงู„ุญุงู„ูŠ ูŠุญุชูˆูŠ ุนู„ู‰ ุงู„ู€SECRET_KEY ุงู„ุตุญูŠุญ. @@ -220,9 +227,9 @@ enable_captcha.description = ู…ุทุงู„ุจุฉ ุงู„ู…ุณุชุฎุฏู…ูŠู† ุจุงุฌุชูŠุงุฒ ุง openid_signup.description = ูุนู‘ู„ ุงู„ุชุณุฌูŠู„ ุงู„ุฐุงุชูŠ ู„ู„ู…ุณุชุฎุฏู…ูŠู† ุนุจุฑ OpenID. require_sign_in_view = ูŠุชุทู„ุจ ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ู„ุนุฑุถ ู…ุญุชูˆู‰ ุงู„ู…ุซูŠู„ require_sign_in_view.description = ู…ูƒู‘ู† ูˆุตูˆู„ ุงู„ุตูุญุงุช ู„ู„ู…ุณุชุฎุฏู…ูŠู† ูู‚ุท. ู„ู† ูŠุฑู‰ ุงู„ุฒุงุฆุฑูˆู† ุณูˆู‰ ุตูุญุงุช ุงู„ุชุณุฌูŠู„ ูˆุงู„ุชุณุฌูŠู„. -admin_setting.description = ุฅู†ุดุงุก ุญุณุงุจ ุฅุฏุงุฑูŠ ู‡ูˆ ุงุฎุชูŠุงุฑูŠ. ุฃูˆู„ ู…ุณุชุฎุฏู… ู…ูุณุฌู„ ุณูŠุตุจุญ ุชู„ู‚ุงุฆูŠุง ู…ุฏูŠุฑู‹ุง. +admin_setting.description = ุฅู†ุดุงุก ุญุณุงุจ ุฅุฏุงุฑูŠ ู‡ูˆ ุงุฎุชูŠุงุฑูŠ. ุฃูˆู„ ู…ุณุชุฎุฏู… ู…ูุณุฌู„ ุณูŠุตุจุญ ุชู„ู‚ุงุฆูŠุง ู…ุฏูŠุฑุง. admin_password = ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ -admin_email = ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ +admin_email = ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ install_btn_confirm = ุชุซุจุช ููˆุฑุฌูŠูˆ secret_key_failed = ู„ู… ูŠุชู… ุชูˆู„ูŠุฏ ู…ูุชุงุญ ุณุฑูŠ: %v save_config_failed = ูุดู„ ููŠ ุญูุธ ุงู„ุฅุนุฏุงุฏ: %s @@ -244,20 +251,22 @@ default_keep_email_private.description = ู‚ู… ุจุชู…ูƒูŠู† ุฅุฎูุงุก ุนู†ูˆุงู† env_config_keys = ุฅุนุฏุงุฏุงุช ุจูŠุฆูŠุฉ default_allow_create_organization = ุงุณู…ุญ ุจุฅู†ุดุงุก ุงู„ู…ู†ุธู…ุงุช ุจุดูƒู„ ุงูุชุฑุงุถูŠ invalid_app_data_path = ู…ุณุงุฑ ุจูŠุงู†ุงุช ุงู„ุชุทุจูŠู‚ ุบูŠุฑ ุตุงู„ุญ: %v +enable_update_checker_helper = ูŠูุญุต ู„ุฅูŠุฌุงุฏ ุงุตุฏุงุฑุงุช ุฌุฏูŠุฏุฉ ุนู† ุทุฑูŠู‚ ุงู„ุฅุชุตุงู„ ุจุณูŠุฑูุฑุงุช ููˆุฑุฌูŠูˆ. invalid_repo_path = ุงู„ู…ุณุงุฑ ุงู„ุฌุฒุฑูŠ ู„ู„ู…ุณุชูˆุฏุน ุบูŠุฑ ุตุงู„ุญ: %v internal_token_failed = ูุดู„ ุชูˆู„ูŠุฏ ุงู„ุฑู…ุฒ ุงู„ุฏุงุฎู„ูŠ: %v -no_reply_address = ู†ุทุงู‚ ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ู…ุฎููŠ +no_reply_address = ู†ุทุงู‚ุงุช ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ุงู„ู…ุฎููŠุฉ default_keep_email_private = ุฃุฎูู ุนู†ุงูˆูŠู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ู…ุจุฏุฆูŠุง admin_name = ุงุณู… ู…ุณุชุฎุฏู… ุงู„ู…ุฏูŠุฑ default_allow_create_organization.description = ุงู„ุณู…ุงุญ ู„ู„ู…ุณุชุฎุฏู…ูŠู† ุงู„ุฌุฏุฏ ุจุฅู†ุดุงุก ู…ู†ุชุฏูŠุงุช ุงู„ู…ุฌู…ูˆุนุฉ ุจุดูƒู„ ุงูุชุฑุงุถูŠ. ุนู†ุฏ ุชุนุทูŠู„ ู‡ุฐุง ุงู„ุฎูŠุงุฑุŒ ุณูŠุชุนูŠู† ุนู„ู‰ ุงู„ู…ุณุคูˆู„ ู…ู†ุญ ุฅุฐู† ู„ุฅู†ุดุงุก ู…ู†ุชุฏูŠุงุช ุงู„ู…ุฌู…ูˆุนุฉ ู„ู„ู…ุณุชุฎุฏู…ูŠู† ุงู„ุฌุฏุฏ. password_algorithm = ุฎูˆุงุฑุฒู…ูŠุฉ ุชุฌุฒุฆุฉ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ invalid_password_algorithm = ุฎูˆุงุฑุฒู…ูŠุฉ ุจุตู…ุฉ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ุบูŠุฑ ุตุงู„ุญุฉ -password_algorithm_helper = ุงุฎุชุฑ ุฎูˆุงุฑุฒู…ูŠุฉ ุจุตู…ุฉ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ. ุชุฎุชู„ู ุงู„ุฎูˆุงุฑุฒู…ูŠุงุช ููŠ ู…ุชุทู„ุจุงุชู‡ุง ูˆู‚ูŠูˆุงู‡ุง. ุฎูˆุงุฑุฒู…ูŠุฉ argon2 ุขู…ู†ุฉ ู„ูƒู† ุชุชุทู„ุจ ุงู„ูƒุซูŠุฑ ู…ู† ุงู„ุฐุงูƒุฑุฉ ูˆู„ุฐู„ูƒ ู‚ุฏ ุชูƒูˆู† ุบูŠุฑ ู…ู„ุงุฆู…ุฉ ู„ู„ุฃู†ุธู…ุฉ ุงู„ุตุบูŠุฑุฉ. -app_slogan_helper = ุฃุฏุฎู„ ุดุนุงุฑ ุงู„ู…ุซูŠู„ ุงู„ุฎุงุต ุจูƒ ู‡ู†ุง. ุงุชุฑูƒู‡ ูุงุฑุบุงู‹ ู„ุชุนุทูŠู„ู‡. +password_algorithm_helper = ุงุฎุชุฑ ุฎูˆุงุฑุฒู…ูŠุฉ ุจุตู…ุฉ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ. ุชุฎุชู„ู ุงู„ุฎูˆุงุฑุฒู…ูŠุงุช ููŠ ู…ุชุทู„ุจุงุชู‡ุง ูˆู‚ูˆุชู‡ุง. ุฎูˆุงุฑุฒู…ูŠุฉ argon2 ุขู…ู†ุฉ ู„ูƒู† ุชุชุทู„ุจ ุงู„ูƒุซูŠุฑ ู…ู† ุงู„ุฐุงูƒุฑุฉ ูˆู„ุฐู„ูƒ ู‚ุฏ ุชูƒูˆู† ุบูŠุฑ ู…ู„ุงุฆู…ุฉ ู„ู„ุฃู†ุธู…ุฉ ุงู„ุตุบูŠุฑุฉ. + app_slogan = ุดุนุงุฑ ุงู„ู…ุซูŠู„ +app_slogan_helper = ุฃุฏุฎู„ ุดุนุงุฑ ุงู„ู…ุซูŠู„ ุงู„ุฎุงุต ุจูƒ ู‡ู†ุง. ุงุชุฑูƒู‡ ูุงุฑุบุงู‹ ู„ุชุนุทูŠู„ู‡. +smtp_from_invalid = ุนู†ูˆุงู† "ุŒุจุฑูŠุฏ ุงู„ุฅุฑุณุงู„ ูƒู€" ุบูŠุฑ ุตุงู„ุญ allow_only_external_registration = ุงู„ุณู…ุงุญ ุจุงู„ุชุณุฌูŠู„ ุนุจุฑ ุงู„ุฎุฏู…ุงุช ุงู„ุฎุงุฑุฌูŠุฉ ูู‚ุท config_location_hint = ุณูŠุชู… ุญูุธ ุฎูŠุงุฑุงุช ุงู„ุชู‡ูŠุฆุฉ ู‡ุฐู‡ ููŠ: -smtp_from_invalid = ุนู†ูˆุงู† "ุŒุจุฑูŠุฏ ุงู„ุฅุฑุณุงู„ ูƒู€" ุบูŠุฑ ุตุงู„ุญ [editor] buttons.list.ordered.tooltip = ุฃุถู ู‚ุงุฆู…ุฉ ู…ุฑู‚ู…ุฉ @@ -274,17 +283,18 @@ buttons.mention.tooltip = ุงุฐูƒุฑ ู…ุณุชุฎุฏู…ู‹ุง ุฃูˆ ูุฑูŠู‚ู‹ุง buttons.italic.tooltip = ุฃุถู ู†ุตู‹ุง ู…ุงุฆู„ู‹ุง buttons.link.tooltip = ุงุถู ุฑุงุจุท buttons.disable_monospace_font = ุนุทู‘ู„ ุงู„ุฎุท ุงู„ุซุงุจุช ุงู„ุนุฑุถ -buttons.unindent.tooltip = โ€ชุนู†ุงุตุฑ ุบูŠุฑ ู…ุชุณุงูˆูŠุฉ ู…ู† ู†ูุณ ุงู„ู…ุณุชูˆู‰ + buttons.indent.tooltip = ุชุฏุงุฎู„ ุงู„ุนู†ุงุตุฑ ุจู†ูุณ ุงู„ู…ุณุชูˆู‰ +buttons.unindent.tooltip = โ€ชุนู†ุงุตุฑ ุบูŠุฑ ู…ุชุณุงูˆูŠุฉ ู…ู† ู†ูุณ ุงู„ู…ุณุชูˆู‰ +buttons.new_table.tooltip = ุฅุถุงูุฉ ุฌุฏูˆู„ table_modal.header = ุฅุถุงูุฉ ุฌุฏูˆู„ table_modal.placeholder.header = ุงู„ุชุฑูˆูŠุณุฉ table_modal.placeholder.content = ุงู„ู…ุญุชูˆู‰ table_modal.label.rows = ุงู„ุตููˆู table_modal.label.columns = ุงู„ุฃุนู…ุฏุฉ +link_modal.header = ุฅุถุงูุฉ ุฑุงุจุท link_modal.url = Url link_modal.description = ุงู„ูˆุตู -buttons.new_table.tooltip = ุฅุถุงูุฉ ุฌุฏูˆู„ -link_modal.header = ุฅุถุงูุฉ ุฑุงุจุท link_modal.paste_reminder = ุชู„ู…ูŠุญ: ุจุงุณุชุฎุฏุงู… ุนู†ูˆุงู† URL ููŠ ุญุงูุธุชูƒุŒ ูŠู…ูƒู†ูƒ ุงู„ู„ุตู‚ ู…ุจุงุดุฑุฉู‹ ููŠ ุงู„ู…ุญุฑุฑ ู„ุฅู†ุดุงุก ุฑุงุจุท. [aria] @@ -302,31 +312,31 @@ blocked_since = ู…ุญุธูˆุฑ ู…ู†ุฐ %s comment_type_group_milestone = ุงู„ุฃู‡ุฏุงู ui = ุงู„ุณู…ุฉ email_notifications.disable = ุนุทู‘ู„ ุฅุดุนุงุฑุงุช ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ -passcode_invalid = ุฑู…ุฒ ุงู„ุฏุฎูˆู„ ุฎุทุฃ. ุญุงูˆู„ ู…ุฌุฏุฏุงู‹. +passcode_invalid = ุฑู…ุฒ ุงู„ุฏุฎูˆู„ ุฎุทุฃ. ุญุงูˆู„ ู…ุฑุฉ ุฃุฎุฑู‰. openid_deletion = ุฃุฒู„ ุนู†ูˆุงู† OpenID activate_email = ุฃุฑุณู„ ุงู„ุชูุนูŠู„ uploaded_avatar_not_a_image = ุงู„ู…ู„ู ุงู„ู…ุฑููˆุน ู„ูŠุณ ุตูˆุฑุฉ. theme_update_error = ุงู„ุณู…ุฉ ุงู„ู…ุฎุชุงุฑุฉ ุบูŠุฑ ู…ูˆุฌูˆุฏุฉ. -twofa_disabled = ุชู… ุชุนุทูŠู„ ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ. +twofa_disabled = ุนูุทู‘ูู„ ุงู„ุงุณุชูŠุซุงู‚ ุงู„ุซู†ุงุฆูŠ. theme_desc = ุณุชูƒูˆู† ู‡ุฐู‡ ุงู„ุณู…ุฉ ุงู„ู…ุจุฏุฆูŠุฉ ู„ูƒ ุนุจุฑ ุงู„ู…ูˆู‚ุน. new_password = ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ุงู„ุฌุฏูŠุฏุฉ -twofa_disable_desc = ุชุนุทูŠู„ ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ ุณูŠุฌุนู„ ุญุณุงุจูƒ ุฃู‚ู„ ุฃู…ุงู†ุงู‹. ุงู„ุงุณุชู…ุฑุงุฑุŸ +twofa_disable_desc = ุชุนุทูŠู„ ุงู„ุงุณุชูŠุซุงู‚ ุงู„ุซู†ุงุฆูŠ ุณูŠุฌุนู„ ุญุณุงุจูƒ ุฃู‚ู„ ุฃู…ุงู†ู‹ุง. ุฃุชุฑูŠุฏ ุงู„ุงุณุชู…ุฑุงุฑุŸ manage_themes = ุงู„ู…ูˆุถูˆุน ุงู„ุงูุชุฑุงุถูŠ -delete_prompt = ู‡ุฐู‡ ุงู„ุนู…ู„ูŠุฉ ุณุชุญุฐู ุญุณุงุจูƒ ุฅู„ู‰ ุงู„ุฃุจุฏ. ู„ุง ูŠู…ูƒู† ุงู„ุชุฑุงุฌุน ุนู† ุฐู„ูƒ. -cancel = ุฅู„ุบุงุก -repos_none = ู„ุง ุชู…ู„ูƒ ุฃูŠุฉ ู…ุณุชูˆุฏุน. +delete_prompt = ู‡ุฐู‡ ุงู„ุนู…ู„ูŠุฉ ุณุชุญุฐู ุญุณุงุจูƒ ุฅู„ู‰ ุงู„ุฃุจุฏ. ู„ุง ูŠู…ูƒู† ุงู„ุชุฑุงุฌุน ุนู†ู‡ุง ุจุนุฏ ุฐู„ูƒ. +cancel = ุฃู„ุบ +repos_none = ู„ูŠุณ ู„ุฏูŠูƒ ุฃูŠ ู…ุณุชูˆุฏุน. twofa_desc = ู„ุญู…ุงูŠุฉ ุญุณุงุจูƒ ู…ู† ุณุฑู‚ุฉ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑุŒ ูŠู…ูƒู†ูƒ ุงุณุชุฎุฏุงู… ู‡ุงุชู ุฐูƒูŠ ุฃูˆ ุฌู‡ุงุฒ ุขุฎุฑ ู„ุงุณุชู„ุงู… ูƒู„ู…ุฉ ู…ุฑูˆุฑ ู…ุคู‚ุชุฉ ุฐุงุช ุงุณุชุฎุฏุงู… ูˆุงุญุฏ ("TOTP"). -email_notifications.submit = ุถุจุท ุชูุถูŠู„ุงุช ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ +email_notifications.submit = ุงุถุจุท ุชูุถูŠู„ุงุช ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ update_user_avatar_success = ุญูุฏู‘ูุซุช ุตูˆุฑุฉ ุงู„ู…ุณุชุฎุฏู… ุงู„ุฑู…ุฒูŠุฉ. activations_pending = ููŠ ุงู†ุชุธุงุฑ ุงู„ุชูุนูŠู„ -language = ุงู„ู„ู‘ุบุฉ +language = ุงู„ู„ุบุฉ primary = ุงู„ุฃุณุงุณูŠ update_avatar_success = ุญูุฏู‘ูุซุช ุตูˆุฑุชูƒ ุงู„ุฑู…ุฒูŠุฉ. keep_email_private = ุฃุฎูู ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ delete_current_avatar = ุงุญุฐู ุงู„ุตูˆุฑุฉ ุงู„ุฑู…ุฒูŠุฉ ุงู„ุญุงู„ูŠุฉ avatar = ุตูˆุฑุฉ ุฑู…ุฒูŠุฉ email_preference_set_success = ุญูุฏู‘ูุซุช ุชูุถูŠู„ุงุช ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ. -scan_this_image = ุงู…ุณุญ ู‡ุฐู‡ ุงู„ุตูˆุฑุฉ ุจุชุทุจูŠู‚ ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุฐูŠ ุชุณุชุฎุฏู…ู‡: +scan_this_image = ุงู…ุณุญ ู‡ุฐู‡ ุงู„ุตูˆุฑุฉ ุจุชุทุจูŠู‚ ุงู„ุงุณุชูŠุซุงู‚ ุงู„ุฐูŠ ุชุณุชุฎุฏู…ู‡: orgs_none = ู„ุณุช ุนุถูˆู‹ุง ููŠ ุฃูŠ ู…ู†ุธู…ุฉ. delete_email = ุฃุฒู„ู‡ theme_update_success = ุญูุฏู‘ูุซุช ุงู„ุณู…ุฉ. @@ -353,17 +363,19 @@ openid_deletion_success = ุฃุฒูŠู„ ุนู†ูˆุงู† OpenID. add_email_success = ุฃุถูŠู ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ุงู„ุฌุฏูŠุฏ. enable_custom_avatar = ุงุณุชุฎุฏู… ุตูˆุฑุฉ ุฑู…ุฒูŠุฉ ู…ุฎุตุตุฉ update_avatar = ุญุฏู‘ุซ ุงู„ุตูˆุฑุฉ ุงู„ุฑู…ุฒูŠุฉ -twofa_disable = ุชุนุทูŠู„ ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ +twofa_disable = ุชุนุทูŠู„ ุงู„ุงุณุชูŠุซุงู‚ ุงู„ุซู†ุงุฆูŠ retype_new_password = ุชุฃูƒูŠุฏ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ุงู„ุฌุฏูŠุฏุฉ manage_emails = ุฃุฏุฑ ุนู†ุงูˆูŠู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ then_enter_passcode = ูˆุฃุฏุฎู„ ุฑู…ุฒ ุงู„ุฏุฎูˆู„ ุงู„ุธุงู‡ุฑ ููŠ ุงู„ุชุทุจูŠู‚: update_password = ุญุฏู‘ุซ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ continue = ุงุณุชู…ุฑ -confirm_delete_account = ุชุฃูƒูŠุฏ ุงู„ุญุฐู +emails = ุนู†ุงูˆูŠู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ +confirm_delete_account = ุฃูƒูุฏ ุงู„ุญุฐู change_password_success = ุญูุฏู‘ูุซุช ูƒู„ู…ุฉ ู…ุฑูˆุฑูƒ. ุณุฌู‘ู„ ุงู„ุฏุฎูˆู„ ุจูƒู„ู…ุฉ ู…ุฑูˆุฑูƒ ุงู„ุฌุฏูŠุฏุฉ ู…ู† ุงู„ุขู† ูุตุงุนุฏุง. email_deletion_desc = ุณูŠูุฒุงู„ ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ู‡ุฐุง ู…ุน ูƒู„ ุงู„ู…ุนู„ูˆู…ุงุช ุงู„ู…ุฑุชุทุจุฉ ุจู‡ ู…ู† ุญุณุงุจูƒ. ู„ูƒู† ุณุชุจู‚ู‰ ุฅูŠุฏุงุนุงุช Git ุงู„ู…ูˆุฏุนุฉ ุจู‡ ุจู„ุง ุชุบูŠูŠุฑ. ุฃุชุฑูŠุฏ ุงู„ุงุณุชู…ุฑุงุฑุŸ or_enter_secret = ุฃูˆ ุฃุฏุฎู„ ุงู„ุณุฑ: %s applications = ุงู„ุชุทุจูŠู‚ุงุช +access_token_deletion_cancel_action = ุฃู„ุบู location = ุงู„ู…ูˆู‚ุน ุงู„ุฌุบุฑุงููŠ password = ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ comment_type_group_title = ุงู„ุนู†ูˆุงู† @@ -371,17 +383,20 @@ location_placeholder = ุดุงุฑูƒ ู…ูƒุงู†ูƒ ุงู„ุชู‚ุฑูŠุจูŠ ู…ุน ุงู„ุขุฎุฑูŠู† appearance = ุงู„ู…ุธู‡ุฑ repos = ุงู„ู…ุณุชูˆุฏุนุงุช change_username = ุชู… ุชุญุฏูŠุซ ุงุณู… ู…ุณุชุฎุฏู…ูƒ. +social = ุงู„ุญุณุงุจุงุช ุงู„ุงุฌุชู…ุงุนูŠุฉ twofa = ุงู„ุงุณุชูŠุซุงู‚ ุงู„ุซู†ุงุฆูŠ saved_successfully = ุญูุฏู‘ูุซุช ุฅุนุฏุงุฏุงุชูƒ ุจู†ุฌุงุญ. update_theme = ุญุฏู‘ูุซ ุงู„ุณู…ุฉ +access_token_deletion_confirm_action = ุงุญุฐู website = ุงู„ู…ูˆู‚ุน ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ -delete_token = ุญุฐู +delete_token = ุงุญุฐู hidden_comment_types.ref_tooltip = ุงู„ุชุนู„ูŠู‚ุงุช ุงู„ุชูŠ ุชู‚ูˆู„ ุฃู† ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ ู‚ุฏ ุฃุดูŠุฑ ุฅู„ูŠู‡ุง ููŠ ู…ุณุฃู„ุฉ ุฃุฎุฑู‰ ุฃูˆ ุฅูŠุฏุงุน ุฃูˆ ุบูŠุฑ ุฐู„ูƒโ€ฆ update_language_success = ุชู… ุชุญุฏูŠุซ ุงู„ู„ุบุฉ. privacy = ุงู„ุฎุตูˆุตูŠุฉ comment_type_group_label = ุงู„ุชุตู†ูŠูุงุช +account_link = ุงู„ุญุณุงุจุงุช ุงู„ู…ุฑุชุจุทุฉ comment_type_group_assignee = ุงู„ู…ูƒู„ููˆู† -update_language = ุชุบูŠูŠุฑ ุงู„ู„ุบุฉ +update_language = ุญุฏู‘ูุซ ุงู„ู„ุบุฉ organization = ุงู„ู…ู†ุธู…ุงุช update_language_not_found = ุงู„ู„ุบุฉ "%s" ุบูŠุฑ ู…ุชุงุญุฉ. update_profile_success = ุชู… ุชุญุฏูŠุซ ู…ู„ููƒ ุงู„ุดุฎุตูŠ. @@ -409,7 +424,7 @@ can_write_info = ูƒุชุงุจุฉ delete = ุงุญุฐู ุงู„ุญุณุงุจ oauth2_application_name = ุงุณู… ุงู„ุชุทุจูŠู‚ key_state_desc = ู‡ุฐุง ุงู„ู…ูุชุงุญ ุฃุณุชูุนู…ู„ ุฎู„ุงู„ ุขุฎุฑ 7 ุฃูŠุงู… -webauthn_delete_key = ุฅุฒุงู„ุฉ ู…ูุชุงุญ ุงู„ุฃู…ุงู† +webauthn_delete_key = ุฃุฒูู„ ู…ูุชุงุญ ุงู„ุฃู…ุงู† valid_forever = ุตุงู„ุญ ู„ู„ุฃุจุฏ can_read_info = ู‚ุฑุงุกุฉ create_oauth2_application_button = ุฃู†ุดุฆ ุชุทุจูŠู‚ุง @@ -421,13 +436,14 @@ select_permissions = ุฃุฎุชุฑ ุงู„ุชุตุงุฑูŠุญ added_on = ู…ูุถุงู ููŠ %s show_openid = ุฃุธู‡ุฑ ุนู„ู‰ ุงู„ู…ู„ู ุงู„ุดุฎุตูŠ hide_openid = ุฃุฎููŠ ู…ู† ุงู„ู…ู„ู ุงู„ุดุฎุตูŠ -webauthn_delete_key_desc = ุฅุฐุง ุฃุฒู„ุช ู…ูุชุงุญ ุงู„ุฃู…ุงู†ุŒ ูู„ู† ุชุชู…ูƒู† ู…ู† ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุจุงุณุชุฎุฏุงู…ู‡. ุงู„ู…ุชุงุจุนุฉุŸ +webauthn_delete_key_desc = ุฅุฐุง ุฃุฒู„ุช ู…ูุชุงุญ ุงู„ุฃู…ุงู†ุŒ ูู„ู† ุชุชู…ูƒู† ู…ู† ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุจุงุณุชุฎุฏุงู…ู‡. ุงูƒู…ู„ุŸ permissions_list = ุงู„ุชุตุงุฑูŠุญ: webauthn_key_loss_warning = ุฅุฐุง ูู‚ุฏุช ู…ูุงุชูŠุญ ุงู„ุฃู…ุงู† ุงู„ุฎุงุตุฉ ุจูƒุŒ ูุณูˆู ุชูู‚ุฏ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ. -hooks.desc = ุฅุถุงูุฉ ุฎุทุงุทูŠู ูˆูŠุจ ุณูŠุชู… ุชุดุบูŠู„ู‡ุง ู„ู€ ุฌู…ูŠุน ุงู„ู…ุณุชูˆุฏุนุงุช ุงู„ุชูŠ ุชู…ุชู„ูƒู‡ุง. +hooks.desc = ุฃุถู ุฎุทุงุทูŠู ูˆูŠุจ ุชูุทู„ู‚ ู„ูƒู„ ู…ุณุชูˆุฏุนุงุชูƒ. +keep_activity_private_popup = ูŠุฌุนู„ ุงู„ู†ุดุงุท ู…ุฑุฃูŠุงู‹ ู„ูƒ ูˆู„ู„ู…ุฏูŠุฑูŠู† ูู‚ุท keep_email_private_popup = ุณูŠุคุฏูŠ ู‡ุฐุง ุฅู„ู‰ ุฅุฎูุงุก ุนู†ูˆุงู† ุจุฑูŠุฏูƒ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ู…ู† ู…ู„ููƒ ุงู„ุดุฎุตูŠุŒ ูˆูƒุฐู„ูƒ ุนู†ุฏ ุชู‚ุฏูŠู… ุทู„ุจ ุณุญุจ ุฃูˆ ุชุญุฑูŠุฑ ู…ู„ู ุจุงุณุชุฎุฏุงู… ูˆุงุฌู‡ุฉ ุงู„ูˆูŠุจ. ู„ู† ูŠุชู… ุชุนุฏูŠู„ ุงู„ุงู„ุชุฒุงู…ุงุช ุงู„ู…ุฏููˆุนุฉ. ุงุณุชุฎุฏู… %s ููŠ ุงู„ุฅูŠุฏุงุนุงุช ู„ุฑุจุทู‡ุง ุจุญุณุงุจูƒ. ssh_key_name_used = ู‡ู†ุงูƒ ู…ูุชุงุญ SSH ุจู†ูุณ ุงู„ุงุณู… ู…ูˆุฌูˆุฏ ุจุงู„ูุนู„ ุนู„ู‰ ุญุณุงุจูƒ. -authorized_oauth2_applications = ุชุทุจูŠู‚ุงุช OAuth2 ุงู„ู…ุฃุฐูˆู† ู„ู‡ุง +authorized_oauth2_applications = ุชุทุจูŠู‚ุงุช OAuth2 ุงู„ู…ุฃุฐูˆู†ุฉ uid = ุงู„ู…ุนุฑู‘ู ุงู„ุฑู…ุฒูŠ manage_openid = ุนู†ุงูˆูŠู† OpenID webauthn = ุงุณุชูŠุซุงู‚ ุซู†ุงุฆูŠ (ู…ูุงุชูŠุญ ุงู„ุฃู…ุงู†) @@ -438,6 +454,7 @@ keep_activity_private = ุงุฎู ุงู„ู†ุดุงุท ู…ู† ุตูุญุฉ ุงู„ู…ู„ู ุงู„ุดุฎุต profile_desc = ุชุญูƒู… ููŠ ูƒูŠููŠุฉ ุธู‡ูˆุฑ ู…ู„ููƒ ุงู„ุดุฎุตูŠ ู„ู„ู…ุณุชุฎุฏู…ูŠู† ุงู„ุขุฎุฑูŠู†. ุณูŠุชู… ุงุณุชุฎุฏุงู… ุนู†ูˆุงู† ุจุฑูŠุฏูƒ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ุงู„ุฃุณุงุณูŠ ู„ู„ุฅุดุนุงุฑุงุช ูˆุงุณุชุนุงุฏุฉ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ูˆุนู…ู„ูŠุงุช Git ุงู„ู…ุนุชู…ุฏุฉ ุนู„ู‰ ุงู„ูˆูŠุจ. can_not_add_email_activations_pending = ู‡ู†ุงูƒ ุชูุนูŠู„ ู‚ูŠุฏ ุงู„ุงู†ุชุธุงุฑุŒ ุญุงูˆู„ ู…ุฌุฏุฏุงู‹ ุฎู„ุงู„ ุจุถุน ุฏู‚ุงุฆู‚ ุฅู† ุฃุฑุฏุช ุฃุถุงูู‡ ุจุฑูŠุฏ ุฅู„ูƒุชุฑูˆู†ูŠ ุฌุฏูŠุฏ. gpg_key_id_used = ู‡ู†ุงูƒ ู…ูุชุงุญ GPG ุนุงู… ุจู†ูุณ ุงู„ู…ุนุฑู ู…ูˆุฌูˆุฏ ุจุงู„ูุนู„. +add_new_gpg_key = ุฃุถู ู…ูุชุงุญ GPG manage_gpg_keys = ุฅุฏุงุฑุฉ ู…ูุงุชูŠุญ GPG password_username_disabled = ู„ุง ูŠู…ูƒู† ู„ู„ู…ุณุชุฎุฏู…ูŠู† ุบูŠุฑ ุงู„ู…ุญู„ูŠูŠู† ุฃู† ูŠุบูŠุฑูˆุง ุงุณู…ู‡ู…. ูŠูุฑุฌู‰ ุงู„ุชูˆุงุตู„ ู…ุน ู…ุฏูŠุฑ ุงู„ู…ูˆู‚ุน ู„ุชูุงุตูŠู„ ุฃูƒุซุฑ. comment_type_group_issue_ref = ู…ุฑุฌุน ุงู„ู…ุณุฃู„ุฉ @@ -445,16 +462,17 @@ gpg_desc = ุชุฑุชุจุท ู…ูุงุชูŠุญ GPG ุงู„ุนุงู…ุฉ ู‡ุฐู‡ ุจุญุณุงุจูƒ. ุญุงู manage_ssh_keys = ุฅุฏุงุฑุฉ ู…ูุงุชูŠุญ SSH openid_desc = ูŠุชูŠุญ ู„ูƒ OpenID ุจุชููˆูŠุถ ุงู„ุงุณุชูŠุซุงู‚ ุฅู„ู‰ ู…ุฒูˆู‘ุฏ ุฎุงุฑุฌูŠ. key_content_ssh_placeholder = ูŠุจุฏุฃ ุจู€'ssh-ed25519', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'sk-ecdsa-sha2-nistp256@openssh.com', ุฃูˆ 'sk-ssh-ed25519@openssh.com' +add_new_key = ุฃุถู ู…ูุชุงุญ SSH hidden_comment_types_description = ุฃู†ูˆุงุน ุงู„ุชุนู„ูŠู‚ ุงู„ู…ูุฎุชุงุฑุฉ ู‡ู†ุง ู„ู† ุชุธู‡ุฑ ุฏุงุฎู„ ุตูุญุงุช ุงู„ู…ุณุงุฆู„. ุฃุฎุชูŠุงุฑ "ุชุตู†ูŠู" ู…ุซู„ุงู‹ ูŠู…ุณุญ ูƒู„ ุชุนู„ูŠู‚ุงุช "<ู…ุณุชุฎุฏู…> ุฃุถุงู/ู…ุณุญ <ุชุตู†ูŠู>". key_content_gpg_placeholder = ูŠุจุฏุฃ ุจู€ '-----BEGIN PGP PUBLIC KEY BLOCK-----' add_email_confirmation_sent = ุจุฑูŠุฏ ุชูุนูŠู„ ุฌุฏูŠุฏ ุชู… ุฅุฑุณุงู„ู‡ ุฅู„ู‰ "%s". ูŠูุฑุฌู‰ ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ุจุฑูŠุฏ ุงู„ูˆุงุฑุฏ ุฎู„ุงู„ %s ู„ุชุฃูƒูŠุฏ ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ. ssh_desc = ู…ูุงุชูŠุญ SSH ุงู„ุนู…ูˆู…ูŠุฉ ู‡ุฐู‡ ู…ุฑุชุจุทุฉ ุจุญุณุงุจูƒ. ูˆุชุณู…ุญ ุงู„ู…ูุงุชูŠุญ ุงู„ุฎุตูˆุตูŠุฉ ุงู„ู…ุฑุงูู‚ุฉ ุจุงู„ูˆุตูˆู„ ุงู„ูƒุงู…ู„ ุฅู„ู‰ ู…ุณุชูˆุฏุนุงุชูƒ. ูˆูŠู…ูƒู† ุงุณุชุนู…ุงู„ ู…ูุงุชูŠุญ SSH ุงู„ู…ูˆุซู‘ูŽู‚ุฉ ู„ุชูˆุซูŠู‚ ุฅูŠุฏุงุนุงุช ุฌุช ุงู„ู…ูˆู‚ู‘ูŽุนุฉ ุจู…ูุงุชูŠุญ SSH. ssh_gpg_keys = ู…ูุงุชูŠุญ SSH / GPG -authorized_oauth2_applications_description = ู„ู‚ุฏ ู…ู†ุญุช ุญู‚ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ ุงู„ุดุฎุตูŠ ููŠ Forgejo ู„ู‡ุฐู‡ ุงู„ุชุทุจูŠู‚ุงุช ุงู„ุฎุงุฑุฌูŠุฉ. ูŠุฑุฌู‰ ุฅู„ุบุงุก ุงู„ูˆุตูˆู„ ู„ู„ุชุทุจูŠู‚ุงุช ุงู„ุชูŠ ู„ู… ุชุนุฏ ู‚ูŠุฏ ุงู„ุงุณุชุฎุฏุงู…. +authorized_oauth2_applications_description = ู„ู‚ุฏ ู…ู†ุญุชูŽ ุฅู…ูƒุงู†ูŠุฉ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ ุงู„ุดุฎุตูŠ ุนู„ู‰ ููˆุฑุฌูŠูˆ ู„ู‡ุฐู‡ ุงู„ุชุทุจูŠู‚ุงุช ู…ู† ุชุทุจูŠู‚ุงุช ุฎุงุฑุฌูŠุฉ. ุงู„ุฑุฌุงุก ุฅู„ุบุงุก ูˆุตูˆู„ ุงู„ุชุทุจูŠู‚ุงุช ุงู„ุชูŠ ู„ู… ุชุนุฏ ุจุญุงุฌุฉ ุฅู„ูŠู‡ุง. ssh_key_been_used = ู‡ุฐุง ุงู„ู…ูุชุงุญ ุงู„ู€SSH ุชู… ุฅุถุงูุชู‡ ุจุงู„ูุนู„ ุฅู„ู‰ ู‡ุฐุง ุงู„ุฎุงุฏู…. password_change_disabled = ุงู„ู…ุณุชุฎุฏู…ูŠู† ุบูŠุฑ ุงู„ู…ุญู„ูŠูŠู† ู„ุง ูŠู…ูƒู†ู‡ู… ุชุบูŠูŠุฑ ูƒู„ู…ุฉ ู…ุฑูˆุฑู‡ู… ุนู† ุทุฑูŠู‚ ูˆุงุฌู‡ุฉ ูˆูŠุจ ููˆุฑุฌูŠูˆ. token_state_desc = ู‡ุฐุง ุงู„ุฑู…ุฒ ุงุณุชุฎุฏู… ุฎู„ุงู„ ุขุฎุฑ 7 ุฃูŠุงู… -delete_key = ุฅุฒุงู„ุฉ +delete_key = ุฃุฒู„ู‡ ssh_invalid_token_signature = ู…ูุชุงุญ SSH ุงู„ู…ุฒูˆุฏุŒ ูˆุงู„ุชูˆู‚ูŠุน ูˆุงู„ุฑู…ุฒ ู„ุง ูŠุชุทุงุจู‚ูˆุง ุฃูˆ ุงู„ุฑู…ุฒ ู‚ุฏูŠู…. ssh_token_help = ูŠู…ูƒู†ูƒ ุชูˆู„ูŠุฏ ุชูˆู‚ูŠุน ุจุงุณุชุฎุฏุงู…: gpg_key_verify = ุชุญู‚ู‚ @@ -464,13 +482,14 @@ last_used = ุงุณุชุนู…ู„ ุขุฎุฑ ู…ุฑุฉ ููŠ gpg_token_signature = ุชูˆู‚ูŠุน GPG ู…ุตูุญ add_openid = ุงุถู ุฑุงุจุท OpenID add_gpg_key_success = ุชู… ุฅุถุงูุฉ ู…ูุชุงุญ GPG "%s". +unbind = ุงู„ุบ ุงู„ุฑุจุท verify_ssh_key_success = ุชู… ุงู„ุชุญู‚ู‚ ู…ู† ู…ูุชุงุญ SSH "%s". gpg_token_required = ูŠุฌุจ ุฃู† ุชู‚ุฏู… ุชูˆู‚ูŠุนุงู‹ ู„ู„ุฑู…ุฒ ุงู„ุชุงู„ูŠ ssh_key_verified_long = ุชู… ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ู…ูุชุงุญ ู…ุน ุฑู…ุฒ ูˆูŠู…ูƒู† ุงุณุชุฎุฏุงู…ู‡ ู„ู„ุชุญู‚ู‚ ู…ู† ุงู„ุฅูŠุฏุงุนุงุช ุงู„ู…ุชุทุงุจู‚ุฉ ู…ุน ุฃูŠ ุนู†ุงูˆูŠู† ุงู„ุจุฑูŠุฏ ุงู„ู…ูุนู„ุฉ ู„ู‡ุฐุง ุงู„ู…ุณุชุฎุฏู…. -gpg_key_deletion = ุฅุฒุงู„ุฉ ู…ูุชุงุญ GPG +gpg_key_deletion = ุฃุฒู„ ู…ูุชุงุญ GPG gpg_token_help = ูŠู…ูƒู†ูƒ ุชูˆู„ูŠุฏ ุชูˆู‚ูŠุน ุจุงุณุชุฎุฏุงู…: -ssh_key_deletion = ุฅุฒุงู„ุฉ ู…ูุชุงุญ SSH -ssh_token = ุฑู…ุฒ ูุฑูŠุฏ +ssh_key_deletion = ุฃุฒู„ ู…ูุชุงุญ SSH +ssh_token = ุฑู…ุฒ ssh_disabled = SSH ู…ูุนุทู„ gpg_key_verified_long = ุชู… ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ู…ูุชุงุญ ุจูˆุงุณุทุฉ ุฑู…ุฒ ูˆูŠู…ูƒู† ุงุณุชุฎุฏุงู…ู‡ ู„ู„ุชุญู‚ู‚ ู…ู† ุฅูŠุฏุงุนุงุช ู…ุชุทุงุจู‚ุฉ ู„ุนู†ุงูˆูŠู† ุงู„ุจุฑูŠุฏ ุงู„ู…ูุนู„ุฉ ู„ู‡ุฐุง ุงู„ู…ุณุชุฎุฏู… ุจุงู„ุฅุถุงูุฉ ุฅู„ู‰ ุฃูŠ ู‡ูˆูŠุงุช ู…ุชุทุงุจู‚ุฉ ู„ู‡ุฐุง ุงู„ู…ูุชุงุญ. change_username_redirect_prompt = ุงุณู… ุงู„ู…ุณุชุฎุฏู… ุงู„ู‚ุฏูŠู… ุณูˆู ูŠุนุงุฏ ุชูˆุฌูŠู‡ู‡ ุญุชู‰ ูŠุทุงู„ุจ ุจู‡ ุดุฎุต ุขุฎุฑ. @@ -478,9 +497,10 @@ add_key_success = ุชู… ุฅุถุงูุฉ ู…ูุชุงุญ SSH "%s". key_name = ุงุณู… ุงู„ู…ูุชุงุญ comment_type_group_time_tracking = ุชุชุจุน ุงู„ูˆู‚ุช gpg_invalid_token_signature = ู…ูุชุงุญ GPG ุงู„ู…ุฒูˆุฏุŒ ูˆุงู„ุชูˆู‚ูŠุน ูˆุงู„ุฑู…ุฒ ู„ุง ูŠุชุทุงุจู‚ูˆุง ุฃูˆ ุงู„ุฑู…ุฒ ู‚ุฏูŠู…. -ssh_key_verified = ู…ูุชุงุญ ุชู… ุงู„ุชุญู‚ู‚ ู…ู†ู‡ +ssh_key_verified = ู…ูุชุงุญ ู…ูุชุญู‚ู‚ ู…ู†ู‡ ssh_key_deletion_success = ุชู… ุฅุฒุงู„ุฉ ู…ูุชุงุญ SSH. key_signature_ssh_placeholder = ูŠุจุฏุฃ ุจู€'-----BEGIN SSH SIGNATURE-----' +gpg_token_code = echo "%s" | gpg -a --default-key %s --detach-sig key_id = ู…ุนุฑู ุงู„ู…ูุชุงุญ gpg_key_deletion_success = ุชู… ุฅุฒุงู„ุฉ ู…ูุชุงุญ GPG. verify_gpg_key_success = ุชู… ุงู„ุชุญู‚ู‚ ู…ู† ู…ูุชุงุญ GPG "%s". @@ -491,7 +511,7 @@ gpg_key_deletion_desc = ุฅุฒุงู„ุฉ ู…ูุชุงุญ GPG ูŠูู„ุบูŠ ุชุญู‚ู‚ ุงู„ุฅูŠุฏ permission_read = ุงู„ู‚ุฑุงุกุฉ ssh_token_signature = ุชูˆู‚ูŠุน SSH ู…ุตูุญ ssh_key_deletion_desc = ุฅุฒุงู„ุฉ ู…ูุชุงุญ SSH ูŠู„ุบูŠ ูˆุตูˆู„ู‡ ุฅู„ู‰ ุญุณุงุจูƒ. ุฃูƒู…ู„ุŸ -revoke_key = ุณุญุจ +revoke_key = ุฃุณุญุจ gpg_token = ุฑู…ุฒ gpg_key_matched_identities_long = ุงู„ู‡ูˆูŠุงุช ุงู„ู…ุฏู…ุฌุฉ ููŠ ู‡ุฐุง ุงู„ู…ูุชุงุญ ุชุทุงุจู‚ ุนู†ุงูˆูŠู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ุงู„ู…ูุนู„ุฉ ุงู„ุชุงู„ูŠุฉ ู„ู‡ุฐุง ุงู„ู…ุณุชุฎุฏู…. ูˆูŠู…ูƒู† ุงู„ุชุญู‚ู‚ ู…ู† ุตุญุฉ ุงู„ุฅูŠุฏุงุนุงุช ุงู„ู…ุทุงุจู‚ุฉ ู„ู‡ุฐู‡ ุงู„ุนู†ุงูˆูŠู† ุงู„ุจุฑูŠุฏูŠุฉ ู…ุน ู‡ุฐุง ุงู„ู…ูุชุงุญ. key_content = ุงู„ู…ุญุชูˆู‰ @@ -505,120 +525,9 @@ remove_oauth2_application_success = ุฃูุฒูŠู„ ุงู„ุชุทุจูŠู‚. update_oauth2_application_success = ู„ู‚ุฏ ุญุฏู‘ุซุช ุจู†ุฌุงุญ ุชุทุจูŠู‚ OAuth2. oauth2_redirect_uris = ุฑูˆุงุจุท ุฅุนุงุฏุฉ ุงู„ุชูˆุฌูŠู‡. ู†ุฑุฌูˆ ูˆุถุน ูƒู„ ุฑุงุจุท ููŠ ุณุทุฑ ูˆุญุฏู‡. remove_account_link = ุฃุฒู„ ุงู„ุญุณุงุจ ุงู„ู…ุฑุจูˆุท -remove_account_link_success = ุฃูุฒูŠู„ ุงู„ุญุณุงุจ ุงู„ู…ุฑุชุจุท. +remove_account_link_success = ุฃูุฒูŠู„ ุงู„ุญุณุงุจ ุงู„ู…ุฑุจูˆุท. + quota = ูƒูˆุชุง -update_hints = ุญุฏู‘ูุซ ุงู„ุชู„ู…ูŠุญุงุช -keep_activity_private.description = ุณูŠูƒูˆู† ู†ุดุงุทูƒ ุงู„ุนุงู… ู…ุฑุฆูŠู‹ุง ู„ูƒ ูˆู„ู…ุดุฑููŠ ุงู„ู…ุซูŠู„ ูู‚ุท. -manage_ssh_principals = ุฅุฏุงุฑุฉ ู…ุฏุฑุงุก ุดู‡ุงุฏุงุช SSH ุงู„ุฑุฆูŠุณูŠุฉ -pronouns = ุงู„ุถู…ุงุฆุฑ -pronouns_unspecified = ุบูŠุฑ ู…ุญุฏุฏ -ssh_principal_been_used = ุชู…ุช ุฅุถุงูุฉ ู‡ุฐู‡ ุงู„ู‡ูˆูŠุฉ ุงู„ุฑุฆูŠุณูŠุฉ ุฅู„ู‰ ุงู„ุฎุงุฏู… ู…ุณุจู‚ุงู‹. -principal_desc = ู‡ุฐู‡ ุงู„ู‡ููˆูŠุงุช ุงู„ุฑุฆูŠุณูŠุฉ ู„ุดู‡ุงุฏุงุช SSH ู…ุฑุชุจุทุฉ ุจุญุณุงุจูƒ ูˆุชุชูŠุญ ูˆุตูˆู„ุงู‹ ูƒุงู…ู„ุงู‹ ุฅู„ู‰ ู…ุณุชูˆุฏุนุงุชูƒ. -gpg_helper = ุชุญุชุงุฌ ู„ู…ุณุงุนุฏุฉุŸ ุงุทู‘ู„ุน ุนู„ู‰ ุงู„ุฏู„ูŠู„ ุญูˆู„ GPG. -ssh_helper = ู‡ู„ ุชุญุชุงุฌ ู…ุณุงุนุฏุฉุŸ ุงุทู„ุน ุนู„ู‰ ุงู„ุฏู„ูŠู„ ู„ู€ ุฅู†ุดุงุก ู…ูุงุชูŠุญ SSH ุงู„ุฎุงุตุฉ ุจูƒ ุฃูˆ ู„ุญู„ ุงู„ู…ุดูƒู„ุงุช ุงู„ุดุงุฆุนุฉ ุงู„ุชูŠ ู‚ุฏ ุชูˆุงุฌู‡ู‡ุง ุนู†ุฏ ุงุณุชุฎุฏุงู… SSH. -add_new_principal = ุฅุถุงูุฉ ู‡ูˆูŠุฉ ุฑุฆูŠุณูŠุฉ -keep_pronouns_private.description = ุณูŠุคุฏูŠ ุฐู„ูƒ ุฅู„ู‰ ุฅุฎูุงุก ุถู…ุงุฆุฑูƒ ุนู† ุงู„ุฒูˆุงุฑ ุงู„ุฐูŠู† ู„ู… ูŠู‚ูˆู…ูˆุง ุจุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„. -language.description = ุณูŠุชู… ุญูุธ ู‡ุฐู‡ ุงู„ู„ุบุฉ ููŠ ุญุณุงุจูƒ ูˆุงุณุชุฎุฏุงู…ู‡ุง ูƒู„ุบุฉ ุงูุชุฑุงุถูŠุฉ ุจุนุฏ ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„. -storage_overview = ู†ุธุฑุฉ ุนุงู…ุฉ ุนู„ู‰ ุงู„ุชุฎุฒูŠู† -hints = ุชู„ู…ูŠุญุงุช -language.title = ุงู„ู„ุบุฉ ุงู„ุงูุชุฑุงุถูŠุฉ -update_hints_success = ุชู… ุชุญุฏูŠุซ ุงู„ุชู„ู…ูŠุญุงุช. -language.localization_project = "ุณุงุนุฏู†ุง ููŠ ุชุฑุฌู…ุฉ Forgejo ุฅู„ู‰ ู„ุบุชูƒ! ุงู„ู…ุฒูŠุฏ ู…ู† ุงู„ู…ุนู„ูˆู…ุงุช. -change_username_redirect_prompt.with_cooldown.one = ุณูŠุตุจุญ ุงุณู… ุงู„ู…ุณุชุฎุฏู… ุงู„ู‚ุฏูŠู… ู…ุชุงุญู‹ุง ู„ู„ุฌู…ูŠุน ุจุนุฏ ูุชุฑุฉ ุชุจุงุทุค ุชุจู„ุบ %[1]d ูŠูˆู…ู‹ุง. ู„ุง ูŠุฒุงู„ ุจุฅู…ูƒุงู†ูƒ ุงุณุชุนุงุฏุฉ ุงุณู… ุงู„ู…ุณุชุฎุฏู… ุงู„ู‚ุฏูŠู… ุฎู„ุงู„ ูุชุฑุฉ ุงู„ุชู‡ุฏุฆุฉ. -additional_repo_units_hint = ุงู‚ุชุฑุงุญ ุชูุนูŠู„ ูˆุญุฏุงุช ุงู„ู…ุณุชูˆุฏุนุงุช ุงู„ุฅุถุงููŠุฉ -additional_repo_units_hint_description = ุงุนุฑุถ ุชู„ู…ูŠุญ "ุชูุนูŠู„ ุงู„ู…ุฒูŠุฏ" ู„ู„ู…ุณุชูˆุฏุนุงุช ุงู„ุชูŠ ู„ู… ูŠุชู… ุชูุนูŠู„ ุฌู…ูŠุน ุงู„ูˆุญุฏุงุช ุงู„ู…ุชุงุญุฉ ุจู‡ุง. -change_password = ุบูŠู‘ุฑ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ -keep_pronouns_private = ุฅุธู‡ุงุฑ ุงู„ุถู…ุงุฆุฑ ู„ู„ู…ุณุชุฎุฏู…ูŠู† ุงู„ุฐูŠู† ุชู…ุช ู…ุตุงุฏู‚ุชู‡ู… ูู‚ุท -change_username_redirect_prompt.with_cooldown.few = ุณูŠุตุจุญ ุงุณู… ุงู„ู…ุณุชุฎุฏู… ุงู„ู‚ุฏูŠู… ู…ุชุงุญู‹ุง ู„ู„ุฌู…ูŠุน ุจุนุฏ ูุชุฑุฉ ุชุจุงุทุค ุชุจู„ุบ ูŠูˆู…ู‹ุง. ู„ุง ูŠุฒุงู„ ุจุฅู…ูƒุงู†ูƒ ุงุณุชุนุงุฏุฉ ุงุณู… ุงู„ู…ุณุชุฎุฏู… ุงู„ู‚ุฏูŠู… ุฎู„ุงู„ ูุชุฑุฉ ุงู„ุชู‡ุฏุฆุฉ. -no_activity = ู„ุง ูŠูˆุฌุฏ ู†ุดุงุท ุญุฏูŠุซ -generate_token_success = ุชู… ุฅู†ุดุงุก ุงู„ุฑู…ุฒ ุงู„ูุฑูŠุฏ ุงู„ุฌุฏูŠุฏ ุงู„ุฎุงุต ุจูƒ. ุงู†ุณุฎู‡ ุงู„ุขู† ู„ุฃู†ู‡ ู„ู† ูŠุธู‡ุฑ ู…ุฑุฉ ุฃุฎุฑู‰. -manage_access_token = ุฑู…ูˆุฒ ุงู„ูˆุตูˆู„ ุงู„ูุฑูŠุฏุฉ -token_name = ุงุณู… ุงู„ุฑู…ุฒ ุงู„ูุฑูŠุฏ -generate_token_name_duplicate = ุงุณู… ุงู„ุชุทุจูŠู‚ %s ู…ูุณุชุฎุฏู… ู…ุณุจู‚ู‹ุง. ูŠูุฑุฌู‰ ุงุณุชุฎุฏุงู… ุงุณู… ุฌุฏูŠุฏ. -regenerate_token = ุฅุนุงุฏุฉ ุงู„ุชูˆู„ูŠุฏ -access_token_regeneration = ุฅุนุงุฏุฉ ุชูˆู„ูŠุฏ ุฑู…ุฒ ูˆุตูˆู„ ูุฑูŠุฏ -permission_write = ู‚ุฑุงุกุฉ ูˆูƒุชุงุจุฉ -delete_token_success = ุชู… ุญุฐู ุงู„ุฑู…ุฒ ุงู„ูุฑูŠุฏ. ู„ู… ูŠุนุฏ ุจุฅู…ูƒุงู† ุงู„ุชุทุจูŠู‚ุงุช ุงู„ุชูŠ ุชุณุชุฎุฏู…ู‡ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ. -gpg_key_matched_identities = ุงู„ู‡ูˆูŠุงุช ุงู„ู…ุชุทุงุจู‚ุฉ: -tokens_desc = ุชู…ู†ุญ ู‡ุฐู‡ ุงู„ุฑู…ูˆุฒ ุงู„ูุฑูŠุฏุฉ ุฅู…ูƒุงู†ูŠุฉ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ ุจุงุณุชุฎุฏุงู… ูˆุงุฌู‡ุฉ ุจุฑู…ุฌุฉ ุชุทุจูŠู‚ุงุช Forgejo. -generate_token = ุชูˆู„ูŠุฏ ุฑู…ุฒ ูุฑูŠุฏ -access_token_deletion = ุญุฐู ุฑู…ุฒ ุงู„ูˆุตูˆู„ ุงู„ูุฑูŠุฏ -generate_new_token = ุชูˆู„ูŠุฏ ุฑู…ุฒ ุฌุฏูŠุฏ -access_token_deletion_desc = ุญุฐู ุงู„ุฑู…ุฒ ุงู„ูุฑูŠุฏ ุณูŠุณุญุจ ุตู„ุงุญูŠุฉ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ ู…ู† ุงู„ุชุทุจูŠู‚ุงุช ุงู„ุชูŠ ุชุณุชุฎุฏู…ู‡. ู„ุง ูŠู…ูƒู† ุงู„ุชุฑุงุฌุน ุนู† ู‡ุฐุง ุงู„ุฅุฌุฑุงุก. ุชุฑูŠุฏ ุงู„ู…ุชุงุจุนุฉุŸ -access_token_desc = ุชู‚ุชุตุฑ ุตู„ุงุญูŠุงุช ุงู„ุฑู…ุฒ ุงู„ู…ุญุฏุฏุฉ ุนู„ู‰ ู…ุณุงุฑุงุช ูˆุงุฌู‡ุฉ ุงู„ุจุฑู…ุฌุฉ (API) ุงู„ู…ู‚ุงุจู„ุฉ ูู‚ุท. ุงุทู„ุน ุนู„ู‰ ุงู„ูˆุซุงุฆู‚ ู„ู…ุฒูŠุฏ ู…ู† ุงู„ู…ุนู„ูˆู…ุงุช. -oauth2_application_remove_description = ุณุชุคุฏูŠ ุฅุฒุงู„ุฉ ุชุทุจูŠู‚ OAuth2 ุฅู„ู‰ ู…ู†ุนู‡ ู…ู† ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจุงุช ุงู„ู…ุณุชุฎุฏู…ูŠู† ุงู„ู…ุตุฑุญ ู„ู‡ู… ุนู„ู‰ ู‡ุฐุง ุงู„ู…ุซูŠู„. ุงู„ู…ุชุงุจุนุฉุŸ -ssh_principal_deletion = ุฅุฒุงู„ุฉ ุงู„ู‡ูˆูŠุฉ ุงู„ุฑุฆูŠุณูŠุฉ ู„ุดู‡ุงุฏุฉ SSH -at_least_one_permission = ูŠุฌุจ ุนู„ูŠูƒ ุชุญุฏูŠุฏ ุตู„ุงุญูŠุฉ ูˆุงุญุฏุฉ ุนู„ู‰ ุงู„ุฃู‚ู„ ู„ุฅู†ุดุงุก ุฑู…ุฒ ูุฑูŠุฏ -subkeys = ุงู„ู…ูุงุชูŠุญ ุงู„ูุฑุนูŠุฉ -ssh_principal_deletion_desc = ุฅุฒุงู„ุฉ ู‡ูˆูŠุฉ ุฑุฆูŠุณูŠุฉ ู„ุดู‡ุงุฏุฉ SSH ุณุชุณุญุจ ุตู„ุงุญูŠุฉ ูˆุตูˆู„ู‡ุง ุฅู„ู‰ ุญุณุงุจูƒ. ุชุฑูŠุฏ ุงู„ู…ุชุงุจุนุฉุŸ -principal_state_desc = ุงุณุชุฎุฏู…ุช ู‡ุฐู‡ ุงู„ู‡ูˆูŠุฉ ููŠ ุขุฎุฑ 7 ุฃูŠุงู… -ssh_signonly = SSH ู…ุนุทู‘ู„ ุญุงู„ูŠู‹ุงุŒ ู„ุฐุง ุชูุณุชุฎุฏู… ู‡ุฐู‡ ุงู„ู…ูุงุชูŠุญ ูู‚ุท ู„ู„ุชุญู‚ู‚ ู…ู† ุชูˆู‚ูŠุน ุงู„ุฅูŠุฏุงุน. -ssh_externally_managed = ูŠุชู… ุฅุฏุงุฑุฉ ู…ูุชุงุญ SSH ู‡ุฐุง ุฎุงุฑุฌูŠู‹ุง ู„ู‡ุฐุง ุงู„ู…ุณุชุฎุฏู… -access_token_regeneration_desc = ุณูŠุคุฏูŠ ุฅุนุงุฏุฉ ุฅู†ุดุงุก ุฑู…ุฒ ูุฑูŠุฏ ุฅู„ู‰ ุฅุจุทุงู„ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ ู„ู„ุชุทุจูŠู‚ุงุช ุงู„ุชูŠ ุชุณุชุฎุฏู…ู‡. ู„ุง ูŠู…ูƒู† ุงู„ุชุฑุงุฌุน ุนู† ุฐู„ูƒ. ุงู„ู…ุชุงุจุนุฉุŸ -regenerate_token_success = ุชู… ุฅุนุงุฏุฉ ุฅู†ุดุงุก ุงู„ุฑู…ุฒ ุงู„ุบุฑูŠุฏ. ู„ู… ูŠุนุฏ ุจุฅู…ูƒุงู† ุงู„ุชุทุจูŠู‚ุงุช ุงู„ุชูŠ ุชุณุชุฎุฏู…ู‡ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ ูˆูŠุฌุจ ุชุญุฏูŠุซู‡ุง ุจุงู„ุฑู…ุฒ ุงู„ุฌุฏูŠุฏ. -repo_and_org_access = ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุงู„ู…ุณุชูˆุฏุน ูˆุงู„ู…ู†ุธู…ุฉ -add_principal_success = ุชู…ุช ุฅุถุงูุฉ ุงู„ู‡ูˆูŠุฉ ุงู„ุฑุฆูŠุณูŠุฉ ู„ุดู‡ุงุฏุฉ "SSH "%s. -ssh_principal_deletion_success = ุชู… ุฅุฒุงู„ุฉ ุงู„ู‡ูˆูŠุฉ. -oauth2_applications_desc = ุชู…ูƒู‘ู† ุชุทุจูŠู‚ุงุช OAuth2 ุชุทุจูŠู‚ุงุช ุงู„ุทุฑู ุงู„ุซุงู„ุซ ู…ู† ู…ุตุงุฏู‚ุฉ ุงู„ู…ุณุชุฎุฏู…ูŠู† ุจุฃู…ุงู† ููŠ ู…ุซูŠู„ Forgejo ู‡ุฐุง. -oauth2_client_secret = ุณุฑ ุงู„ุนู…ูŠู„ -oauth2_regenerate_secret = ุชุฌุฏูŠุฏ ุงู„ุณุฑ -oauth2_regenerate_secret_hint = ูู‚ุฏุช ุณุฑูƒุŸ -oauth2_client_id = ู…ุนุฑู ุงู„ุนู…ูŠู„ -permission_no_access = ู„ุง ูˆุตูˆู„ -remove_oauth2_application_desc = ุณุชุคุฏูŠ ุฅุฒุงู„ุฉ ุชุทุจูŠู‚ OAuth2 ุฅู„ู‰ ุฅุจุทุงู„ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุฌู…ูŠุน ุฑู…ูˆุฒ ุงู„ูˆุตูˆู„ ุงู„ูุฑูŠุฏุฉ ุงู„ู…ูˆู‚ุนุฉ. ุงู„ู…ุชุงุจุนุฉุŸ -oauth2_confidential_client = ุงู„ุนู…ูŠู„ ุงู„ุณุฑูŠ. ุญุฏุฏ ู„ู„ุชุทุจูŠู‚ุงุช ุงู„ุชูŠ ุชุญุงูุธ ุนู„ู‰ ุงู„ุณุฑูŠุฉุŒ ู…ุซู„ ุชุทุจูŠู‚ุงุช ุงู„ูˆูŠุจ. ู„ุง ุชุญุฏุฏ ู„ู„ุชุทุจูŠู‚ุงุช ุงู„ุฃุตู„ูŠุฉ ุจู…ุง ููŠ ุฐู„ูƒ ุชุทุจูŠู‚ุงุช ุณุทุญ ุงู„ู…ูƒุชุจ ูˆุชุทุจูŠู‚ุงุช ุงู„ุฃุฌู‡ุฒุฉ ุงู„ู…ุญู…ูˆู„ุฉ. -oauth2_client_secret_hint = ู„ู† ูŠุธู‡ุฑ ุงู„ุณุฑ ู…ุฑุฉ ุฃุฎุฑู‰ ุจุนุฏ ู…ุบุงุฏุฑุฉ ู‡ุฐู‡ ุงู„ุตูุญุฉ ุฃูˆ ุชุญุฏูŠุซู‡ุง. ูŠุฑุฌู‰ ุงู„ุชุฃูƒุฏ ู…ู† ุฃู†ูƒ ู‚ู…ุช ุจุญูุธู‡. -oauth2_application_create_description = โ€ชุชู…ู†ุญ ุชุทุจูŠู‚ุงุช OAuth2 ุชุทุจูŠู‚ุงุช ุงู„ุทุฑู ุงู„ุซุงู„ุซ ุญู‚ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจุงุช ุงู„ู…ุณุชุฎุฏู…ูŠู† ุนู„ู‰ ู‡ุฐุง ุงู„ู…ุซูŠู„. -oauth2_application_locked = ูŠู‚ูˆู… Forgejo ุจุงู„ุชุณุฌูŠู„ ุงู„ู…ุณุจู‚ ู„ุจุนุถ ุชุทุจูŠู‚ุงุช OAuth2 ุนู†ุฏ ุจุฏุก ุงู„ุชุดุบูŠู„ ุฅุฐุง ุชู… ุชู…ูƒูŠู†ู‡ุง ููŠ ุงู„ุชูƒูˆูŠู†. ู„ู…ู†ุน ุงู„ุณู„ูˆูƒ ุบูŠุฑ ุงู„ู…ุชูˆู‚ุนุŒ ู„ุง ูŠู…ูƒู† ุชุญุฑูŠุฑู‡ุง ุฃูˆ ุฅุฒุงู„ุชู‡ุง. ูŠุฑุฌู‰ ุงู„ุฑุฌูˆุน ุฅู„ู‰ ูˆุซุงุฆู‚ OAuth2 ู„ู…ุฒูŠุฏ ู…ู† ุงู„ู…ุนู„ูˆู…ุงุช. -twofa_recovery_tip = ุฅุฐุง ูู‚ุฏุช ุฌู‡ุงุฒูƒุŒ ุณุชุชู…ูƒู† ู…ู† ุงุณุชุฎุฏุงู… ู…ูุชุงุญ ุงู„ุงุณุชุฑุฏุงุฏ ู„ู„ุงุณุชุฎุฏุงู… ู…ุฑุฉ ูˆุงุญุฏุฉ ู„ุงุณุชุนุงุฏุฉ ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ. -twofa_not_enrolled = ุญุณุงุจูƒ ุบูŠุฑ ู…ุณุฌู‘ู„ ุญุงู„ูŠุงู‹ ููŠ ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ. -twofa_scratch_token_regenerate = ุฅุนุงุฏุฉ ุฅู†ุดุงุก ู…ูุชุงุญ ุงู„ุงุณุชุฑุฏุงุฏ ู„ู„ุงุณุชุฎุฏุงู… ู…ุฑุฉ ูˆุงุญุฏุฉ -regenerate_scratch_token_desc = ุฅุฐุง ูู‚ุฏุช ู…ูุชุงุญ ุงู„ุงุณุชุฑุฏุงุฏ ุงู„ุฎุงุต ุจูƒ ููŠ ุบูŠุฑ ู…ุญู„ู‡ ุฃูˆ ุงุณุชุฎุฏู…ุชู‡ ุจุงู„ูุนู„ ู„ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ุŒ ูŠู…ูƒู†ูƒ ุฅุนุงุฏุฉ ุชุนูŠูŠู†ู‡ ู‡ู†ุง. -twofa_failed_get_secret = ุฅุฎูุงู‚ ููŠ ุงู„ุญุตูˆู„ ุนู„ู‰ ุณุฑ. -manage_account_links_desc = ู‡ุฐู‡ ุงู„ุญุณุงุจุงุช ุงู„ุฎุงุฑุฌูŠุฉ ู…ุฑุชุจุทุฉ ุจุญุณุงุจูƒ ููŠ Forgejo. -revoke_oauth2_grant_description = ุณูŠุคุฏูŠ ุฅุจุทุงู„ ุงู„ูˆุตูˆู„ ู„ู‡ุฐุง ุงู„ุชุทุจูŠู‚ ุงู„ุชุงุจุน ู„ุฌู‡ุฉ ุฎุงุฑุฌูŠุฉ ุฅู„ู‰ ู…ู†ุน ู‡ุฐุง ุงู„ุชุทุจูŠู‚ ู…ู† ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุจูŠุงู†ุงุชูƒ. ุฃู†ุช ู…ุชุฃูƒุฏุŸ -revoke_oauth2_grant_success = ุชู… ุณุญุจ ุตู„ุงุญูŠุฉ ุงู„ูˆุตูˆู„ ุจู†ุฌุงุญ. -webauthn_alternative_tip = ู‚ุฏ ุชุฑุบุจ ููŠ ุชูƒูˆูŠู† ุฃุณู„ูˆุจ ู…ุตุงุฏู‚ุฉ ุฅุถุงููŠ. -webauthn_register_key = ุฅุถุงูุฉ ู…ูุชุงุญ ุชุดููŠุฑ -webauthn_nickname = ุงู„ุงุณู… ุงู„ู…ุณุชุนุงุฑ -manage_account_links = ุงู„ุญุณุงุจุงุช ุงู„ู…ุฑุชุจุทุฉ -revoke_oauth2_grant = ุณุญุจ ุตู„ุงุญูŠุฉ ุงู„ูˆุตูˆู„ -twofa_enroll = ุงู„ุชุณุฌูŠู„ ููŠ ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ -twofa_is_enrolled = ุญุณุงุจูƒ ู…ุณุฌู‘ู„ ุญุงู„ูŠู‹ุง ููŠ ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ. -twofa_scratch_token_regenerated = ู…ูุชุงุญ ุงู„ุงุณุชุฑุฏุงุฏ ู„ู„ุงุณุชุฎุฏุงู… ู…ุฑุฉ ูˆุงุญุฏุฉ ู‡ูˆ %s ุงู„ุขู†. ู‚ู… ุจุชุฎุฒูŠู†ู‡ ููŠ ู…ูƒุงู† ุขู…ู†ุŒ ูู„ู† ูŠุชู… ุนุฑุถู‡ ู…ุฌุฏุฏุงู‹. -twofa_enrolled = ุชู… ุชุณุฌูŠู„ ุญุณุงุจูƒ ุจู†ุฌุงุญ. ู‚ู… ุจุชุฎุฒูŠู† ู…ูุชุงุญ ุงู„ุงุณุชุฑุฏุงุฏ ู„ู„ุงุณุชุฎุฏุงู… ู„ู…ุฑุฉ ูˆุงุญุฏุฉ (%s) ููŠ ู…ูƒุงู† ุขู…ู†ุŒ ูู„ู† ูŠุชู… ุนุฑุถู‡ ู…ุฌุฏุฏุงู‹. -webauthn_desc = ู…ูุงุชูŠุญ ุงู„ุฃู…ุงู† ู‡ูŠ ุฃุฌู‡ุฒุฉ ูุนู„ูŠุฉ ุชุญูˆูŠ ุนู„ู‰ ู…ูุงุชูŠุญ ุชุดููŠุฑ. ูŠู…ูƒู† ุงุณุชุฎุฏุงู…ู‡ุง ู„ู„ุชุญู‚ู‚ ุจุฎุทูˆุชูŠู†. ูŠุฌุจ ุฃู† ุชุฏุนู… ู…ูุงุชูŠุญ ุงู„ุฃู…ุงู† ู…ุนูŠุงุฑ WebAuthn Authenticator. -remove_account_link_desc = ุณุชุคุฏูŠ ุฅุฒุงู„ุฉ ุญุณุงุจ ู…ุฑุชุจุท ุฅู„ู‰ ุฅู„ุบุงุก ูˆุตูˆู„ู‡ ุฅู„ู‰ ุญุณุงุจ Forgejo ุงู„ุฎุงุต ุจูƒ. ุงู„ู…ุชุงุจุนุฉุŸ -email_notifications.onmention = ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ูู‚ุท ุนู†ุฏ ุงู„ุฅุดุงุฑุฉ -email_notifications.andyourown = ูˆุงู„ุฅุดุนุงุฑุงุช ุงู„ุฎุงุตุฉ ุจูƒ -visibility = ุฑุคูŠุฉ ุงู„ู…ุณุชุฎุฏู… -visibility.public_tooltip = ู…ุฑุฆูŠ ู„ู„ุฌู…ูŠุน -visibility.private_tooltip = ู…ุฑุฆูŠ ูู‚ุท ู„ุฃุนุถุงุก ุงู„ู…ุคุณุณุงุช ุงู„ุชูŠ ุงู†ุถู…ู…ุช ุฅู„ูŠู‡ุง -visibility.public = ุนุงู… -delete_account_desc = ู‡ู„ ุฃู†ุช ู…ุชุฃูƒุฏ ู…ู† ุฑุบุจุชูƒ ููŠ ุญุฐู ุญุณุงุจ ุงู„ู…ุณุชุฎุฏู… ู‡ุฐุง ู†ู‡ุงุฆูŠู‹ุงุŸ -user_block_yourself = ู„ุง ูŠู…ูƒู†ูƒ ุญุธุฑ ู†ูุณูƒ. -delete_with_all_comments = ุญุณุงุจูƒ ุฃุตุบุฑ ู…ู† %s. ู„ุชุฌู†ุจ ุงู„ุชุนู„ูŠู‚ุงุช ุงู„ูˆู‡ู…ูŠุฉุŒ ุณูŠุชู… ุญุฐู ุฌู…ูŠุน ุชุนู„ูŠู‚ุงุช ุงู„ู…ุดูƒู„ุฉ/ุงู„ู…ุณุคูˆู„ูŠุฉ ุงู„ุดุฎุตูŠุฉ ู…ุนู‡ุง. -visibility.limited_tooltip = ู…ุฑุฆูŠุฉ ูู‚ุท ู„ู„ู…ุณุชุฎุฏู…ูŠู† ุงู„ุฐูŠู† ู‚ุงู…ูˆุง ุจุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ -visibility.limited = ู…ุญุฏูˆุฏ -visibility.private = ุฎุงุต -quota.applies_to_org = ุชู†ุทุจู‚ ู‚ูˆุงุนุฏ ุงู„ุญุตุต ุงู„ุชุงู„ูŠุฉ ุนู„ู‰ ู‡ุฐู‡ ุงู„ู…ู†ุธู…ุฉ -quota.rule.no_limit = ุบูŠุฑ ู…ุญุฏูˆุฏ -quota.sizes.all = ุงู„ูƒู„ -quota.sizes.repos.all = ุงู„ู…ุณุชูˆุฏุนุงุช -quota.sizes.repos.public = ู…ุณุชูˆุฏุนุงุช ุนุงู…ุฉ -quota.sizes.repos.private = ู…ุณุชูˆุฏุนุงุช ุฎุงุตุฉ -quota.sizes.git.all = ู…ุญุชูˆู‰ Git -quota.sizes.git.lfs = Git LFS -quota.sizes.assets.all = ุงู„ุฃุตูˆู„ -quota.sizes.assets.attachments.all = ุงู„ู…ุฑูู‚ุงุช -quota.sizes.assets.attachments.issues = ุฅุตุฏุงุฑ ุงู„ู…ุฑูู‚ุงุช -quota.sizes.assets.attachments.releases = ุชุญุฑูŠุฑ ุงู„ู…ุฑูู‚ุงุช -quota.sizes.assets.artifacts = ุงู„ุชุญู ุงู„ูู†ูŠุฉ -quota.sizes.assets.packages.all = ุงู„ุญุฒู… -quota.rule.exceeded.helper = ู„ู‚ุฏ ุชุฌุงูˆุฒ ุงู„ุญุฌู… ุงู„ุฅุฌู…ุงู„ูŠ ู„ู„ูƒุงุฆู†ุงุช ู„ู‡ุฐู‡ ุงู„ู‚ุงุนุฏุฉ ุงู„ุญุตุฉ ุงู„ู†ุณุจูŠุฉ. -quota.rule.exceeded = ุชู… ุชุฌุงูˆุฒู‡ -quota.applies_to_user = ุชู†ุทุจู‚ ู‚ูˆุงุนุฏ ุงู„ุญุตุต ุงู„ุชุงู„ูŠุฉ ุนู„ู‰ ุญุณุงุจูƒ -quota.sizes.wiki = ุงู„ู…ูˆุณูˆุนุฉ [org] follow_blocked_user = ู„ุง ูŠู…ูƒู†ูƒ ุฅุชุจุงุน ู‡ุฐู‡ ุงู„ู…ู†ุธู…ุฉ ู„ุฃู† ู‡ุฐู‡ ุงู„ู…ู†ุธู…ุฉ ุญุธุฑุชูƒ. @@ -709,8 +618,10 @@ settings.add_collaborator_blocked_our = ู„ุง ูŠู…ูƒู† ุฅุถุงูุฉ ุงู„ู…ุดุชุฑูƒ commits.browse_further = ุชุตูุญ ุฃูƒุซุฑ settings.ignore_stale_approvals = ุชุฌุงู‡ู„ ุงู„ุทู„ุจุงุช ุงู„ุฑุงูƒุฏุฉ rss.must_be_on_branch = ูŠุฌุจ ุฃู† ุชูƒูˆู† ุนู„ู‰ ูุฑุน ู„ุชุญุตู„ ุนู„ู‰ ู…ูˆุฌุฒ RSS. +clone_in_vscodium = ุฅุณุชู†ุณุฎ ููŠ VSCodium admin.enabled_flags = ุงู„ุนู„ุงู…ุงุช ุงู„ู…ูุนู„ุฉ ู„ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน: settings.new_owner_blocked_doer = ุงู„ู…ุงู„ูƒ ุงู„ุฌุฏูŠุฏ ุญุธุฑูƒ. +issues.comment.blocked_by_user = ู„ุง ูŠู…ูƒู†ูƒ ุฃู† ุชุฑุณู„ ุชุนู„ูŠู‚ุงู‹ ุนู„ู‰ ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ ู„ุฃู†ูƒ ู…ุญุธูˆุฑ ู…ู† ู‚ุจู„ ู…ุงู„ูƒ ุงู„ู…ุณุชูˆุฏุน ุฃูˆ ู…ุฑุณู„ ุงู„ู…ุณุฃู„ุฉ. pulls.nothing_to_compare_have_tag = ุงู„ูุฑุน/ุงู„ูˆุณู… ุงู„ู…ุฎุชุงุฑูŠู† ู…ุชุณุงูˆูŠูŠู†. admin.update_flags = ุชุญุฏูŠุซ ุงู„ุนู„ุงู…ุงุช editor.invalid_commit_mail = ุงู„ุจุฑูŠุฏ ุบูŠุฑ ุตุงู„ุญ ู„ุตู†ุน ุฅูŠุฏุงุน. @@ -720,23 +631,24 @@ settings.add_collaborator_blocked_them = ู„ุง ูŠู…ูƒู† ุฃู† ุฅุถุงูุฉ ุงู„ู…ุด issues.blocked_by_user = ู„ุง ูŠู…ูƒู†ูƒ ุฃู† ุชุฑุณู„ ู…ุณุฃู„ุฉ ููŠ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน ู„ุฃู†ูƒ ู…ุญุธูˆุฑ ู…ู† ู‚ุจู„ ู…ุงู„ูƒ ุงู„ู…ุณุชูˆุฏุน. mirror_sync = ู…ุชุฒุงู…ู† settings.archive.mirrors_unavailable = ุงู„ู…ุฑุงูŠุง ู„ูŠุณุช ู…ุชุงุญุฉ ุฅุฐุง ุชู… ุฃุฑุดูุฉ ุงู„ู…ุณุชูˆุฏุน. +migrate.forgejo.description = ุชุฑุญูŠู„ ุงู„ู…ุนู„ูˆู…ุงุช ู…ู† ูƒูˆุฏุจูŠุฑุฌ ุฃูˆ ุฎูˆุงุฏู… ููˆุฑุฌูŠูˆ ุงู„ุฃุฎุฑู‰. pulls.blocked_by_user = ู„ุง ูŠู…ูƒู†ูƒ ุฃู† ุชุฑุณู„ ุทู„ุจ ุณุญุจ ููŠ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน ู„ุฃู†ูƒ ู…ุญุธูˆุฑ ู…ู† ู‚ุจู„ ู…ุงู„ูƒ ุงู„ู…ุณุชูˆุฏุน. migrate.migrating_milestones = ุชุฑุญูŠู„ ุงู„ุฃู‡ุฏุงู migrate_items_milestones = ุฃู‡ุฏุงู repo_size = ุญุฌู… ุงู„ู…ุณุชูˆุฏุน -object_format = ุชู†ุณูŠู‚ ุงู„ูƒุงุฆู†ุงุช +object_format = ุตูŠุบุฉ ุงู„ูƒุงุฆู†ุงุช use_template = ุงุณุชุฎุฏู… ู‡ุฐุง ุงู„ู‚ุงู„ุจ migrate_items_merge_requests = ุทู„ุจุงุช ุงู„ุฏู…ุฌ repo_name = ุงุณู… ุงู„ู…ุณุชูˆุฏุน template = ุงู„ู‚ุงู„ุจ projects.modify = ุนุฏู‘ู„ ุงู„ู…ุดุฑูˆุน -tree_path_not_found.commit = ุงู„ู…ุณุงุฑ %[1]s ุบูŠุฑ ู…ูˆุฌูˆุฏ ููŠ ุงู„ุฅูŠุฏุงุน %[2]s +tree_path_not_found_commit = ุงู„ู…ุณุงุฑ %[1]s ุบูŠุฑ ู…ูˆุฌูˆุฏ ููŠ ุงู„ุฅูŠุฏุงุน %[2]s repo_lang = ุงู„ู„ุบุฉ -fork_repo = ุงุดุชู‚ุงู‚ ุงู„ู…ุณุชูˆุฏุน +fork_repo = ุงุดุชู‚ ุงู„ู…ุณุชูˆุฏุน fork_no_valid_owners = ู„ุง ูŠู…ูƒู† ุงุดุชู‚ุงู‚ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน ู„ุนุฏู… ูˆุฌูˆุฏ ู…ุงู„ูƒ ุตุงู„ุญ. license = ุงู„ุชุฑุฎูŠุต fork_branch = ุงู„ูุฑุน ุงู„ุฐูŠ ุณูŠูุณุชู†ุณุฎ ุฅู„ู‰ ุงู„ุงุดุชู‚ุงู‚ -template_helper = ุงุฌุนู„ ุงู„ู…ุณุชูˆุฏุน ู‚ุงู„ุจุงู‹ +template_helper = ุงุฌุนู„ ุงู„ู…ุณุชูˆุฏุน ู‚ุงู„ุจุง owner = ุงู„ู…ุงู„ูƒ projects.deletion_success = ุชู… ุญุฐู ุงู„ู…ุดุฑูˆุน. projects.deletion = ุงุญุฐู ุงู„ู…ุดุฑูˆุน @@ -746,23 +658,23 @@ projects.edit = ุนุฏู‘ู„ ุงู„ู…ุดุฑูˆุน template.avatar = ุงู„ุตูˆุฑุฉ ุงู„ุฑู…ุฒูŠุฉ migrate_items_wiki = ุงู„ู…ูˆุณูˆุนุฉ repo_desc = ุงู„ูˆุตู -template_select = ุงุฎุชุฑ ู‚ุงู„ุจุง +template_select = ุงุฎุชุฑ ู‚ุงู„ุจุง. repo_name_helper = ุงู„ุฃุณู…ุงุก ุงู„ุญุณู†ุฉ ู„ู„ู…ุณุชูˆุฏุนุงุช ุชุณุชุฎุฏู… ูƒู„ู…ุงุช ู…ูุชุงุญูŠุฉ ู‚ุตูŠุฑุฉ ูˆุณู‡ู„ุฉ ุงู„ุชุฐูƒุฑ ูˆูุฑูŠุฏุฉ. -default_branch = ุงู„ูุฑุน ุงู„ุงูุชุฑุงุถูŠ +default_branch = ุงู„ูุฑุน ุงู„ู…ุจุฏุฆูŠ all_branches = ูƒู„ ุงู„ูุฑูˆุน -migrate_items_issues = ุงู„ุจู„ุงุบุงุช +migrate_items_issues = ุงู„ู…ุณุงุฆู„ projects.deletion_desc = ุญุฐู ู…ุดุฑูˆุน ูŠุญุฐู ูƒู„ ุงู„ู…ุณุงุฆู„ ุงู„ู…ุฑุชุจุทุฉ ุจู‡. ุฃุชุฑูŠุฏ ุงู„ุงุณุชู…ุฑุงุฑุŸ -repo_desc_helper = ุฃุฏุฎู„ ูˆุตูุงู‹ ู‚ุตูŠุฑุงู‹ (ุงุฎุชูŠุงุฑูŠ) -create_repo = ุฅู†ุดุงุก ู…ุณุชูˆุฏุน +repo_desc_helper = ุฃุฏุฎู„ ูˆุตูุง ู‚ุตูŠุฑุง (ุงุฎุชูŠุงุฑูŠุง) +create_repo = ุฃู†ุดุฆ ู…ุณุชูˆุฏุนุง migrate_items_releases = ุงู„ุฅุตุฏุงุฑุงุช already_forked = ู„ู‚ุฏ ุงุดุชู‚ู‚ุช %s ุจุงู„ูุนู„ license_helper = ุงุฎุชุฑ ู…ู„ู ุชุฑุฎูŠุต. -tree_path_not_found.tag = ุงู„ู…ุณุงุฑ %[1]s ุบูŠุฑ ู…ูˆุฌูˆุฏ ููŠ ุงู„ูˆุณู… %[2]s +tree_path_not_found_tag = ุงู„ู…ุณุงุฑ %[1]s ุบูŠุฑ ู…ูˆุฌูˆุฏ ููŠ ุงู„ูˆุณู… %[2]s object_format_helper = ุตูŠุบุฉ ูƒุงุฆู†ุงุช ุงู„ู…ุณุชูˆุฏุน. ู„ุง ูŠู…ูƒู† ุชุบูŠูŠุฑู‡ุง ุจุนุฏ ุฐู„ูƒ. SHA1 ู‡ูŠ ุงู„ุฃูƒุซุฑ ุชูˆุงูู‚ูŠุฉ. forks = ุงู„ุงุดุชู‚ุงู‚ุงุช migrate_items_pullrequests = ุทู„ุจุงุช ุงู„ุณุญุจ fork_to_different_account = ุงุดุชู‚ ุฅู„ู‰ ุญุณุงุจ ู…ุฎุชู„ู -tree_path_not_found.branch = ุงู„ู…ุณุงุฑ %[1]s ุบูŠุฑ ู…ูˆุฌูˆุฏ ููŠ ุงู„ูุฑุน %[2]s +tree_path_not_found_branch = ุงู„ู…ุณุงุฑ %[1]s ุบูŠุฑ ู…ูˆุฌูˆุฏ ููŠ ุงู„ูุฑุน %[2]s projects.edit_success = ุญุฏู‘ูุซ ุงู„ู…ุดุฑูˆุน "%s". projects.create_success = ุชู… ุฅู†ุดุงุก ุงู„ู…ุดุฑูˆุน "%s". find_file.no_matching = ู„ุง ูŠูˆุฌุฏ ู…ู„ู ู…ุทุงุจู‚ @@ -774,7 +686,7 @@ issues.remove_milestone_at = `ุฃุฒุงู„ ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ ู…ู† ุงู„ู‡ุฏู issues.filter_assginee_no_assignee = ุจู„ุง ู…ูƒู„ู issues.new.no_milestone = ุจู„ุง ู‡ุฏู issues.new.projects = ุงู„ู…ุดุฑูˆุนุงุช -delete_preexisting_label = ุญุฐู +delete_preexisting_label = ุงุญุฐู issues.context.edit = ุนุฏู‘ู„ branch.rename = ุบูŠู‘ุฑ ุงุณู… ุงู„ูุฑุน "%s" issue_labels = ุชุตู†ูŠูุงุช ุงู„ู…ุณุงุฆู„ @@ -783,6 +695,7 @@ issues.remove_project_at = `ุฃุฒุงู„ ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ ู…ู† ุงู„ู…ุดุฑูˆุน < issues.unlock.notice_1 = - ูŠุณุชุทูŠุน ุฃูŠ ู…ุณุชุฎุฏู… ุนู†ุฏุฆุฐู ุฃู† ูŠุนู„ู‘ู‚ ุนู„ู‰ ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ ู…ู† ุฌุฏูŠุฏ. issues.remove_assignee_at = `ุฃู„ุบู‰ ุชูƒู„ูŠูู‡ %s %s` branch.warning_rename_default_branch = ุฅู†ูƒ ุชุบูŠู‘ุฑ ุงุณู… ุงู„ูุฑุน ุงู„ู…ุจุฏุฆูŠ. +trust_model_helper_default = ุงู„ู…ุจุฏุฆูŠ: ุงุฎุชุฑ ู†ู…ูˆุฐุฌ ุงู„ุซู‚ุฉ ุงู„ู…ุจุฏุฆูŠ ู„ู‡ุฐุง ุงู„ู…ูˆู‚ุน tag.create_tag = ุฃู†ุดุฆ ุงู„ูˆุณู… %s release.title_empty = ู„ุง ูŠู…ูƒู† ุชุฑูƒ ุงู„ุนู†ูˆุงู† ูุงุฑุบุง. tag.create_tag_operation = ุฃู†ุดุฆ ูˆุณู…ู‹ุง @@ -869,8 +782,9 @@ milestones.deletion_desc = ุญุฐู ู‡ุฏู ูŠุญุฐูู‡ ู…ู† ูƒู„ ุงู„ู…ุณุงุฆู„ ุง issues.desc = ู†ุธู‘ู… ุฅุจู„ุงุบุงุช ุงู„ุนู„ู„ุŒ ูˆุงู„ู…ู‡ุงู…ุŒ ูˆุงู„ุฃู‡ุฏุงู. issues.choose.ignore_invalid_templates = ุฃูู‡ู…ูู„ุช ุงู„ู‚ูˆุงู„ุจ ุงู„ุชุงู„ูุฉ branch.renamed = ุบููŠู‘ุฑ ุงุณู… ุงู„ูุฑุน %s ุฅู„ู‰ %s. -delete_preexisting = ุญุฐู ุงู„ู…ู„ูุงุช ุงู„ู…ูˆุฌูˆุฏุฉ ู…ุณุจู‚ุงู‹ +delete_preexisting = ุงุญุฐู ุงู„ู…ู„ูุงุช ุงู„ู…ูˆุฌูˆุฏุฉ ุณุงุจู‚ุง branch.included_desc = ู‡ุฐุง ุงู„ูุฑุน ุฌุฒุก ู…ู† ุงู„ูุฑุน ุงู„ู…ุจุฏุฆูŠ +trust_model_helper_collaborator_committer = ู…ุดุชุฑูƒ+ู…ูˆุฏุน: ุซู‚ ุจุชูˆู‚ูŠุนุงุช ุงู„ู…ุดุชุฑูƒูŠู† ุงู„ุชูŠ ุชุทุงุจู‚ ุงู„ู…ูˆุฏุน issues.reopened_at = `ุฃุนุงุฏ ูุชุญ ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ %s` issues.action_milestone = ู‡ุฏู issues.new.assignees = ุงู„ู…ูƒู„ู‘ูŽููˆู† @@ -879,6 +793,7 @@ milestones.filter_sort.most_complete = ุงู„ุฃูƒุซุฑ ุงูƒุชู…ุงู„ุง issues.filter_labels = ุชุตููŠุฉ ุงู„ุชุตู†ูŠูุงุช issues.label.filter_sort.alphabetically = ุฃุจุฌุฏูŠุง settings.confirm_wiki_delete = ุงุญุฐู ุจูŠุงู†ุงุช ุงู„ู…ูˆุณูˆุนุฉ +branch.confirm_rename_branch = ุบูŠู‘ุฑ ุงุณู… ุงู„ูุฑุน issues.action_assignee_no_select = ุจู„ุง ู…ูƒู„ู release.publish = ุงู†ุดุฑ ุงู„ุฅุตุฏุงุฑ issues.lock_duplicate = ู„ุง ูŠู…ูƒู† ุฅู‚ูุงู„ ู…ุณุฃู„ุฉ ู…ู‚ูู„ุฉ. @@ -890,6 +805,7 @@ milestones.filter_sort.least_complete = ุงู„ุฃู‚ู„ ุงูƒุชู…ุงู„ุง branch.create_branch = ุฃู†ุดุฆ ุงู„ูุฑุน %s issues.remove_self_assignment = `ุฃู„ุบู‰ ุชูƒู„ูŠู ู†ูุณู‡ %s` issues.label_edit = ุนุฏู‘ู„ +release.download_count = ุงู„ุชู†ุฒูŠู„ุงุช: %s wiki.welcome = ุฃู‡ู„ุง ุจูƒ ููŠ ุงู„ู…ูˆุณูˆุนุฉ. find_file.go_to_file = ุงู†ุชู‚ู„ ุฅู„ู‰ ู…ู„ู issues.cancel = ุฃู„ุบู @@ -940,7 +856,7 @@ issues.reopen_comment_issue = ุนู„ู‘ู‚ ูˆุฃุนุฏ ูุชุญู‡ุง issues.dependency.add = ุฃุถู ุงุนุชู…ุงุฏูŠุฉโ€ฆ issues.label_deletion_desc = ุญุฐู ุชุตู†ูŠู ูŠุญุฐูู‡ ู…ู† ูƒู„ ุงู„ู…ุณุงุฆู„ุŒ ุฃุชุฑูŠุฏ ุงู„ุงุณุชู…ุฑุงุฑุŸ labels = ุงู„ุชุตู†ูŠูุงุช -delete_preexisting_content = ุญุฐู ุงู„ู…ู„ูุงุช ููŠ %s +delete_preexisting_content = ุงุญุฐู ุงู„ู…ู„ูุงุช ููŠ %s milestones.deletion = ุงุญุฐู ุงู„ู‡ุฏู issues.comment_pull_merged_at = ุฏู…ุฌ ุงู„ุฅูŠุฏุงุน %[1]s ุฅู„ู‰ %[2]s %[3]s issues.new.closed_milestone = ุงู„ุฃู‡ุฏุงู ุงู„ุชุงู…ุฉ @@ -948,6 +864,7 @@ issues.new.milestone = ุงู„ุฃู‡ุฏุงู branch.confirm_create_branch = ุฃู†ุดุฆ ูุฑุนู‹ุง issues.close = ู…ุณุฃู„ุฉ ุชุงู…ุฉ issues.label_modify = ุนุฏู‘ู„ ุงู„ุชุตู†ูŠู +issues.author_helper = ู‡ุฐุง ุงู„ู…ุณุชุฎุฏู… ู‡ูˆ ู…ู†ุดุฆ ุงู„ู…ุณุฃู„ุฉ. issues.delete_branch_at = `ุญูุฐูู ุงู„ูุฑุน %s %s` issues.new.open_projects = ุงู„ู…ุดุฑูˆุนุงุช ุงู„ุญุงู„ูŠุฉ issues.new_label = ุชุตู†ูŠู ุฌุฏูŠุฏ @@ -964,6 +881,7 @@ issues.filter_assginee_no_select = ูƒู„ ุงู„ู…ูƒู„ููŠู† issues.new.no_projects = ุจู„ุง ู…ุดุฑูˆุน issues.new.labels = ุงู„ุชุตู†ูŠูุงุช issues.role.member = ุนุถูˆ +trust_model_helper_collaborator = ู…ุดุชุฑูƒ: ุซู‚ ุจุชูˆู‚ูŠุนุงุช ุงู„ู…ุดุชุฑููƒูŠู† issues.label_archived_filter = ุฃุธู‡ุฑ ุงู„ุชุตู†ูŠูุงุช ุงู„ู…ุคุฑุดูุฉ issues.filter_milestone = ู‡ุฏู issues.remove_label = ุฃุฒุงู„ ุงู„ุชุตู†ูŠู %s %s @@ -980,14 +898,16 @@ issues.dependency.issue_no_dependencies = ุจู„ุง ุงุนุชู…ุงุฏูŠุฉ. issues.filter_sort.mostcomment = ุงู„ุฃูƒุซุฑ ุชุนู„ูŠู‚ุงุช issues.label.filter_sort.reverse_by_size = ุงู„ุฃูƒุจุฑ ุญุฌู…ุง release.message = ุตูู ู‡ุฐุง ุงู„ุฅุตุฏุงุฑ -editor.cancel_lower = ุฅู„ุบุงุก +editor.cancel_lower = ุฃู„ุบู issues.label.filter_sort.reverse_alphabetically = ุฃุจุฌุฏูŠุง ู…ุนูƒูˆุณุง +trust_model_helper = ุงุฎุชุฑ ู†ู…ูˆุฐุฌ ุงู„ุซู‚ุฉ ู„ู„ุชุญู‚ู‚ ู…ู† ุงู„ุชูˆู‚ูŠุนุงุช. ุงู„ุฎูŠุงุฑุงุช ุงู„ู…ุชุงุญุฉ ู‡ูŠ: issues.unlock_error = ู„ุง ูŠู…ูƒู† ููƒ ู‚ูู„ ู…ุณุฃู„ุฉ ุบูŠุฑ ู…ู‚ูู„ุฉ. milestones.filter_sort.most_issues = ุงู„ุฃูƒุซุฑ ู…ุณุงุฆู„ issues.add_project_at = `ุฃุถุงู ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ ุฅู„ู‰ ุงู„ู…ุดุฑูˆุน %s %s` issues.context.reference_issue = ุฃุดุฑ ุฅู„ูŠู‡ุง ููŠ ู…ุณุฃู„ุฉ ุฌุฏูŠุฏุฉ issues.context.quote_reply = ุงู‚ุชุจุณ ููŠ ุฑุฏ issues.role.owner_helper = ู‡ุฐุง ุงู„ู…ุณุชุฎุฏู… ู‡ูˆ ู…ุงู„ูƒ ุงู„ู…ุณุชูˆุฏุน. +trust_model_helper_committer = ู…ูˆุฏุน: ุซู‚ ุจุงู„ุชูˆู‚ูŠุนุงุช ุงู„ู…ูˆุงูู‚ุฉ ู„ู„ู…ูˆุฏุนูŠู† issues.filter_project_none = ุจู„ุง ู…ุดุฑูˆุน issues.lock_no_reason = "ุฃู‚ูู„ู‡ุง ูˆู‚ูŠู‘ุฏ ุงู„ุชุญุงูˆุฑ ู„ู„ู…ุดุชุฑูƒูŠู† ููŠ ุงู„ู…ุณุชูˆุฏุน %s" issue_labels_helper = ุงุฎุชุฑ ุจุงู‚ุฉ ุชุตู†ูŠูุงุช ู„ู„ู…ุณุงุฆู„. @@ -1012,7 +932,7 @@ issues.label_archive = ุฃุฑุดู ุงู„ุชุตู†ูŠู issues.choose.blank_about = ุฃู†ุดุฆ ู…ุณุฃู„ุฉ ู…ู† ุงู„ู‚ุงู„ุจ ุงู„ู…ุจุฏุฆูŠ. issues.filter_poster = ู…ู†ุดุฆ release.delete_release = ุงุญุฐู ุงู„ุฅุตุฏุงุฑ -editor.cancel = ุฅู„ุบุงุก +editor.cancel = ุฃู„ุบู issues.change_title_at = `ุบูŠู‘ุฑ ุงู„ุนู†ูˆุงู† ู…ู† %s ุฅู„ู‰ %s %s` branch.new_branch_from = ุฃู†ุดุฆ ูุฑุนู‹ุง ุฌุฏูŠุฏู‹ุง ู…ู† "%s" issues.due_date_form_edit = "ุนุฏู‘ู„" @@ -1024,7 +944,7 @@ issues.filter_assignee = ู…ูƒู„ู issues.open_title = ุญุงู„ูŠุฉ download_file = ู†ุฒู‘ู„ ุงู„ู…ู„ู issues.attachment.download = `ุงู†ู‚ุฑ ู„ุชู†ุฒูŠู„ "%s"` -download_archive = ุชู†ุฒูŠู„ ุงู„ู…ุณุชูˆุฏุน +download_archive = ู†ุฒู‘ู„ ุงู„ู…ุณุชูˆุฏุน download_tar = ู†ุฒู‘ู„ TAR.GZ download_zip = ู†ุฒู‘ู„ ZIP releases.desc = ุชุชุจุน ุฅุตุฏุงุฑุงุช ุงู„ู…ุดุฑูˆุน ูˆุชู†ุฒูŠู„ุงุชู‡. @@ -1037,15 +957,15 @@ projects.desc = ุฃุฏุฑ ุงู„ู…ุณุงุฆู„ ูˆุทู„ุจุงุช ุงู„ุฏู…ุฌ ููŠ ู„ูˆุญุงุช ู… ambiguous_runes_header = `ูŠุญุชูˆูŠ ู‡ุฐุง ุงู„ู…ู„ู ุนู„ู‰ ู…ุญุงุฑู ูŠูˆู†ูŠูƒูˆุฏ ุบุงู…ุถุฉ` executable_file = ู…ู„ู ุชู†ููŠุฐูŠ settings.webhook.response = ุงู„ุงุณุชุฌุงุจุฉ -editor.delete = ุญุฐู %s -file_view_raw = ุฃุธู‡ุฑ ุงู„ุฎุงู… +editor.delete = ุงุญุฐู %s +file_view_raw = ุฃุธู‡ุฑ ุงู„ู…ุฌุฑุฏ settings.add_webhook = ุฃุถู ุฎุทุงู ูˆูŠุจ settings.slack_channel = ู‚ู†ุงุฉ commits = ุฅูŠุฏุงุนุงุช commit = ุฅูŠุฏุงุน -editor.upload_file = ุฑูุน ู…ู„ู +editor.upload_file = ุงุฑูุน ู…ู„ูุง settings.webhook.headers = ุงู„ุชุฑูˆูŠุณุงุช -org_labels_desc_manage = ุฅุฏุงุฑุฉ +org_labels_desc_manage = ุฃุฏุฑู‡ุง editor.patch = ุทุจู‘ู‚ ุงู„ุฑู‚ุนุฉ editor.must_have_write_access = ูŠุฌุจ ุฃู† ูŠูƒูˆู† ู„ุฏูŠูƒ ุฅู…ูƒุงู†ูŠุฉ ุงู„ูƒุชุงุจุฉ ุญุชู‰ ุชุนุฏู‘ู„ ู‡ุฐุง ุงู„ู…ู„ู ุฃูˆ ุชู‚ุชุฑุญ ุชุนุฏูŠู„ุงุช. template.webhooks = ุฎุทุงุทูŠู ุงู„ูˆูŠุจ @@ -1069,12 +989,12 @@ settings.webhook.payload = ุงู„ู…ุญุชูˆู‰ invisible_runes_header = `ูŠุญุชูˆูŠ ู‡ุฐุง ุงู„ู…ู„ู ุนู„ู‰ ู…ุญุงุฑู ูŠูˆู†ูŠูƒูˆุฏ ุบูŠุฑ ู…ุฑุฆูŠุฉ` editor.filename_help = ุฃุถู ู…ุฌู„ุฏุง ุจูƒุชุงุจุฉ ุงุณู…ู‡ ุซู… ุดุฑุทุฉ ู…ุงุฆู„ุฉ ('/'). ุงุญุฐู ู…ุฌู„ุฏุง ุจุถุบุท ุฒุฑ Backspace ุฃูˆู„ ุดูŠุก ููŠ ุฎุงู†ุฉ ุงู„ุงุณู…. editor.commit_changes = ุฃูˆุฏุน ุงู„ุชุนุฏูŠู„ุงุช -editor.add_file = ุฅุถุงูุฉ ู…ู„ู +editor.add_file = ุฃุถู ู…ู„ูุง settings.githook_name = ุงุณู… ุงู„ุฎุทุงู editor.fork_before_edit = ูŠุฌุจ ุฃู† ุชุดุชู‚ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน ุญุชู‰ ุชุนุฏู‘ู„ ู‡ุฐุง ุงู„ู…ู„ู ุฃูˆ ุชู‚ุชุฑุญ ุชุนุฏูŠู„ุงุช. projects.description_placeholder = ุงู„ูˆุตู tag = ูˆุณู… -file_raw = ุฎุงู… +file_raw = ู…ุฌุฑุฏ projects.create = ุฃู†ุดุฆ ู…ุดุฑูˆุนุง settings.update_webhook = ุญุฏู‘ุซ ุฎุทุงู ุงู„ูˆูŠุจ editor.push_rejected_no_message = ู„ู‚ุฏ ุฑูุถ ุงู„ุฎุงุฏูˆู… ุงู„ุชุนุฏูŠู„ ุจุบูŠุฑ ุฑุณุงู„ุฉ. ู†ุฑุฌูˆ ู…ุฑุงุฌุนุฉ ุฎุทุงุทูŠู ุฌุช. @@ -1093,7 +1013,7 @@ editor.no_changes_to_show = ู„ุง ุชูˆุฌุฏ ุชุนุฏูŠู„ุงุช ู„ุนุฑุถู‡ุง. settings.webhook.test_delivery = ุงุฎุชุจุงุฑ ุงู„ุชูˆุตูŠู„ commit_graph.hide_pr_refs = ุฃุฎูู ุทู„ุจุงุช ุงู„ุฏู…ุฌ editor.new_file = ู…ู„ู ุฌุฏูŠุฏ -file_view_source = ุนุฑุถ ุงู„ู…ุตุฏุฑ +file_view_source = ุฃุธู‡ุฑ ุงู„ู…ุตุฏุฑ settings.webhook_deletion_success = ุฃุฒูŠู„ ุฎุทุงู ุงู„ูˆูŠุจ. projects.title = ุงู„ุนู†ูˆุงู† settings.slack_domain = ุงู„ู†ุทุงู‚ @@ -1122,11 +1042,11 @@ settings.add_hook_success = ุฃุถูŠู ุฎุทุงู ุงู„ูˆูŠุจ. commit.revert-header = ุฅุฑุฌุงุน: %s editor.file_already_exists = ูŠูˆุฌุฏ ูุนู„ุง ููŠ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน ู…ู„ู ุจุงุณู… "%s". settings.web_hook_name_matrix = ู…ุชุฑูƒุณ -editor.filename_cannot_be_empty = ู„ุง ูŠู…ูƒู† ุชุฑูƒ ุงุณู… ุงู„ู…ู„ู ูุงุฑุบุงู‹. +editor.filename_cannot_be_empty = ู„ุง ูŠู…ูƒู† ุชุฑูƒ ุงุณู… ุงู„ู…ู„ู ูุงุฑุบุง. editor.add_tmpl = ุฃุถู '<%s>' editor.new_branch_name_desc = ุงุณู… ุงู„ูุฑุน ุงู„ุฌุฏูŠุฏโ€ฆ release = ุฅุตุฏุงุฑ -editor.delete_this_file = ุญุฐู ุงู„ู…ู„ู +editor.delete_this_file = ุงุญุฐู ุงู„ู…ู„ู editor.or = ุฃูˆ editor.push_rejected_summary = ุฑุณุงู„ุฉ ุงู„ุฑูุถ ุงู„ูƒุงู…ู„ุฉ: settings.webhook_deletion = ุฃุฒู„ ุฎุทุงู ุงู„ูˆูŠุจ @@ -1147,6 +1067,7 @@ visibility_helper_forced = ูŠูุฑุถ ู…ุฏูŠุฑ ู…ูˆู‚ุนูƒ ุฃู† ุชูƒูˆู† ุงู„ู…ุณุช wiki.page_content = ู…ุญุชูˆู‰ ุงู„ุตูุญุฉ settings.collaborator_deletion_desc = ุฅุฒุงู„ุฉ ู…ุดุชุฑูƒ ุณุชุจุทู„ ูˆุตูˆู„ู‡ ุฅู„ู‰ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน. ุฃุชุฑูŠุฏ ุงู„ุงุณุชู…ุฑุงุฑุŸ settings.remove_collaborator_success = ุฃูุฒูŠู„ ุงู„ู…ุดุชุฑูƒ. +settings.search_user_placeholder = ุงุจุญุซ ุนู† ู…ุณุชุฎุฏู…โ€ฆ settings.mirror_settings.pushed_repository = ู…ุณุชูˆุฏุน ู…ุฏููˆุน settings.delete_collaborator = ุฃุฒู„ settings.add_collaborator_success = ุฃูุถูŠู ุงู„ู…ุดุชุฑูƒ. @@ -1295,6 +1216,8 @@ milestones.close = ุชุงู… milestones.new_subheader = ุชุณุงุนุฏูƒ ุงู„ุฃู‡ุฏุงู ููŠ ุชู†ุธูŠู… ุงู„ู…ุณุงุฆู„ ูˆุชุชุจุน ุณูŠุฑู‡ุง. milestones.completeness = %d%% ู…ูƒุชู…ู„ milestones.create = ุฃู†ุดุฆ ู‡ุฏูุง +search.match.tooltip = ู„ุง ุชุฃุช ุฅู„ุง ุจุงู„ู†ุชุงุฆุฌ ุงู„ุชูŠ ุชุทุงุจู‚ ูƒู„ู…ุฉ ุงู„ุจุญุซ ุชู…ุงู…ุง +search.results = ู†ุชุงุฆุฌ ุงู„ุจุญุซ ุนู† "%s" ููŠ %s settings.collaboration = ุงู„ู…ุดุชุฑูƒูˆู† settings.collaboration.admin = ู…ุฏูŠุฑ settings.collaboration.write = ุชุญุฑูŠุฑ @@ -1343,6 +1266,7 @@ settings.transfer_perform = ุฃุชู… ู†ู‚ู„ ุงู„ู…ู„ูƒูŠุฉ settings.transfer_succeed = ุชู… ู†ู‚ู„ ู…ู„ูƒูŠุฉ ุงู„ู…ุณุชูˆุฏุน. pulls.auto_merge_newly_scheduled_comment = `ุฃู…ุฑ ุจุฌุฏูˆู„ุฉ ู‡ุฐุง ุงู„ุทู„ุจ ู„ู„ุฏู…ุฌ ุขู„ูŠุง ุนู†ุฏ ู†ุฌุงุญ ุฌู…ูŠุน ุงู„ูุญูˆุต %[1]s pulls.auto_merge_canceled_schedule_comment = `ุฃู„ุบู‰ ุงู„ุฏู…ุฌ ุงู„ุขู„ูŠ ู„ู‡ุฐุง ุงู„ุทู„ุจ ุนู†ุฏ ู†ุฌุงุญ ุฌู…ูŠุน ุงู„ูุญูˆุต %[1]s +ext_issues.desc = ุฑุงุจุท ู…ุชุชุจุน ุงู„ู…ุณุงุฆู„ ุงู„ุฎุงุฑุฌูŠ. projects.edit_subheader = ุชุณุงุนุฏ ุงู„ู…ุดุฑูˆุนุงุช ููŠ ุชู†ุธูŠู… ุงู„ู…ุณุงุฆู„ ูˆุชุชุจุน ุณูŠุฑู‡ุง. issues.tracker = ู…ุชุชุจุน ุงู„ูˆู‚ุช issues.start_tracking_short = ุดุบู‘ู„ ุงู„ู…ุคู‚ุช @@ -1374,6 +1298,10 @@ settings.trust_model.collaborator.long = ู…ุดุชุฑูƒ: ุซู‚ ุจุชูˆู‚ูŠุนุงุช ุงู„ wiki.file_revision = ู…ุฑุงุฌุนุฉ ุงู„ุตูุญุฉ wiki.wiki_page_revisions = ู…ุฑุงุฌุนุงุช ุตูุญุฉ ุงู„ู…ูˆุณูˆุนุฉ wiki.back_to_wiki = ุนุฏ ุฅู„ู‰ ุตูุญุฉ ุงู„ู…ูˆุณูˆุนุฉ +search.type.tooltip = ู†ูˆุน ุงู„ุจุญุซ +search.fuzzy = ุชู‚ุฑูŠุจูŠ +search.fuzzy.tooltip = ุงุฆุช ุจุงู„ู†ุชุงุฆุฌ ุงู„ู‚ุฑูŠุจุฉ ู…ู† ูƒู„ู…ุฉ ุงู„ุจุญุซ +search.match = ู…ุทุงุจู‚ settings = ุงู„ุฅุนุฏุงุฏุงุช settings.mirror_settings.push_mirror.remote_url = ุฑุงุจุท ู…ุณุชูˆุฏุน ุฌุช ุงู„ุจุนูŠุฏ settings.releases_desc = ูุนู‘ู„ ุงู„ุฅุตุฏุงุฑุงุช ููŠ ุงู„ู…ุณุชูˆุฏุน @@ -1383,10 +1311,12 @@ settings.trust_model = ู†ู…ูˆุฐุฌ ุงู„ุซู‚ุฉ ููŠ ุงู„ุชูˆู‚ูŠุนุงุช settings.trust_model.committer = ู…ูˆุฏูุน settings.trust_model.collaboratorcommitter = ู…ุดุชุฑูƒ+ู…ูˆุฏุน settings.trust_model.collaboratorcommitter.long = ู…ุดุชุฑูƒ+ู…ูˆุฏุน: ุซู‚ ุจุชูˆู‚ูŠุนุงุช ุงู„ู…ุดุชุฑูƒูŠู† ุงู„ุชูŠ ุชุทุงุจู‚ ุงู„ู…ูˆุฏุน +tagged_this = ูˆุณู… ู‡ุฐุง branches = ุงู„ูุฑูˆุน tags = ุงู„ูˆุณูˆู… issues = ุงู„ู…ุณุงุฆู„ pulls = ุทู„ุจุงุช ุงู„ุฏู…ุฌ +project_board = ุงู„ู…ุดุฑูˆุนุงุช packages = ุงู„ุญุฒู… actions = ุงู„ุฅุฌุฑุงุกุงุช released_this = ุฃุตุฏุฑ ู‡ุฐุง @@ -1403,10 +1333,14 @@ issues.ref_issue_from = `ุฃุดุงุฑ ุฅู„ู‰ ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ % issues.ref_pull_from = `ุฃุดุงุฑ ุฅู„ู‰ ู‡ุฐุง ุงู„ุทู„ุจ %[3]s %[1]s` issues.ref_closing_from = `ุฃุดุงุฑ ุฅู„ู‰ ุทู„ุจ ุฏู…ุฌ %[3]s ุณูŠุบู„ู‚ ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ %[1]s` issues.ref_reopening_from = `ุฃุดุงุฑ ุฅู„ู‰ ุทู„ุจ ุฏู…ุฌ %[3]s ุณูŠุนูŠุฏ ูุชุญ ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ %[1]s` +issues.ref_closed_from = `ุฃุบู„ู‚ ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ %[4]s %[2]s` +issues.ref_reopened_from = `ุฃุนุงุฏ ูุชุญ ู‡ุฐู‡ ุงู„ู…ุณุฃู„ุฉ %[4]s %[2]s` issues.reference_issue.body = ุงู„ู…ุญุชูˆู‰ +issues.reference_link = ู„ู„ุฅุดุงุฑุฉ: %s settings.actions_desc = ูุนู‘ู„ ุงู„ุฅุฌุฑุงุกุงุช ููŠ ุงู„ู…ุณุชูˆุฏุน pulls.push_rejected = ุชุนุฐุฑ ุงู„ุฏู…ุฌ: ุชู… ุฑูุถ ุงู„ุฏูุน. ุฑุงุฌุน ุฎุทุงุทูŠู ุฌุช ู„ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน. contributors.contribution_type.additions = ุงู„ุฅุถุงูุงุช +search = ุจุญุซ pulls.require_signed_wont_sign = ูŠุทู„ุจ ุงู„ูุฑุน ุฅูŠุฏุงุนุงุช ู…ูˆู‚ู‘ุนุฉุŒ ู„ูƒู† ู„ู† ูŠูƒูˆู† ู‡ุฐุง ุงู„ุฏู…ุฌ ู…ูˆู‚ู‘ุนู‹ุง pulls.update_branch = ุชุญุฏูŠุซ ุงู„ูุฑุน ุจุงู„ุฏู…ุฌ pulls.update_branch_rebase = ุชุญุฏูŠุซ ุงู„ูุฑุน ุจุฅุนุงุฏุฉ ุงู„ุชุฃุณูŠุณ @@ -1419,223 +1353,30 @@ pulls.fast_forward_only_merge_pull_request = ุชุณุฑูŠุน ูˆุญุณุจ pulls.merge_conflict = ุชุนุฐุฑ ุงู„ุฏู…ุฌ: ุญุฏุซ ู†ุฒุงุน ุฎู„ุงู„ ุงู„ุฏู…ุฌ. ู…ุณุงุนุฏุฉ: ุฌุฑุจ ุทุฑูŠู‚ุฉ ุฃุฎุฑู‰ pulls.rebase_conflict = ุชุนุฐุฑ ุงู„ุฏู…ุฌ: ุญุฏุซ ู†ุฒุงุน ุฎู„ุงู„ ุฅุนุงุฏุฉ ุชุฃุณูŠุณ ุงู„ุฅูŠุฏุงุน: %[1]s. ู…ุณุงุนุฏุฉ: ุฌุฑุจ ุทุฑูŠู‚ุฉ ุฃุฎุฑู‰ pulls.has_merged = ูุดู„: ู„ู‚ุฏ ุชู… ุฏู…ุฌ ู‡ุฐุง ุงู„ุทู„ุจุŒ ูู„ุง ูŠู…ูƒู†ูƒ ุฏู…ุฌู‡ ู…ุฌุฏุฏุง ุฃูˆ ุชุบูŠูŠุฑ ุงู„ูุฑุน ุงู„ู‡ุฏู. -new_repo_helper = ูŠุญุชูˆูŠ ุงู„ู…ุณุชูˆุฏุน ุนู„ู‰ ุฌู…ูŠุน ู…ู„ูุงุช ุงู„ู…ุดุฑูˆุนุŒ ุจู…ุง ููŠ ุฐู„ูƒ ุณุฌู„ ุงู„ุชุนุฏูŠู„ุงุช. ู‡ู„ ุชุณุชุถูŠู ูˆุงุญุฏู‹ุง ุจุงู„ูุนู„ ุนู„ู‰ ู…ู†ุตุฉ ุฃุฎุฑู‰ุŸ ู†ู‚ู„ ุงู„ู…ุณุชูˆุฏุน. -new_from_template = ุงุณุชุฎุฏู… ู‚ุงู„ุจุงู‹ -new_advanced = ุฅุนุฏุงุฏุงุช ู…ู‚ุชุฏู…ุฉ -new_advanced_expand = ุงู†ู‚ุฑ ู„ู„ุชูˆุณุนุฉ -new_from_template_description = ูŠู…ูƒู†ูƒ ุชุญุฏูŠุฏ ู‚ุงู„ุจ ู…ุณุชูˆุฏุน ู…ูˆุฌูˆุฏ ุนู„ู‰ ู‡ุฐุง ุงู„ู…ุซูŠู„ ูˆุชุทุจูŠู‚ ุฅุนุฏุงุฏุงุชู‡. -owner_helper = ู‚ุฏ ู„ุง ุชุธู‡ุฑ ุจุนุถ ู…ู†ุชุฏูŠุงุช ุงู„ู…ุฌู…ูˆุนุฉ ููŠ ุงู„ู‚ุงุฆู…ุฉ ุงู„ู…ู†ุณุฏู„ุฉ ุจุณุจุจ ุงู„ุญุฏ ุงู„ุฃู‚ุตู‰ ู„ุนุฏุฏ ุงู„ู…ุณุชูˆุฏุนุงุช. -fork_from = ุงุดุชู‚ ู…ู† -fork_visibility_helper = ู„ุง ูŠู…ูƒู† ุชุบูŠูŠุฑ ุธู‡ูˆุฑ ุงู„ู…ุณุชูˆุฏุน ุงู„ู…ุดุชู‘ู‚. -generate_repo = ุชูˆู„ูŠุฏ ู„ู…ุณุชูˆุฏุน -readme_helper_desc = ู‡ุฐุง ู‡ูˆ ุงู„ู…ูƒุงู† ุงู„ุฐูŠ ูŠู…ูƒู†ูƒ ููŠู‡ ูƒุชุงุจุฉ ูˆุตู ูƒุงู…ู„ ู„ู…ุดุฑูˆุนูƒ. -repo_gitignore_helper = ุญุฏุฏ ู‚ูˆุงู„ุจ .gitignore -auto_init = ุชู‡ูŠุฆุฉ ุงู„ู…ุณุชูˆุฏุน -default_branch_label = ุงูุชุฑุงุถูŠ -auto_init_description = ุงุจุฏุฃ ุณุฌู„ Git ุจู…ู„ู READMEุŒ ู…ุน ุฅู…ูƒุงู†ูŠุฉ ุฅุถุงูุฉ ู…ู„ูุงุช ุงู„ุฑุฎุตุฉ ูˆ.gitignore ุงุฎุชูŠุงุฑูŠุงู‹. -mirror_use_ssh.text = ุงุณุชุฎุฏู… ู…ุตุงุฏู‚ุฉ SSH -mirror_address = ุงุณุชู†ุณุงุฎ ุนุจุฑ URL -mirror_prune_desc = ุฅุฒุงู„ุฉ ู…ุฑุงุฌุน ุงู„ุชุชุจุน ุนู† ุจูุนุฏ ุงู„ู‚ุฏูŠู…ุฉ -mirror_interval_invalid = ุงู„ูุงุตู„ ุงู„ุฒู…ู†ูŠ ู„ู„ู…ุฑุขุฉ ุบูŠุฑ ุตุงู„ุญ. -readme_helper = ุญุฏุฏ ู‚ุงู„ุจ ู…ู„ู README -generate_from = ุงู„ุชูˆู„ูŠุฏ ู…ู† -mirror_use_ssh.not_available = ุงู„ู…ุตุงุฏู‚ุฉ ุนุจุฑ SSH ุบูŠุฑ ู…ุชุงุญุฉ. -open_with_editor = ุงูุชุญ ุจู€ %s -mirror_prune = ุชู†ู‚ูŠุฉ -visibility_fork_helper = (ุณูŠุคุซุฑ ุชุบูŠูŠุฑ ุฐู„ูƒ ุนู„ู‰ ุฑุคูŠุฉ ุฌู…ูŠุน ุงู„ู…ุดุชู‚ุงุช.) -clone_helper = ุชุญุชุงุฌ ู…ุณุงุนุฏุฉ ููŠ ุงู„ุงุณุชู†ุณุงุฎุŸ ุฒูุฑ ุงู„ู…ุณุงุนุฏุฉ. -mirror_public_key = ู…ูุชุงุญ SSH ุนุงู… -size_format = %[1]s: %[2]s, %[3]s: %[4]s -visibility_description = ูู‚ุท ุงู„ู…ุงู„ูƒ ุฃูˆ ุฃุนุถุงุก ุงู„ู…ุคุณุณุฉ ุฅุฐุง ูƒุงู† ู„ุฏูŠู‡ู… ุญู‚ูˆู‚ุŒ ุณูŠุชู…ูƒู†ูˆู† ู…ู† ุฑุคูŠุชู‡. -license_helper_desc = ุชุญุฏุฏ ุงู„ุฑุฎุตุฉ ู…ุง ูŠู…ูƒู† ู„ู„ุขุฎุฑูŠู† ูุนู„ู‡ ุฃูˆ ุนุฏู… ูุนู„ู‡ ุจุดูŠูุฑุฉ ุจุฑู…ุฌูŠุชูƒ. ู„ุณุช ู…ุชุฃูƒุฏู‹ุง ู…ู† ุงู„ุฑุฎุตุฉ ุงู„ู…ู†ุงุณุจุฉ ู„ู…ุดุฑูˆุนูƒุŸ ุทุงู„ุน ุงุฎุชูŠุงุฑ ุงู„ุฑุฎุตุฉ. -mirror_denied_combination = ู„ุง ูŠู…ูƒู† ุงุณุชุฎุฏุงู… ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ู…ุณุชู†ุฏุฉ ุฅู„ู‰ ุงู„ู…ูุชุงุญ ุงู„ุนุงู… ูˆูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ู…ุนุงู‹. -repo_gitignore_helper_desc = ุงุฎุชุฑ ุงู„ู…ู„ูุงุช ุงู„ุชูŠ ู„ุง ุชุฑูŠุฏ ุชุชุจุนู‡ุง ู…ู† ู‚ุงุฆู…ุฉ ุงู„ู‚ูˆุงู„ุจ ุงู„ุฎุงุตุฉ ุจุงู„ู„ุบุงุช ุงู„ุดุงุฆุนุฉ. ูŠุชู… ุชุถู…ูŠู† ุงู„ู‚ุทุน ุงู„ุฃุซุฑูŠุฉ ุงู„ู†ู…ูˆุฐุฌูŠุฉ ุงู„ุชูŠ ุชู… ุฅู†ุดุงุคู‡ุง ุจูˆุงุณุทุฉ ุฃุฏูˆุงุช ุงู„ุจู†ุงุก ุงู„ุฎุงุตุฉ ุจูƒู„ ู„ุบุฉ ููŠ .gitignore ุจุดูƒู„ ุงูุชุฑุงุถูŠ. -stars = ุงู„ู†ุฌูˆู… -default_branch_helper = ุงู„ูุฑุน ุงู„ุงูุชุฑุงุถูŠ ู‡ูˆ ุงู„ูุฑุน ุงู„ุฃุณุงุณูŠ ู„ุทู„ุจุงุช ุงู„ุณุญุจ ุŒูˆุนู…ู„ูŠุงุช ุฅู„ุฅูŠุฏุงุน. -mirror_use_ssh.helper = ุณูŠู‚ูˆู… Forgejo ุจุนูƒุณ ุงู„ู…ุณุชูˆุฏุน ุนุจุฑ Git ุนุจุฑ SSH ูˆุฅู†ุดุงุก ุฒูˆุฌ ู…ูุงุชูŠุญ ู„ูƒ ุนู†ุฏ ุชุญุฏูŠุฏ ู‡ุฐุง ุงู„ุฎูŠุงุฑ. ูŠุฌุจ ุนู„ูŠูƒ ุงู„ุชุฃูƒุฏ ู…ู† ุฃู† ุงู„ู…ูุชุงุญ ุงู„ุนุงู… ุงู„ุฐูŠ ุชู… ุฅู†ุดุงุคู‡ ู…ุฎูˆู„ ู„ู„ุฏูุน ุฅู„ู‰ ุงู„ู…ุณุชูˆุฏุน ุงู„ูˆุฌู‡ุฉ. ู„ุง ูŠู…ูƒู†ูƒ ุงุณุชุฎุฏุงู… ุงู„ุชุฎูˆูŠู„ ุงู„ู…ุณุชู†ุฏ ุฅู„ู‰ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ุนู†ุฏ ุชุญุฏูŠุฏ ู‡ุฐุง ุงู„ุฎูŠุงุฑ. -desc.private = ุฎุงุต -readme = README -mirror_interval = ุงู„ูุงุตู„ ุงู„ุฒู…ู†ูŠ ู„ู„ู…ุฑุขุฉ (ูˆุญุฏุงุช ุงู„ูˆู‚ุช ุงู„ุตุญูŠุญุฉ ู‡ูŠ 'h' ุŒ'm' ุŒ's'). 0 ู„ุชุนุทูŠู„ ุงู„ู…ุฒุงู…ู†ุฉ ุงู„ุฏูˆุฑูŠุฉ. (ุงู„ุญุฏ ุงู„ุฃุฏู†ู‰: %s) -desc.template = ู‚ุงู„ุจ -desc.public = ุนุงู… -visibility = ุงู„ุฑุคูŠุฉ -migrate_options_mirror_helper = ุณูŠูƒูˆู† ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน ู…ุฑุขุฉ -adopt_preexisting_success = ุงู„ู…ู„ูุงุช ุงู„ู…ุนุชู…ุฏุฉ ูˆุงู„ู…ุณุชูˆุฏุน ุงู„ุฐูŠ ุชู… ุฅู†ุดุงุคู‡ ู…ู† %s -archive.title_date = ุชู…ุช ุฃุฑุดูุฉ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน ุนู„ู‰ %s. ูŠู…ูƒู†ูƒ ุนุฑุถ ุงู„ู…ู„ูุงุช ูˆุงุณุชู†ุณุงุฎู‡ุŒ ู„ูƒู† ู„ุง ูŠู…ูƒู†ูƒ ุฅุฌุฑุงุก ุฃูŠ ุชุบูŠูŠุฑุงุช ุนู„ู‰ ุญุงู„ุชู‡ุŒ ู…ุซู„ ุฏูุน ูˆุฅู†ุดุงุก ุจู„ุงุบุงุช ุฃูˆ ุทู„ุจุงุช ุณุญุจ ุฃูˆ ุชุนู„ูŠู‚ุงุช ุฌุฏูŠุฏุฉ. -migrate_options_lfs_endpoint.label = ู†ู‚ุทุฉ ู†ู‡ุงูŠุฉ LFS -transfer.reject_desc = ุฅู„ุบุงุก ุงู„ู†ู‚ู„ ุฅู„ู‰ โ€%sโ€œ -archive.title = ุชู…ุช ุฃุฑุดูุฉ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน. ูŠู…ูƒู†ูƒ ุนุฑุถ ุงู„ู…ู„ูุงุช ูˆุงุณุชู†ุณุงุฎู‡ุŒ ู„ูƒู† ู„ุง ูŠู…ูƒู†ูƒ ุฅุฌุฑุงุก ุฃูŠ ุชุบูŠูŠุฑุงุช ุนู„ู‰ ุญุงู„ุชู‡ุŒ ู…ุซู„ ุฏูุน ูˆุฅู†ุดุงุก ุจู„ุงุบุงุช ุฃูˆ ุทู„ุจุงุช ุณุญุจ ุฃูˆ ุชุนู„ูŠู‚ุงุช ุฌุฏูŠุฏุฉ. -stargazers = ุงู„ู…ู…ูŠู‘ูุฒูˆู† ุจู†ุฌู…ุฉ -form.reach_limit_of_creation_n = ู„ู‚ุฏ ูˆุตู„ ุงู„ู…ุงู„ูƒ ุจุงู„ูุนู„ ุฅู„ู‰ ุงู„ุญุฏ ุงู„ุฃู‚ุตู‰ ู„ู„ู…ุณุชูˆุฏุนุงุช %d. -mirror_sync_on_commit = ุงู„ู…ุฒุงู…ู†ุฉ ุนู†ุฏ ุฏูุน ุงู„ุฅูŠุฏุงุนุงุช -mirror_lfs_desc = ุชู†ุดูŠุท ุงู„ู†ุณุฎ ุงู„ู…ุชุทุงุจู‚ ู„ุจูŠุงู†ุงุช LFS. -author_search_tooltip = ุนุฑุถ ูƒุญุฏ ุฃู‚ุตู‰ 30 ู…ุณุชุฎุฏู…ู‹ุง -template.git_content = ู…ุญุชูˆู‰ Git (ุงู„ูุฑุน ุงู„ุงูุชุฑุงุถูŠ) -need_auth = ุงู„ู…ุตุงุฏู‚ุฉ -migrate_options_lfs_endpoint.description.local = ูŠุชู… ุฏุนู… ู…ุณุงุฑ ุงู„ุฎุงุฏู… ุงู„ู…ุญู„ูŠ ุฃูŠุถุงู‹. -template.one_item = ูŠุฌุจ ุนู„ู‰ ุงู„ุฃู‚ู„ ุชุญุฏูŠุฏ ุนู†ุตุฑ ู‚ุงู„ุจ ูˆุงุญุฏ -archive.pull.noreview = ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน ู…ุคุฑุดู. ู„ุง ูŠู…ูƒู†ูƒ ู…ุฑุงุฌุนุฉ ุทู„ุจุงุช ุงู„ุณุญุจ. -migrate.clone_address = ุชุฑุญูŠู„ / ุงุณุชู†ุณุงุฎ ู…ู† ุนู†ูˆุงู† URL -migrate.repo_desc_helper = ุงุชุฑูƒู‡ ูุงุฑุบุงู‹ ู„ุงุณุชูŠุฑุงุฏ ุงู„ูˆุตู ุงู„ู…ูˆุฌูˆุฏ -archive.nocomment = ุงู„ุชุนู„ูŠู‚ ุบูŠุฑ ู…ู…ูƒู† ู„ุฃู† ุงู„ู…ุณุชูˆุฏุน ุชู…ุช ุฃุฑุดูุชู‡. -mirror_address_protocol_invalid = ุนู†ูˆุงู† URL ุงู„ู…ู‚ุฏู… ุบูŠุฑ ุตุงู„ุญ. ูŠู…ูƒู† ุงุณุชุฎุฏุงู… ู…ูˆุงู‚ุน http(s):// ุฃูˆ git:// ูู‚ุท ู„ู„ู†ุณุฎ ุงู„ู…ุชุทุงุจู‚. -mirror_lfs_endpoint = ู†ู‚ุทุฉ ู†ู‡ุงูŠุฉ LFS -mirror_lfs_endpoint_desc = ุณุชุญุงูˆู„ ุงู„ู…ุฒุงู…ู†ุฉ ุงุณุชุฎุฏุงู… ุนู†ูˆุงู† url ุงู„ู…ุณุชู†ุณุฎ ุฅู„ู‰ ุชุญุฏูŠุฏ ุฎุงุฏู… LFS. ูŠู…ูƒู†ูƒ ุฃูŠุถู‹ุง ุชุญุฏูŠุฏ ู†ู‚ุทุฉ ู†ู‡ุงูŠุฉ ู…ุฎุตุตุฉ ุฅุฐุง ูƒุงู†ุช ุจูŠุงู†ุงุช LFS ุงู„ู…ุณุชูˆุฏุน ู…ุฎุฒู†ุฉ ููŠ ู…ูƒุงู† ุขุฎุฑ. -mirror_password_blank_placeholder = (ุจู„ุง ุชุนูŠูŠู†) -delete_preexisting_success = ุงู„ู…ู„ูุงุช ุงู„ู…ุญุฐูˆูุฉ ุบูŠุฑ ุงู„ู…ุนุชู…ุฏุฉ ููŠ %s -blame_prior = ุนุฑุถ ุงู„ู†ู‘ู‚ุฏ ู‚ุจู„ ู‡ุฐุง ุงู„ุชุบูŠูŠุฑ -blame.ignore_revs = ุฌุงุฑูŠ ุชุฌุงู‡ู„ ุงู„ู…ุฑุงุฌุนุงุช ููŠ .git-blame-ignore-revs. ุงู†ู‚ุฑ ู‡ู†ุง ู„ุชุฌุงูˆุฒ ูˆุนุฑุถ ูˆุงุฌู‡ุฉ blame ุงู„ุนุงุฏูŠุฉ. -desc.archived = ู…ุคุฑุดู -template.issue_labels = ูˆุณูˆู… ุงู„ุฅุจู„ุงุบุงุช -sync_fork.branch_behind_one = ู‡ุฐุง ุงู„ูุฑุน ู‡ูˆ %[1]d ุฅูŠุฏุงุน ุฎู„ู %[2]s -sync_fork.button = ู…ุฒุงู…ู†ุฉ -transfer.no_permission_to_reject = ู„ุง ุชู…ู„ูƒ ุงู„ุตู„ุงุญูŠุฉ ู„ุฑูุถ ู‡ุฐุง ุงู„ู†ู‚ู„. -form.string_too_long = ุงู„ุณู„ุณู„ุฉ ุงู„ู…ุญุฏุฏุฉ ุฃุทูˆู„ ู…ู† d ุญุฑูุงู‹. -migrate_options = ุฎูŠุงุฑุงุช ุงู„ุชุฑุญูŠู„ -migrate_options_lfs = ุชุฑุญูŠู„ ู…ู„ูุงุช LFS -migrate.clone_local_path = ุฃูˆ ู…ุณุงุฑ ุฎุงุฏู… ู…ุญู„ูŠ -mirror_password_help = ุชุบูŠูŠุฑ ุงุณู… ุงู„ู…ุณุชุฎุฏู… ู„ู…ุณุญ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ุงู„ู…ุฎุฒู†ุฉ. -watchers = ุงู„ู…ุฑุงู‚ุจูˆู† -template.items = ุนู†ุงุตุฑ ุงู„ู‚ุงู„ุจ -template.topics = ุงู„ู…ูˆุงุถูŠุน -migrate_options_lfs_endpoint.placeholder = ุฅุฐุง ุชูุฑูƒุช ูุงุฑุบุฉุŒ ุณูŠุชู… ุงุดุชู‚ุงู‚ ู†ู‚ุทุฉ ุงู„ู†ู‡ุงูŠุฉ ู…ู† ุนู†ูˆุงู† URL ุงู„ู…ุณุชู†ุณุฎ -migrate.clone_address_desc = ุฑุงุจุท HTTP(S) ุฃูˆ Git ู„ุงุณุชู†ุณุงุฎ ู…ุณุชูˆุฏุน ู…ูˆุฌูˆุฏ -migrate.github_token_desc = ูŠู…ูƒู†ูƒ ูˆุถุน ุฑู…ุฒ ูุฑูŠุฏ ุฃูˆ ุฃูƒุซุฑ ู‡ู†ุง ู…ูุตูˆู„ ุจููˆุงุตู„ ู„ุฌุนู„ ุงู„ุชุฑุญูŠู„ ุฃุณุฑุน ู…ู† ุฎู„ุงู„ ุงู„ุชุญุงูŠู„ ุนู„ู‰ ุญุฏ ู…ุนุฏู„ GitHub API. ุชุญุฐูŠุฑ: ู‚ุฏ ูŠุคุฏูŠ ุฅุณุงุกุฉ ุงุณุชุฎุฏุงู… ู‡ุฐู‡ ุงู„ู…ูŠุฒุฉ ุฅู„ู‰ ุงู†ุชู‡ุงูƒ ุณูŠุงุณุฉ ู…ุฒูˆุฏ ุงู„ุฎุฏู…ุฉ ูˆู‚ุฏ ูŠุคุฏูŠ ุฅู„ู‰ ุญุธุฑ ุญุณุงุจูƒ (ุญุณุงุจุงุชูƒ). -transfer.no_permission_to_accept = ู„ุง ุชู…ู„ูƒ ุงู„ุตู„ุงุญูŠุฉ ู„ู‚ุจูˆู„ ู‡ุฐุง ุงู„ู†ู‚ู„. -transfer.reject = ุฑูุถ ุงู„ู†ู‚ู„ -transfer.accept_desc = ุงู„ู†ู‚ู„ ุฅู„ู‰ โ€%sโ€œ -desc.internal = ุฏุงุฎู„ูŠ -summary_card_alt = ุจุทุงู‚ุฉ ู…ู„ุฎุต ุงู„ู…ุณุชูˆุฏุน %s -transfer.accept = ู‚ุจูˆู„ ุงู„ู†ู‚ู„ -blame.ignore_revs.failed = ูุดู„ ุชุฌุงู‡ู„ ุงู„ู…ุฑุงุฌุนุงุช ููŠ .git-blame-ignore-revs. -form.name_pattern_not_allowed = ุงู„ู†ู…ุท โ€%sโ€œ ุบูŠุฑ ู…ุณู…ูˆุญ ุจู‡ ููŠ ุงุณู… ุงู„ู…ุณุชูˆุฏุน. -migrate_options_lfs_endpoint.description = ุณูŠุญุงูˆู„ ุงู„ุชุฑุญูŠู„ ุงุณุชุฎุฏุงู… ู…ุณุงุฑ Git ุงู„ุจุนูŠุฏ (remote) ู„ู€ ุชุญุฏูŠุฏ ุฎุงุฏู… LFS. ูŠู…ูƒู†ูƒ ุฃูŠุถู‹ุง ุชุญุฏูŠุฏ ู†ู‚ุทุฉ ู†ู‡ุงูŠุฉ ู…ุฎุตุตุฉ ุฅุฐุง ูƒุงู†ุช ุจูŠุงู†ุงุช LFS ู„ู„ู…ุณุชูˆุฏุน ู…ุฎุฒู†ุฉ ููŠ ู…ูƒุงู† ุขุฎุฑ. -migrate_items = ุนู†ุงุตุฑ ุงู„ุชุฑุญูŠู„ -adopt_preexisting_content = ุฅู†ุดุงุก ู…ุณุชูˆุฏุน ู…ู† %s -migrate_repo = ุชุฑุญูŠู„ ุงู„ู…ุณุชูˆุฏุน -mirror_password_placeholder = (ู„ู… ูŠุชู… ุชุนุฏูŠู„ู‡) -sync_fork.branch_behind_few = ู‡ุฐุง ุงู„ูุฑุน ู‡ูˆ %[1]d ุฅูŠุฏุงุนุงุช ุฎู„ู %[2]s -mirror_address_desc = ุถุน ุฃูŠ ุจูŠุงู†ุงุช ุงุนุชู…ุงุฏ ู…ุทู„ูˆุจุฉ ููŠ ู‚ุณู… ุงู„ู…ุตุงุฏู‚ุฉ. -mirror_last_synced = ุขุฎุฑ ู…ุฒุงู…ู†ุฉ -mirror_lfs = ุชุฎุฒูŠู† ุงู„ู…ู„ูุงุช ุงู„ูƒุจูŠุฑุฉ (LFS) -stars_remove_warning = ุณูŠุคุฏูŠ ุฐู„ูƒ ุฅู„ู‰ ุฅุฒุงู„ุฉ ุฌู…ูŠุน ุงู„ู†ุฌูˆู… ู…ู† ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน. -reactions_more = ูˆ %d ุฃูƒุซุฑ -template.invalid = ูŠุฌุจ ุชุญุฏูŠุฏ ู…ุณุชูˆุฏุน ุงู„ู‚ูˆุงู„ุจ -adopt_search = ุฃุฏุฎู„ ุงุณู… ุงู„ู…ุณุชุฎุฏู… ู„ู„ุจุญุซ ุนู† ู…ุณุชูˆุฏุนุงุช ุบูŠุฑ ู…ุนุชู…ุฏุฉ... (ุงุชุฑูƒู‡ ูุงุฑุบุงู‹ ู„ู„ุนุซูˆุฑ ุนู„ู‰ ุงู„ูƒู„) -adopt_preexisting = ุงุนุชู…ุงุฏ ุงู„ู…ู„ูุงุช ุงู„ู…ูˆุฌูˆุฏุฉ ู…ุณุจู‚ุงู‹ -language_other = ุฃูุฎุฑู‰ -adopt_preexisting_label = ุงุนุชู…ุงุฏ ุงู„ู…ู„ูุงุช -form.reach_limit_of_creation_1 = ู„ู‚ุฏ ูˆุตู„ ุงู„ู…ุงู„ูƒ ุจุงู„ูุนู„ ุฅู„ู‰ ุงู„ุญุฏ ุงู„ุฃู‚ุตู‰ ู„ู„ู…ุณุชูˆุฏุน %d. -form.name_reserved = ุชู… ุญุฌุฒ ุงุณู… ุงู„ู…ุณุชูˆุฏุน โ€%sโ€œ. -mirror_address_url_invalid = ุนู†ูˆุงู† URL ุงู„ู…ู‚ุฏู… ุบูŠุฑ ุตุงู„ุญ. ุชุฃูƒุฏ ู…ู† ุชุญุฑูŠุฑ ู…ูƒูˆู†ุงุช ุนู†ูˆุงู† URL ุจุดูƒู„ ุตุญูŠุญ. -migrate.migrate = ุงู„ุชุฑุญูŠู„ ู…ู† %s -migrate.migrating_topics = ุชุฑุญูŠู„ ุงู„ู…ูˆุงุถูŠุน -migrate.cancel_migrating_title = ุฅู„ุบุงุก ุงู„ุชุฑุญูŠู„ -generated_from = ุชู… ุชูˆู„ูŠุฏู‡ ู…ู† -star_guest_user = ู‚ู… ุจุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ู„ุฅุนุทุงุก ู†ุฌู…ุฉ ู„ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน. -subscribe.pull.guest.tooltip = ุณุฌู‘ู„ ุงู„ุฏุฎูˆู„ ู„ู„ุงุดุชุฑุงูƒ ููŠ ุทู„ุจ ุงู„ุณุญุจ ู‡ุฐุง. -unwatch = ุฅู„ุบุงุก ุงู„ู…ุดุงู‡ุฏุฉ -quick_guide = ุฏู„ูŠู„ ุณุฑูŠุน -empty_message = ู„ุง ูŠุญุชูˆูŠ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน ุนู„ู‰ ุฃูŠ ู…ุญุชูˆู‰. -migrate.migrating_labels = ุชุฑุญูŠู„ ุงู„ูˆุณูˆู… -migrate.migrating_releases = ุชุฑุญูŠู„ ุงู„ุฅุตุฏุงุฑุงุช -watch_guest_user = ุณุฌู‘ู„ ุงู„ุฏุฎูˆู„ ู„ู…ุดุงู‡ุฏุฉ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน. -star = ู†ุฌู…ุฉ -cite_this_repo = ุงู„ุงุณุชุดู‡ุงุฏ ุจู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน -no_desc = ู„ุง ูŠูˆุฌุฏ ูˆุตู -migrated_from_fake =ุชู… ุงู„ุชุฑุญูŠู„ ู…ู† %[1]s -clone_this_repo = ุงุณุชู†ุณุฎ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน -fork_from_self = ู„ุง ูŠู…ูƒู†ูƒ ุงุดุชู‚ุงู‚ ู…ุณุชูˆุฏุน ุชู…ู„ูƒู‡. -fork_guest_user = ุณุฌู‘ู„ ุงู„ุฏุฎูˆู„ ู„ุงุดุชู‚ุงู‚ ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน. -subscribe.issue.guest.tooltip = ุณุฌู‘ู„ ุงู„ุฏุฎูˆู„ ู„ู„ุงุดุชุฑุงูƒ ููŠ ู‡ุฐุง ุงู„ุจู„ุงุบ. -more_operations = ุงู„ู…ุฒูŠุฏ ู…ู† ุงู„ุนู…ู„ูŠุงุช -push_exist_repo = ุฏูุน ู…ุณุชูˆุฏุน ู…ูˆุฌูˆุฏ ู…ู† ู…ูˆุฌู‘ู‡ ุงู„ุฃูˆุงู…ุฑ -broken_message = ู„ุง ูŠู…ูƒู† ู‚ุฑุงุกุฉ ุจูŠุงู†ุงุช Git ุงู„ุชูŠ ูŠุณุชู†ุฏ ุฅู„ูŠู‡ุง ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน. ุงุชุตู„ ุจู…ุณุคูˆู„ ู‡ุฐุง ุงู„ู…ุซูŠู„ ุฃูˆ ุงุญุฐู ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน. -watch = ุดุงู‡ุฏ -migrate.migrating_git = ุชุฑุญูŠู„ ุจูŠุงู†ุงุช Git -migrate.cancel_migrating_confirm = ุชุฑูŠุฏ ุฅู„ุบุงุก ุนู…ู„ูŠุฉ ุงู„ุชุฑุญูŠู„ ู‡ุฐู‡ุŸ -migrate.permission_denied_blocked = ู„ุง ูŠู…ูƒู†ูƒ ุงู„ุงุณุชูŠุฑุงุฏ ู…ู† ู…ุถูŠููŠู† ุบูŠุฑ ู…ุณู…ูˆุญ ุจู‡ู…ุŒ ูŠูุฑุฌู‰ ุงู„ุทู„ุจ ู…ู† ุงู„ู…ุณุคูˆู„ ุงู„ุชุญู‚ู‚ ู…ู† ุฅุนุฏุงุฏุงุช ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS. -migrate.migrating = ุงู„ุชุฑุญูŠู„ ู…ู† %s โ€ฆ -migrate.migrating_failed.error = ุฃุฎูู‚ ุงู„ุชุฑุญูŠู„: %s -migrate.invalid_local_path = ุงู„ู…ุณุงุฑ ุงู„ู…ุญู„ูŠ ุบูŠุฑ ุตุงู„ุญ. ูู‡ูˆ ุบูŠุฑ ู…ูˆุฌูˆุฏ ุฃูˆ ู„ูŠุณ ู…ุฌู„ุฏุงู‹. -migrate.permission_denied = ู„ุง ูŠูุณู…ุญ ู„ูƒ ุจุงุณุชูŠุฑุงุฏ ุงู„ู…ุณุชูˆุฏุนุงุช ุงู„ู…ุญู„ูŠุฉ. -migrate.failed = ุฃุฎูู‚ ุงู„ุชุฑุญูŠู„: %v -migrate.migrate_items_options = ุฑู…ุฒ ุงู„ูˆุตูˆู„ ุงู„ูุฑูŠุฏ ู…ุทู„ูˆุจ ู„ุชุฑุญูŠู„ ุงู„ุนู†ุงุตุฑ ุงู„ุฅุถุงููŠุฉ -migrated_from = ุชู… ุงู„ุชุฑุญูŠู„ ู…ู† %[2]s -mirror_from = ู…ุฑุขุฉ ู„ู€ -forked_from = ู…ุดุชู‚ู‘ ู…ู† -create_new_repo_command = ุฅู†ุดุงุก ู…ุณุชูˆุฏุน ุฌุฏูŠุฏ ุนู„ู‰ ู…ูˆุฌู‘ู‡ ุงู„ุฃูˆุงู…ุฑ -fork = ุงุดุชู‚ุงู‚ -migrate.migrating_failed_no_addr = ุฃุฎูู‚ ุงู„ุชุฑุญูŠู„. -unstar = ุฅุฒุงู„ุฉ ุงู„ู†ุฌู…ุฉ -migrate.migrating_issues = ุชุฑุญูŠู„ ุงู„ุจู„ุงุบุงุช -migrate.migrating_pulls = ุชุฑุญูŠู„ ุทู„ุจุงุช ุงู„ุณุญุจ -code = ุงู„ูƒูˆุฏ -migrate.invalid_lfs_endpoint = ู†ู‚ุทุฉ ู†ู‡ุงูŠุฉ LFS ุบูŠุฑ ุตุงู„ุญุฉ. -migrate.migrating_failed = ูุดู„ ุงู„ุชุฑุญูŠู„ ู…ู† %s. -branch = ูุฑุน -template.git_hooks_tooltip = ูŠุชุนุฐุฑ ุนู„ูŠูƒ ุญุงู„ูŠู‹ุง ุชุนุฏูŠู„ ุฃูˆ ุฅุฒุงู„ุฉ ุฎุทุงูุงุช Git ุจู…ุฌุฑุฏ ุฅุถุงูุชู‡ุง. ุญุฏุฏ ู‡ุฐุง ูู‚ุท ุฅุฐุง ูƒู†ุช ุชุซู‚ ุจู…ุณุชูˆุฏุน ุงู„ู‚ุงู„ุจ. -code.desc = ุงู„ูˆุตูˆู„ ุฅู„ู‰ ุงู„ุดูŠูุฑุฉ ุงู„ู…ุตุฏุฑูŠุฉ ูˆุงู„ู…ู„ูุงุช ูˆุงู„ุงู„ุชุฒุงู…ุงุช ูˆุงู„ูุฑูˆุน. -tree = ุดุฌุฑุฉ -clear_ref = 'ู…ุณุญ ุงู„ู…ุฑุฌุน ุงู„ุญุงู„ูŠ' -project = ุงู„ู…ุดุงุฑูŠูŠุน -filter_branch_and_tag = ุชุตููŠุฉ ุงู„ูุฑุน ุฃูˆ ุงู„ุนู„ุงู…ุฉ -find_tag = ุงู„ุจุญุซ ุนู† ุนู„ุงู…ุฉ -commit_graph = ุงู„ุฑุณู… ุงู„ุจูŠุงู†ูŠ ู„ู„ุฅูŠุฏุงุน -editor.edit_this_file = ุนุฏู„ ุงู„ู…ู„ู -editor.signoff_desc = ุฃุถู ู…ู‚ุทูˆุฑุฉ ู…ูˆู‚ู‘ุนุฉ ู…ู† ู‚ูุจู„ ุงู„ู…ูุฌุฑู‘ุฏ ููŠ ู†ู‡ุงูŠุฉ ุฑุณุงู„ุฉ ุณุฌู„ ุงู„ุฏุฎูˆู„. -n_release_one = %s ุฅุตุฏุงุฑ -symbolic_link = ุฑุงุจุท ุฑู…ุฒูŠ -editor.cannot_edit_lfs_files = ู„ุง ูŠู…ูƒู† ุชุญุฑูŠุฑ ู…ู„ูุงุช LFS ููŠ ูˆุงุฌู‡ุฉ ุงู„ูˆูŠุจ. -editor.this_file_locked = ุงู„ู…ู„ู ู…ู‚ูู„ -n_commit_few = %s ุฅูŠุฏุงุนุงุช -editor.file_delete_success = ุชู… ุญุฐู ุงู„ู…ู„ู "%s". -editor.edit_file = ุนุฏู‘ู„ ุงู„ู…ู„ู -commit.contained_in_default_branch = ู‡ุฐุง ุงู„ุฅูŠุฏุงุน ุฌุฒุก ู…ู† ุงู„ูุฑุน ุงู„ุงูุชุฑุงุถูŠ -line = ุณุทุฑ -lines = ุฃุณุทุฑ -normal_view = ุนุฑุถ ุนุงุฏูŠ -n_branch_one = %s ูุฑุน -n_commit_one = %s ุฅูŠุฏุงุน -view_git_blame = ุนุฑุถ ู…ุณุคูˆู„ ุชุนุฏูŠู„ git -editor.add_tmpl.filename = ุงุณู… ุงู„ู…ู„ู -editor.name_your_file = ุงุณู… ู…ู„ููƒโ€ฆ -editor.propose_file_change = ุงู‚ุชุฑุงุญ ุชุบูŠูŠุฑ ุงู„ู…ู„ู -editor.new_branch_name = ุชุณู…ูŠุฉ ุงู„ูุฑุน ุงู„ุฌุฏูŠุฏ ู„ู‡ุฐุง ุงู„ุฅูŠุฏุงุน -from_comment = (ุชุนู„ูŠู‚) -no_eol.text = ู„ุง EOL -no_eol.tooltip = ู‡ุฐุง ุงู„ู…ู„ู ู„ุง ูŠุญุชูˆูŠ ุนู„ู‰ ู†ู‡ุงูŠุฉ ู„ุฎุท ุงู„ุดุฎุตูŠุฉ. -stored_lfs = ู…ุฎุฒู† ู…ุน Git LFS -commit.contained_in = ู‡ุฐุง ุงู„ุฅูŠุฏุงุน ู…ูˆุฌูˆุฏ ููŠ: -file_view_rendered = ุนุฑุถ ุงู„ู…ูุฎุฑุฌ ุงู„ู†ู‡ุงุฆูŠ -n_branch_few = %s ูุฑูˆุน -n_tag_one = %s ุนู„ุงู…ุฉ -n_tag_few = โ€ช%s ุนู„ุงู…ุงุช -n_release_few = %s ุฅุตุฏุงุฑุงุช -file.title = %s ุนู†ุฏ %s -vendored = ู…ุถู…ู† -file_follow = ู…ุชุงุจุนุฉ ุงู„ุฑูˆุงุจุท ุงู„ุฑู…ุฒูŠุฉ [mail] admin.new_user.text = ู…ู† ูุถู„ูƒ ุงุถุบุท ู‡ู†ุง ู„ุฅุฏุงุฑุฉ ู‡ุฐุง ุงู„ู…ุณุชุฎุฏู… ู…ู† ู„ูˆุญุฉ ุงู„ุฅุฏุงุฑุฉ. admin.new_user.subject = ู…ุณุชุฎุฏู… ุฌุฏูŠุฏ: %s ุณุฌู„ ุญุงู„ุงู‹ admin.new_user.user_info = ู…ุนู„ูˆู…ุงุช ุงู„ู…ุณุชุฎุฏู… activate_account.text_1 = ุฃู‡ู„ุง ูŠุง %[1]sุŒ ุดูƒุฑุง ู„ูƒ ู„ู„ุชุณุฌูŠู„ ููŠ %[2]s! -register_notify = ุฃู‡ู„ุง ุจูƒ ููŠ %s +register_notify = ุฃู‡ู„ุง ุจูƒ ููŠ ููˆุฑุฌูŠูˆ activate_account = ู†ุฑุฌูˆ ุชูุนูŠู„ ุญุณุงุจูƒ +activate_account.title = ูŠุง %sุŒ ู†ุฑุฌูˆ ู…ู†ูƒ ุชูุนูŠู„ ุญุณุงุจูƒ issue.x_mentioned_you = ุฐูƒุฑูƒ @%s: +register_notify.title = ู…ุฑุญุจุง ุจูƒ ูŠุง %[1]s ููŠ %[2]s issue.in_tree_path = ููŠ %s: -register_notify.text_3 = ุฅุฐุง ู‚ุงู… ุดุฎุต ุขุฎุฑ ุจุฅู†ุดุงุก ู‡ุฐุง ุงู„ุญุณุงุจ ู„ูƒุŒ ูุณุชุญุชุงุฌ ุฃูˆู„ุงู‹ ุฅู„ู‰ ุถุจุท ูƒู„ู…ุฉ ู…ุฑูˆุฑูƒ. -register_notify.text_2 = ูŠู…ูƒู†ูƒ ุงู„ุขู† ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ ุจุงุณู… ุงู„ู…ุณุชุฎุฏู…: %s +register_notify.text_3 = ุฅุฐุง ุฃูู†ุดุฆ ู‡ุฐุง ุงู„ุญุณุงุจ ู„ูƒุŒ ูู†ุฑุฌูˆ ุฃูˆู„ุง ุถุจุท ูƒู„ู…ุฉ ู…ุฑูˆุฑูƒ. +register_notify.text_2 = ูŠู…ูƒู†ูƒ ุงู„ุขู† ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุจุงุณู… ุงู„ู…ุณุชุฎุฏู…: %s. +reset_password.title = ูŠุง %sุŒ ู„ู‚ุฏ ุทู„ุจุช ุงุณุชุนุงุฏุฉ ุญุณุงุจูƒ repo.transfer.to_you = ุฃู†ุช reset_password = ุงุณุชุนุงุฏุฉ ุญุณุงุจูƒ -repo.collaborator.added.subject = %s ุฃุถุงููƒ ุฅู„ู‰ %s ูƒู…ุดุชุฑููƒ +repo.collaborator.added.subject = %s ุฃุถุงููƒ ุฅู„ู‰ %s team_invite.subject = ู„ู‚ุฏ ุฏุนุงูƒ %[1]s ู„ู„ุงู†ุถู…ุงู… ุฅู„ู‰ ู…ู†ุธู…ุฉ %[2]s team_invite.text_2 = ู†ุฑุฌูˆ ุงู„ุถุบุท ุนู„ู‰ ุงู„ุฑุงุจุท ุงู„ุชุงู„ูŠ ู„ู„ุงู†ุถู…ุงู… ุฅู„ู‰ ุงู„ูุฑูŠู‚: team_invite.text_1 = ู„ู‚ุฏ ุฏุนุงูƒ %[1]s ู„ู„ุงู†ุถู…ุงู… ุฅู„ู‰ ูุฑูŠู‚ %[2]s ููŠ ู…ู†ุธู…ุฉ %[3]s. -repo.collaborator.added.text = ู„ู‚ุฏ ุฌูุนู„ุช ู…ุดุชุฑููƒุง ุฅู„ู‰ ู…ุณุชูˆุฏุน: +repo.collaborator.added.text = ู„ู‚ุฏ ุฌูุนู„ุช ู…ุดุชุฑููƒุง ููŠ ู…ุณุชูˆุฏุน: reply = ุฃูˆ ุฑุฏ ุนู„ู‰ ู‡ุฐุง ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ู…ุจุงุดุฑุฉ -link_not_working_do_paste = ู‡ู„ ุงู„ุฑุงุจุท ู„ุง ูŠุนู…ู„ุŸ ุฌุฑู‘ุจ ู†ุณุฎู‡ ูˆู„ุตู‚ู‡ ููŠ ุดุฑูŠุท ุนู†ูˆุงู† ุงู„ู…ุชุตูุญ ู„ุฏูŠูƒ. +link_not_working_do_paste = ู„ุง ุชุนู…ู„ุŸ ุญุงูˆู„ ุฃู† ุงู„ู†ุณุฎ ูˆุงู„ู„ุตู‚ ุฅู„ู‰ ู…ุชุตูุญูƒ. register_success = ู†ุฌุญ ุงู„ุชุณุฌูŠู„ view_it_on = ุงุนุฑุถู‡ ุนู„ู‰ %s activate_account.text_2 = ูŠุฑุฌู‰ ุงู„ู†ู‚ุฑ ุนู„ู‰ ุงู„ุฑุงุจุท ุงู„ุชุงู„ูŠ ู„ุชูุนูŠู„ ุญุณุงุจูƒ ููŠ %s: @@ -1646,6 +1387,7 @@ activate_email.text = ูŠุฑุฌู‰ ุงู„ุถุบุท ุนู„ู‰ ุงู„ุฑุงุจุท ุงู„ุขุชูŠ ู„ุชุฃ reset_password.text = ูŠุฑุฌู‰ ุงู„ุถุบุท ุนู„ู‰ ุงู„ุฑุงุจุท ุงู„ุขุชูŠ ู„ุงุณุชุนุงุฏุฉ ุงู„ุญุณุงุจ ููŠ ุฎู„ุงู„ %s: release.downloads = ุงู„ุชู†ุฒูŠู„ุงุช: activate_email = ุฃูƒุฏ ุนู†ูˆุงู† ุจุฑูŠุฏูƒ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ +activate_email.title = %sุŒ ูŠุฑุฌู‰ ุชุฃูƒูŠุฏ ุนู†ูˆุงู† ุจุฑูŠุฏูƒ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ release.note = ู…ู„ุงุญุธุฉ: issue.action.close = @%[1]s ุฃุบู„ู‚ #%[2]d. issue.action.merge = @%[1]s ุฏู…ุฌ #%[2]d ู…ุน %[3]s. @@ -1664,32 +1406,35 @@ issue.action.new = @%[1]s ุงู†ุดุฃ #%[2]d. issue_assigned.issue = @%[1]s ุนูŠู‘ู†ูƒ ุฅู„ู‰ ู…ุณุฃู„ุฉ %[2]s ููŠ ู…ุณุชูˆุฏุน %[3]s. issue.action.push_n = @%[1]s ุฏูุน %[3]d ุฅูŠุฏุงุนุงุช ุฅู„ู‰ %[2]s release.new.subject = ุฃูุตุฏุฑ %s ููŠ %s -repo.transfer.subject_to_you = %s ูŠุฑูŠุฏ ู†ู‚ู„ ู…ู„ูƒูŠุฉ ู…ุณุชูˆุฏุน "%s" ุฅู„ูŠูƒ -repo.transfer.subject_to = %s ูŠุฑูŠุฏ ู†ู‚ู„ ู…ู„ูƒูŠุฉ ู…ุณุชูˆุฏุน "%s" ุฅู„ู‰ %s +repo.transfer.subject_to_you = %s ูŠูˆุฏ ู†ู‚ู„ ู…ู„ูƒูŠุฉ "%s" ุฅู„ูŠูƒ +repo.transfer.subject_to = %s ูŠูˆุฏ ู†ู‚ู„ ู…ู„ูƒูŠุฉ "%s" ุฅู„ู‰ %s issue.action.ready_for_review = @%[1]s ุนู„ู‘ู… ู‡ุฐุง ุงู„ุทู„ุจ ู„ู„ุณุญุจ ูƒุฌุงู‡ุฒ ู„ู„ู…ุฑุงุฌุนุฉ. issue_assigned.pull = @%[1]s ุนูŠู‘ู†ูƒ ุฅู„ู‰ ุทู„ุจ ุณุญุจ %[2]s ููŠ ู…ุณุชูˆุฏุน %[3]s. issue.action.review_dismissed = @%[1]s ุฃุณุชุจุนุฏ ุขุฎุฑ ู…ุฑุงุฌุนุฉ ู…ู† %[2]s ู„ู‡ุฐุง ุงู„ุทู„ุจ ู„ู„ุณุญุจ. + password_change.subject = ุชู… ุชุบูŠูŠุฑ ูƒู„ู…ุฉ ู…ุฑูˆุฑูƒ +password_change.text_1 = ุชู… ุชุบูŠูŠุฑ ูƒู„ู…ุฉ ู…ุฑูˆุฑ ุญุณุงุจูƒ ู„ู„ุชูˆ. +primary_mail_change.subject = ุชู… ุชุบูŠูŠุฑ ุงู„ุจุฑูŠุฏ ุงู„ุฃุณุงุณูŠ ุงู„ุฎุงุต ุจูƒ +primary_mail_change.text_1 = ุชู… ุชุบูŠูŠุฑ ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ุงู„ุฃุณุงุณูŠ ู„ุญุณุงุจูƒ ุฅู„ู‰ %[1]s. ู‡ุฐุง ูŠุนู†ูŠ ุฃู† ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ู‡ุฐุง ู„ู† ูŠุชู„ู‚ู‰ ุฅุดุนุงุฑุงุช ุงู„ุจุฑูŠุฏ ู„ุญุณุงุจูƒ ุจุนุฏ ุงู„ุขู†. totp_disabled.subject = ุชู… ุชุนุทูŠู„ TOTP totp_disabled.text_1 = ุชู… ุชุนุทูŠู„ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ู„ู…ุฑุฉ ูˆุงุญุฏุฉ ุงู„ู…ุณุชู†ุฏุฉ ุฅู„ู‰ ุงู„ูˆู‚ุช (TOTP) ุนู„ู‰ ุญุณุงุจูƒ ู„ู„ุชูˆ. -totp_enrolled.text_1.has_webauthn = ู„ู‚ุฏ ู‚ู…ุช ู„ู„ุชูˆ ุจุชู…ูƒูŠู† TOTP ู„ุญุณุงุจูƒ. ู‡ุฐุง ูŠุนู†ูŠ ุฃู†ู‡ ุจุงู„ู†ุณุจุฉ ู„ุฌู…ูŠุน ุนู…ู„ูŠุงุช ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุงู„ู…ุณุชู‚ุจู„ูŠุฉ ุฅู„ู‰ ุญุณุงุจูƒุŒ ูŠู…ูƒู†ูƒ ุงุณุชุฎุฏุงู… TOTP ูƒุทุฑูŠู‚ุฉ ู„ู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ ุŒ ุฃูˆ ุงุณุชุฎุฏุงู… ุฃูŠ ู…ู† ู…ูุงุชูŠุญ ุงู„ุฃู…ุงู† ุงู„ุฎุงุตุฉ ุจูƒ. -totp_enrolled.subject = ู„ู‚ุฏ ู‚ู…ุช ุจุชุดูŠุท TOTP ูƒุทุฑูŠู‚ุฉ 2FA +totp_disabled.no_2fa = ู„ู… ุชุนุฏ ู‡ู†ุงูƒ ุทุฑู‚ ุฃูุฎุฑู‰ ู„ู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ (2FA) ู‚ูŠุฏ ุงู„ุชู‡ูŠุฆุฉ ุนุฏ ุงู„ุขู† ุŒ ุฃูŠ ุฃู†ู‡ ู„ู… ูŠุนุฏ ู…ู† ุงู„ุถุฑูˆุฑูŠ ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ ุจุงุณุชุฎุฏุงู… ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ (2FA). removed_security_key.subject = ุชู…ุช ุฅุฒุงู„ุฉ ู…ูุชุงุญ ุงู„ุฃู…ุงู† removed_security_key.text_1 = ุชู… ุฅุฒุงู„ุฉ ู…ูุชุงุญ ุงู„ุฃู…ุงู† โ€%[1] sโ€œ ู„ู„ุชูˆ ู…ู† ุญุณุงุจูƒ. -account_security_caution.text_1 = ุฅุฐุง ูƒุงู† ู‡ุฐุง ุฃู†ุชุŒ ููŠู…ูƒู†ูƒ ุชุฌุงู‡ู„ ู‡ุฐุง ุงู„ุจุฑูŠุฏ ุจุฃู…ุงู†. -totp_disabled.no_2fa = ู„ู… ุชุนุฏ ู‡ู†ุงูƒ ุทุฑู‚ ุฃูุฎุฑู‰ ู„ู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ (2FA) ู‚ูŠุฏ ุงู„ุชู‡ูŠุฆุฉ ุนุฏ ุงู„ุขู† ุŒ ุฃูŠ ุฃู†ู‡ ู„ู… ูŠุนุฏ ู…ู† ุงู„ุถุฑูˆุฑูŠ ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ ุจุงุณุชุฎุฏุงู… ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ (2FA). removed_security_key.no_2fa = ู„ู… ุชุนุฏ ู‡ู†ุงูƒ ุทุฑู‚ ุฃุฎุฑู‰ ู„ู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ (2FA) ู‚ูŠุฏ ุงู„ุชู‡ูŠุฆุฉ ุจุนุฏ ุงู„ุขู†ุŒ ุฃูŠ ู„ู… ูŠุนุฏ ู…ู† ุงู„ุถุฑูˆุฑูŠ ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุฅู„ู‰ ุญุณุงุจูƒ ุจุงุณุชุฎุฏุงู… ุงู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ (2FA). -primary_mail_change.subject = ุชู… ุชุบูŠูŠุฑ ุงู„ุจุฑูŠุฏ ุงู„ุฃุณุงุณูŠ ุงู„ุฎุงุต ุจูƒ -password_change.text_1 = ุชู… ุชุบูŠูŠุฑ ูƒู„ู…ุฉ ู…ุฑูˆุฑ ุญุณุงุจูƒ ู„ู„ุชูˆ. -primary_mail_change.text_1 = ุชู… ุชุบูŠูŠุฑ ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ุงู„ุฃุณุงุณูŠ ู„ุญุณุงุจูƒ ุฅู„ู‰ %[1]s. ู‡ุฐุง ูŠุนู†ูŠ ุฃู† ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ู‡ุฐุง ู„ู† ูŠุชู„ู‚ู‰ ุฅุดุนุงุฑุงุช ุงู„ุจุฑูŠุฏ ู„ุญุณุงุจูƒ ุจุนุฏ ุงู„ุขู†. +account_security_caution.text_1 = ุฅุฐุง ูƒุงู† ู‡ุฐุง ุฃู†ุชุŒ ููŠู…ูƒู†ูƒ ุชุฌุงู‡ู„ ู‡ุฐุง ุงู„ุจุฑูŠุฏ ุจุฃู…ุงู†. account_security_caution.text_2 = ุฅุฐุง ู„ู… ุชูƒู† ุฃู†ุชุŒ ูู‡ุฐุง ูŠุนู†ูŠ ุฃู† ุญุณุงุจูƒ ู…ุฎุชุฑู‚. ูŠุฑุฌู‰ ุงู„ุงุชุตุงู„ ุจู…ุณุคูˆู„ูŠ ู‡ุฐุง ุงู„ู…ูˆู‚ุน. +totp_enrolled.subject = ู„ู‚ุฏ ู‚ู…ุช ุจุชุดูŠุท TOTP ูƒุทุฑูŠู‚ุฉ 2FA totp_enrolled.text_1.no_webauthn = ู„ู‚ุฏ ู‚ู…ุช ู„ู„ุชูˆ ุจุชู…ูƒูŠู† TOTP ู„ุญุณุงุจูƒ. ู‡ุฐุง ูŠุนู†ูŠ ุฃู†ู‡ ุจุงู„ู†ุณุจุฉ ู„ุฌู…ูŠุน ุนู…ู„ูŠุงุช ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุงู„ู…ุณุชู‚ุจู„ูŠุฉ ุฅู„ู‰ ุญุณุงุจูƒุŒ ูŠุฌุจ ุนู„ูŠูƒ ุงุณุชุฎุฏุงู… TOTP ูƒุทุฑูŠู‚ุฉ ู„ู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ. +totp_enrolled.text_1.has_webauthn = ู„ู‚ุฏ ู‚ู…ุช ู„ู„ุชูˆ ุจุชู…ูƒูŠู† TOTP ู„ุญุณุงุจูƒ. ู‡ุฐุง ูŠุนู†ูŠ ุฃู†ู‡ ุจุงู„ู†ุณุจุฉ ู„ุฌู…ูŠุน ุนู…ู„ูŠุงุช ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ุงู„ู…ุณุชู‚ุจู„ูŠุฉ ุฅู„ู‰ ุญุณุงุจูƒุŒ ูŠู…ูƒู†ูƒ ุงุณุชุฎุฏุงู… TOTP ูƒุทุฑูŠู‚ุฉ ู„ู„ู…ุตุงุฏู‚ุฉ ุงู„ุซู†ุงุฆูŠุฉ ุŒ ุฃูˆ ุงุณุชุฎุฏุงู… ุฃูŠ ู…ู† ู…ูุงุชูŠุญ ุงู„ุฃู…ุงู† ุงู„ุฎุงุตุฉ ุจูƒ. [error] not_found = ุชุนุฐุฑ ุงู„ุนุซูˆุฑ ุนู„ู‰ ุงู„ู‡ุฏู. report_message = ุฅู† ูƒู†ุช ู…ุชูŠู‚ู‘ูู†ู‹ุง ุฃู† ู‡ุฐู‡ ุนู„ุฉ ููŠ ููˆุฑุฌูŠูˆุŒ ุฑุฌุงุกู‹ ุงุจุญุซ ููŠ ูƒูˆุฏุจูŠุฑุฌ ุฃูˆ ุงูุชุญ ู…ุณุฃู„ู‡ ุฌุฏูŠุฏุฉ ุฅุฐุง ู„ุฒู… ุงู„ุฃู…ุฑ. network_error = ุฎุทุฃ ููŠ ุงู„ุดุจูƒุฉ +invalid_csrf = ุทู„ุจ ุณูŠุฆ: ุฑู…ุฒ CSRF ุบูŠุฑ ุตุงู„ุญ occurred = ุญุฏุซ ุฎุทุฃ +missing_csrf = ุทู„ุจ ุณูŠุฆ: ู„ุง ูŠูˆุฌุฏ ุฑู…ุฒ CSRF server_internal = ุฎุทุฃ ุฏุงุฎู„ูŠ ููŠ ุงู„ุฎุงุฏู… [startpage] @@ -1730,19 +1475,21 @@ overview = ู†ุธุฑุฉ ุนุงู…ุฉ watched = ุงู„ู…ุณุชูˆุฏุนุงุช ุงู„ู…ุดุงู‡ุฏุฉ disabled_public_activity = ู‡ุฐุง ุงู„ู…ุณุชุฎุฏู… ุนุทู‘ู„ ุงู„ุธู‡ูˆุฑ ุงู„ุนุงู… ู„ู„ู†ุดุงุท. show_on_map = ุงุนุฑุถ ู‡ุฐุง ุงู„ู…ูƒุงู† ุนู„ู‰ ุงู„ุฎุฑูŠุทุฉ +email_visibility.private = ุนู†ูˆุงู† ุจุฑูŠุฏูƒ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ุธุงู‡ุฑ ู„ูƒ ูˆู„ู„ู…ุฏูŠุฑูŠู† ูู‚ุท starred = ุงู„ู…ุณุชูˆุฏุนุงุช ุงู„ู…ู…ูŠู‘ุฒุฉ ุจู†ุฌู…ุฉ form.name_chars_not_allowed = ุงุณู… ุงู„ู…ุณุชุฎุฏู… "%s" ูŠุญุชูˆูŠ ุนู„ู‰ ุฑู…ูˆุฒ ุบูŠุฑ ุตุงู„ุญุฉ. form.name_pattern_not_allowed = ุงู„ู†ู…ุท "s%" ุบูŠุฑ ู…ุณู…ูˆุญ ุจู‡ ููŠ ุฅุณู… ุงู„ู…ุณุชุฎุฏู…. + followers.title.one = ู…ุชุงุจูุน -public_activity.visibility_hint.admin_private = ู‡ุฐุง ุงู„ู†ุดุงุท ู…ุฑุฆูŠ ู„ูƒ ู„ุฃู†ูƒ ู…ุณุคูˆู„ุŒ ูˆู„ูƒู† ุงู„ู…ุณุชุฎุฏู… ูŠุฑูŠุฏ ุฃู† ูŠุธู„ ุฎุงุตุงู‹. -public_activity.visibility_hint.self_private = ู†ุดุงุทูƒ ู…ุฑุฆูŠ ู„ูƒ ูˆู„ุณูุนุงุฉ ุงู„ู…ุซูŠู„ ูู‚ุท. ุชุนุฏูŠู„ ุงู„ุฅุนุฏุงุฏุงุช. -followers_one = %d ู…ุชุงุจูุน -following.title.one = ู…ุชุงุจุนุฉ followers.title.few = ู…ุชุงุจุนูŠู† -following_one = %d ูŠูุชุงุจุน +following.title.one = ู…ุชุงุจุนุฉ following.title.few = ู…ุชุงุจุนุฉ +followers_one = %d ู…ุชุงุจูุน +following_one = %d ูŠูุชุงุจุน public_activity.visibility_hint.self_public = ู†ุดุงุทูƒ ู…ุฑุฆูŠ ู„ู„ุฌู…ูŠุนุŒ ุจุงุณุชุซู†ุงุก ุงู„ุชูุงุนู„ุงุช ููŠ ุงู„ู…ุณุงุญุงุช ุงู„ุฎุงุตุฉ. ุงุถุจุท ุงู„ุฅุนุฏุงุฏุงุช. public_activity.visibility_hint.admin_public = ู‡ุฐุง ุงู„ู†ุดุงุท ู…ุฑุฆูŠ ู„ู„ุฌู…ูŠุนุŒ ูˆู„ูƒู† ุจุตูุชูƒ ู…ุณุคูˆู„ุงู‹ ูŠู…ูƒู†ูƒ ุฃูŠุถู‹ุง ุฑุคูŠุฉ ุงู„ุชูุงุนู„ุงุช ููŠ ุงู„ู…ุณุงุญุงุช ุงู„ุฎุงุตุฉ. +public_activity.visibility_hint.self_private = ู†ุดุงุทูƒ ู…ุฑุฆูŠ ู„ูƒ ูˆู„ุณูุนุงุฉ ุงู„ู…ุซูŠู„ ูู‚ุท. ุชุนุฏูŠู„ ุงู„ุฅุนุฏุงุฏุงุช. +public_activity.visibility_hint.admin_private = ู‡ุฐุง ุงู„ู†ุดุงุท ู…ุฑุฆูŠ ู„ูƒ ู„ุฃู†ูƒ ู…ุณุคูˆู„ุŒ ูˆู„ูƒู† ุงู„ู…ุณุชุฎุฏู… ูŠุฑูŠุฏ ุฃู† ูŠุธู„ ุฎุงุตุงู‹. public_activity.visibility_hint.self_private_profile = ู†ุดุงุทูƒ ู…ุฑุฆูŠ ู„ูƒ ูˆู„ุณูุนุงุฉ ุงู„ู…ุซูŠู„ ูู‚ุท ู„ุฃู† ู…ู„ููƒ ุงู„ุดุฎุตูŠ ุฎุงุต. ุชุนุฏูŠู„ ุงู„ุฅุนุฏุงุฏุงุช. [auth] @@ -1754,21 +1501,26 @@ disable_register_mail = ุชู… ุชุนุทูŠู„ ุชุฃูƒูŠุฏ ุงู„ุจุฑูŠุฏ ู„ู„ุชุณุฌูŠู„. sign_up_successful = ุฃูŒู†ุดุฆ ุงู„ุญุณุงุจ ุจู†ุฌุงุญ. ู…ุฑุญุจุงู‹! forgot_password = ู†ุณูŠุช ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑุŸ allow_password_change = ุฃู„ุฒู… ุงู„ู…ุณุชุฎุฏู… ุจุชุบูŠูŠุฑ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ (ูŠูู†ุตุญ ุจู‡) +sign_up_now = ุชุญุชุงุฌ ุฅู„ู‰ ุญุณุงุจุŸ ุณุฌู„ ุงู„ุขู†. forgot_password_title = ู†ุณูŠุช ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ account_activated = ุชู… ุชูุนูŠู„ ุงู„ุญุณุงุจ +social_register_helper_msg = ู‡ู„ ู„ุฏูŠูƒ ุญุณุงุจ ุจุงู„ูุนู„ุŸ ุงุฑุจุทู‡ ุงู„ุขู†! create_new_account = ุณุฌู„ ุญุณุงุจ disable_register_prompt = ุงู„ุชุณุฌูŠู„ ู…ุบู„ู‚ ุญุงู„ูŠุงู‹. ูŠุฑุฌู‰ ุงู„ุงุชุตุงู„ ุจุงู„ู…ุฏูŠุฑ. active_your_account = ูุนู‘ู„ ุญุณุงุจูƒ +register_helper_msg = ู‡ู„ ู„ุฏูŠูƒ ุญุณุงุจ ุจุงู„ูุนู„ุŸ ุณุฌู„ ุงู„ุฏุฎูˆู„! manual_activation_only = ุชูˆุงุตู„ ู…ุน ู…ุฏูŠุฑ ู…ูˆู‚ุนูƒ ู„ุฅูƒู…ุงู„ ุงู„ุชูุนูŠู„. must_change_password = ุญุฏู‘ุซ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ุงู„ุฎุงุตุฉ ุจูƒ send_reset_mail = ุฃุฑุณู„ ุจุฑูŠุฏ ุงู„ุงุณุชุนุงุฏุฉ resend_mail = ุงุถุบุท ู‡ู†ุง ู„ุฅุนุงุฏุฉ ุฅุฑุณุงู„ุฉ ุฑุณุงู„ุฉ ุชูุนูŠู„ ุญุณุงุจูƒ has_unconfirmed_mail = ุฃู‡ู„ุง ูŠุง %sุŒ ู„ุฏูŠูƒ ุนู†ูˆุงู† ุจุฑูŠุฏ ุฅู„ูƒุชุฑูˆู†ูŠ ุบูŠุฑ ู…ุคูƒู‘ูŽุฏ (%s). ุฅู† ู„ู… ุชุณุชู„ู… ุฑุณุงู„ุฉ ุชุฃูƒูŠุฏ ุฃูˆ ุชุฑูŠุฏ ุฅุฑุณุงู„ ูˆุงุญุฏุฉ ุฌุฏูŠุฏุฉุŒ ูู†ุฑุฌูˆ ุงู„ุถุบุท ุนู„ู‰ ุงู„ุฒุฑ ุงู„ุฐูŠ ุจุงู„ุฃุณูู„. +email_not_associate = ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ู‡ุฐุง ุบูŠุฑ ู…ุฑุชุจุท ุจุฃูŠ ุญุณุงุจ. reset_password = ุงุณุชุนุงุฏุฉ ุงู„ุญุณุงุจ oauth_signin_tab = ุฃุฑุจุท ุจุญุณุงุจ ู…ูˆุฌูˆุฏ invalid_password = ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ุงู„ุฎุงุตุฉ ุจูƒ ู„ุง ุชุทุงุจู‚ ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ุงู„ุชูŠ ุงุณุชุฎุฏู…ุช ู„ุชุณุฌูŠู„ ุงู„ุญุณุงุจ. oauth_signin_title = ุณุฌู‘ู„ ุงู„ุฏุฎูˆู„ ู„ุชุฃุฐู† ู„ู„ุญุณุงุจ ุงู„ู…ุฑุจูˆุท reset_password_helper = ุฅุนุงุฏุฉ ุงู„ุญุณุงุจ +tab_openid = ุชุณุฌูŠู„ ุฏุฎูˆู„ ุจู€OpenID openid_connect_submit = ุงุชุตู„ oauth_signup_tab = ุณุฌู„ ุญุณุงุจ ุฌุฏูŠุฏ oauth.signin.error.temporarily_unavailable = ูุดู„ ุทู„ุจ ุงู„ุฅุฐู† ู„ุฃู† ุฎุงุฏู… ุงู„ุชูˆุซูŠู‚ ุบูŠุฑ ู…ุชุงุญ ู…ุคู‚ุชุง. ุญุงูˆู„ ู…ุฑุฉ ุฃุฎุฑู‰ ู„ุงุญู‚ุงู‹. @@ -1799,26 +1551,29 @@ authorize_application_description = ุฅุฐุง ู…ู†ุญุช ุญู‚ ุงู„ูˆุตูˆู„ุŒ ูุณูŠูƒ authorize_application_created_by = ุฃูู†ุดุฆ ู‡ุฐุง ุงู„ุชุทุจูŠู‚ ุจูˆุงุณุทุฉ %s. email_domain_blacklisted = ู„ุง ูŠู…ูƒู†ูƒ ุงู„ุชุณุฌูŠู„ ุจุงุณุชุฎุฏุงู… ุนู†ูˆุงู† ุจุฑูŠุฏูƒ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ. authorize_title = ู‡ู„ ุชุฑูŠุฏ ุฃู† ุชุฃุฐู† ู„ู€ "%s" ุจุงู„ูˆุตูˆู„ ุฅู„ู‰ ุญุณุงุจูƒุŸ -prohibit_login = ู‡ุฐุง ุงู„ุญุณุงุจ ู…ุนู„ู‚ -prohibit_login_desc = ุชู… ุชุนู„ูŠู‚ ุญุณุงุจูƒ ู…ู† ุงู„ุชูุงุนู„ ู…ุน ู‡ุฐู‡ ุงู„ู†ุณุฎุฉ. ุชูˆุงุตู„ ู…ุน ู…ุณุคูˆู„ ุงู„ู†ุณุฎุฉ ู„ุงุณุชุนุงุฏุฉ ุงู„ูˆุตูˆู„. +prohibit_login = ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ู…ู…ู†ูˆุน +prohibit_login_desc = ุญุณุงุจูƒ ู…ู…ู†ูˆุน ู…ู† ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ุŒ ูŠุฑุฌู‰ ุงู„ุชูˆุงุตู„ ู…ุน ู…ุฏูŠุฑ ุงู„ู…ูˆู‚ุน. disable_forgot_password_mail_admin = ุงุณุชุฑุฏุงุฏ ุงู„ุญุณุงุจ ู…ุชุงุญ ูู‚ุท ุนู†ุฏ ุฅุนุฏุงุฏ ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ. ูŠูุฑุฌู‰ ุฅุนุฏุงุฏ ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ู„ุชูุนูŠู„ ุงุณุชุฑุฏุงุฏ ุงู„ุญุณุงุจ. password_pwned_err = ุชุนุฐุฑ ุงู„ูˆุตูˆู„ ุฅู„ู‰ HaveIBeenPwned password_pwned = ุงู„ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ุงู„ู…ูุฎุชุงุฑุฉ ู‡ูŠ ุนู„ู‰ ู‚ุงุฆู…ุฉ ูƒู„ู…ุงุช ู…ุฑูˆุฑ ู…ุณุฑูˆู‚ุฉ ุชู… ูƒุดูู‡ุง ููŠ ุชุณุฑูŠุจุงุช ุนุงู…ุฉ ู„ู„ุจูŠุงู†ุงุช. ูŠูุฑุฌู‰ ุงู„ู…ุญุงูˆู„ุฉ ู…ุฑุฉ ุฃุฎุฑู‰ ุจูƒู„ู…ุฉ ู…ุฑูˆุฑ ุฃุฎุฑู‰ุŒ ูˆุถุน ููŠ ุงุนุชุจุงุฑูƒ ุชุบูŠูŠุฑ ุชู„ูƒ ุงู„ูƒู„ู…ุฉ ููŠ ุงู„ุฃู…ุงูƒู† ุงู„ุฃุฎุฑู‰. authorization_failed = ูุดู„ ุงู„ุฅุฐู† authorize_redirect_notice = ุณุชุชู… ุฅุนุงุฏุฉ ุชูˆุฌูŠู‡ูƒ ุฅู„ู‰ %s ุฅุฐุง ุฃุฐู†ุช ู„ู„ุชุทุจูŠู‚. authorize_application = ุงุฆุฐู† ู„ู„ุชุทุจูŠู‚ +sspi_auth_failed = ูุดู„ุช ุนู…ู„ูŠุฉ ุงุณุชูŠุซุงู‚ SSPI openid_connect_desc = ู…ุณุงุฑ ุงู„ู€OpenID ุงู„ู…ุฎุชุงุฑ ู…ุฌู‡ูˆู„. ุงุฑุจุทู‡ ู…ุน ุญุณุงุจ ุฌุฏูŠุฏ ู‡ู†ุง. openid_signin_desc = ุฃุฏุฎู„ ู…ุณุงุฑ ุงู„ู€OpenID ุงู„ุฎุงุต ุจูƒ. ู…ุซู„ุงู‹: alice.openid.example.org ุฃูˆ https://openid.example.org/alice. openid_register_desc = ู…ุณุงุฑ ุงู„ู€OpenID ุงู„ู…ุฎุชุงุฑ ู…ุฌู‡ูˆู„. ุงุฑุจุทู‡ ู…ุน ุญุณุงุจ ุฌุฏูŠุฏ ู‡ู†ุง. remember_me = ุชุฐูƒุฑ ู‡ุฐุง ุงู„ุฌู‡ุงุฒ +remember_me.compromised = ุฑู…ุฒ ุงู„ุงุญุชูุงุธ ุจุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ ู„ู… ูŠุนุฏ ุตุงู„ุญุงุŒ ู…ู…ุง ู‚ุฏ ูŠุนู†ูŠ ุงุฎุชุฑุงู‚ ุงู„ุญุณุงุจ. ู†ุฑุฌูˆ ู…ุฑุงุฌุนุฉ ุญุณุงุจูƒ ู„ุฑุคูŠุฉ ุฃูŠ ู†ุดุงุท ุบูŠุฑ ู…ุฃู„ูˆู. authorization_failed_desc = ูุดู„ ุงู„ุชููˆูŠุถ ู„ุฃู†ู†ุง ุงูƒุชุดูู†ุง ุทู„ุจู‹ุง ุบูŠุฑ ุตุงู„ุญ. ูŠุฑุฌู‰ ุงู„ุงุชุตุงู„ ุจู…ุดุฑู ุงู„ุชุทุจูŠู‚ ุงู„ุฐูŠ ุญุงูˆู„ุช ุชุฑุฎูŠุตู‡. -sign_in_openid = ุงู„ู…ุชุงุจุนุฉ ุจุงุณุชุฎุฏุงู… OpenID + hint_login = ู„ุฏูŠูƒ ุญุณุงุจ ุจุงู„ูุนู„ุŸ ุณุฌู‘ู„ ุงู„ุฏุฎูˆู„ ุงู„ุขู†! hint_register = ูŠู„ุฒู…ูƒ ุญุณุงุจ ุŸ ุณุฌู‘ูู„ ุงู„ุขู†. sign_up_button = ุณุฌู‘ูู„ ุงู„ุขู†. -back_to_sign_in = ุงู„ุนูˆุฏุฉ ุฅู„ู‰ ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ -use_onetime_code = ุงุณุชุฎุฏู… ุฑู…ุฒู‹ุง ู„ู…ุฑุฉ ูˆุงุญุฏุฉ unauthorized_credentials = ุจูŠุงู†ุงุช ุงู„ุงุนุชู…ุงุฏ ุบูŠุฑ ุตุญูŠุญุฉ ุฃูˆ ุงู†ุชู‡ุช ุตู„ุงุญูŠุชู‡ุง. ุฃุนุฏ ู…ุญุงูˆู„ุฉ ุชู†ููŠุฐ ุงู„ุฃู…ุฑ ุฃูˆ ุฑุงุฌุน %s ู„ู…ุฒูŠุฏ ู…ู† ุงู„ู…ุนู„ูˆู…ุงุช +use_onetime_code = ุงุณุชุฎุฏู… ุฑู…ุฒู‹ุง ู„ู…ุฑุฉ ูˆุงุญุฏุฉ +back_to_sign_in = ุงู„ุนูˆุฏุฉ ุฅู„ู‰ ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„ +sign_in_openid = ุงู„ู…ุชุงุจุนุฉ ุจุงุณุชุฎุฏุงู… OpenID [packages] rpm.repository.multiple_groups = ู‡ุฐู‡ ุงู„ุญุฒู…ุฉ ู…ุชูˆูุฑุฉ ููŠ ู…ุฌู…ูˆุนุงุช ู…ุชุนุฏุฏุฉ. @@ -1862,6 +1617,7 @@ less = ุฃู‚ู„ number_of_contributions_in_the_last_12_months = %s ู…ุณุงู‡ู… ููŠ ุขุฎุฑ 12 ุดู‡ุฑ contributions_zero = ุจู„ุง ู…ุณุงู‡ู…ุงุช more = ุฃูƒุซุฑ + contributions_format = {contributions} ู…ุณุงู‡ู…ุฉ ููŠ {day} {month} {year} contributions_one = ุงู„ู…ุณุงู‡ู…ุฉ contributions_few = ุงู„ู…ุณุงู‡ู…ุงุช @@ -1936,6 +1692,7 @@ packages.repository = ุงู„ู…ุณุชูˆุฏุน orgs.teams = ุงู„ููุฑู‚ packages.size = ุงู„ุญุฌู… users.max_repo_creation = ุงู„ุนุฏุฏ ุงู„ุฃู‚ุตู‰ ู„ู„ู…ุณุชูˆุฏุนุงุช +repos.forks = ุงู„ุงุดุชู‚ุงู‚ุงุช orgs.new_orga = ู…ู†ุธู…ุฉ ุฌุฏูŠุฏุฉ users.allow_import_local = ูŠุณุชุทูŠุน ุงุณุชูŠุฑุงุฏ ู…ุณุชูˆุฏุนุงุช ู…ุญู„ูŠุฉ repos.name = ุงู„ุงุณู… @@ -2028,6 +1785,7 @@ email_invalid = ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ุบูŠุฑ ุตุงู„ุญ. CommitSummary = ุฎู„ุงุตุฉ ุงู„ุฅูŠุฏุงุน team_not_exist = ุงู„ูุฑูŠู‚ ุบูŠุฑ ู…ูˆุฌูˆุฏ. TreeName = ู…ุณุงุฑ ุงู„ู…ู„ู +SSPIDefaultLanguage = ุงู„ู„ุบุฉ ุงู„ู…ุจุฏุฆูŠุฉ password_complexity = ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ู„ูŠุณุช ุจุงู„ุชุนู‚ูŠุฏ ุงู„ู…ุทู„ูˆุจ: password_not_match = ู„ุง ุชุชุทุงุจู‚ ูƒู„ู…ุชุง ุงู„ู…ุฑูˆุฑ. still_has_org = "ุญุณุงุจูƒ ุนุถูˆ ููŠ ู…ู†ุธู…ุฉ ุฃูˆ ุฃูƒุซุฑุ› ุบุงุฏุฑู‡ู… ุฃูˆู„ุง." @@ -2036,22 +1794,26 @@ repository_files_already_exist.delete = ุงู„ู…ู„ูุงุช ู…ูˆุฌูˆุฏุฉ ุจุงู„ูุนู„ repository_files_already_exist.adopt = ุงู„ู…ู„ูุงุช ู…ูˆุฌูˆุฏุฉ ุจุงู„ูุนู„ ู„ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน ูˆูŠู…ูƒู† ุงุนุชู…ุงุฏู‡ุง ูู‚ุท. repository_files_already_exist = ุงู„ู…ู„ูุงุช ู…ูˆุฌูˆุฏุฉ ุจุงู„ูุนู„ ู„ู‡ุฐุง ุงู„ู…ุณุชูˆุฏุน. ุงุชุตู„ ุจู…ุฏูŠุฑ ุงู„ู†ุธุงู…. TeamName = ุงุณู… ุงู„ูุฑูŠู‚ +username_has_not_been_changed = ู„ู… ูŠุชู… ุชุบูŠูŠุฑ ุงุณู… ุงู„ู…ุณุชุฎุฏู… username_change_not_local_user = ุงู„ู…ุณุชุฎุฏู…ูŠู† ุบูŠุฑ ุงู„ู…ุญู„ูŠูŠู† ุบูŠุฑ ู…ุณู…ูˆุญ ู„ู‡ู… ุจุชุบูŠูŠุฑ ุฃุณู…ุงุฆู‡ู…. captcha_incorrect = ุงู„ูƒุงุจุชุดุง ุฎุงุทุฆุฉ. AdminEmail = ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ู„ู„ู…ุฏูŠุฑ team_no_units_error = ุงุณู…ุญ ุจุงู„ูˆุตูˆู„ ุฅู„ู‰ ู‚ุณู… ูˆุงุญุฏ ุนู„ู‰ ุงู„ุฃู‚ู„ ููŠ ุงู„ู…ุณุชูˆุฏุนุงุช. must_use_public_key = ุงู„ู…ูุชุงุญ ุงู„ุฐูŠ ู‚ุฏู…ุชู‡ ู‡ูˆ ู…ูุชุงุญ ุฎุงุต. ู…ู† ูุถู„ูƒ ู„ุง ุชุฑูุน ู…ูุชุงุญูƒ ุงู„ุฎุงุต ููŠ ุฃูŠ ู…ูƒุงู†. ุงุณุชุฎุฏู… ู…ูุชุงุญูƒ ุงู„ุนุงู… ุจุฏู„ุงู‹ ู…ู† ุฐู„ูƒ. -unable_verify_ssh_key = ุชุนุฐุฑ ุงู„ุชุญู‚ู‚ ู…ู† ู…ูุชุงุญ ุงู„ู€SSHุŒ ุชุฃูƒุฏ ู…ู†ู‡ ู…ุฌุฏุฏุงู‹. +unable_verify_ssh_key = "ุชุนุฐุฑ ุงู„ุชุญู‚ู‚ ู…ู† ู…ูุชุงุญ ุงู„ู€SSHุŒ ุชุฃูƒุฏ ู…ู†ู‡ ู…ุฌุฏุฏุงู‹." invalid_gpg_key = ูุดู„ ุชุญู‚ู‚ ู…ูุชุงุญ ุงู„ู€GPG: %s still_own_packages = "ุญุณุงุจูƒ ูŠู…ู„ูƒ ุญุฒู…ุฉ ูˆุงุญุฏุฉ ุฃูˆ ุงูƒุซุฑุŒ ุงุญุฐูู‡ู… ุฃูˆู„ุงู‹." -still_own_repo = ุญุณุงุจูƒ ูŠู…ู„ูƒ ู…ุณุชูˆุฏุน ูˆุงุญุฏ ุฃูˆ ุงูƒุซุฑุŒ ุงุญุฐูู‡ู… ุฃูˆ ุญูˆู„ู‡ู… ุฃูˆู„ุงู‹. +still_own_repo = "ุญุณุงุจูƒ ูŠู…ู„ูƒ ู…ุณุชูˆุฏุน ูˆุงุญุฏ ุฃูˆ ุงูƒุซุฑุŒ ุงุญุฐูู‡ู… ุฃูˆ ุญูˆู„ู‡ู… ุฃูˆู„ุงู‹." +SSHTitle = ุงุณู… ู…ูุชุงุญ SSH 2fa_auth_required = ุงู„ุฒูŠุงุฑุฉ ุงู„ุฎุงุฑุฌูŠุฉ ุงู„ุฒู…ุช ุงุณุชูŠุซุงู‚ ุซู†ุงุฆูŠ. target_branch_not_exist = ุงู„ูุฑุน ุงู„ู…ุณุชู‡ุฏู ู„ูŠุณ ู…ูˆุฌูˆุฏ. PayloadUrl = ุฑุงุจุท ุงู„ุญู…ูˆู„ุฉ org_still_own_packages = "ุงู„ู…ู†ุธู…ุฉ ุชุฒุงู„ ุชู…ู„ูƒ ุญุฒู…ุฉ ูˆุงุญุฏุฉ ุฃูˆ ุงูƒุซุฑุŒ ุงุญุฐูู‡ู… ุฃูˆู„ุงู‹." last_org_owner = ู„ุง ูŠู…ูƒู†ูƒ ุฅุฒุงู„ุฉ ุขุฎุฑ ู…ุณุชุฎุฏู… ู…ู† ูุฑูŠู‚ "ุงู„ู…ุงู„ูƒูŠู†". ูŠุฌุจ ุฃู† ูŠูƒูˆู† ู‡ู†ุงูƒ ุนู„ู‰ ุงู„ุฃู‚ู„ ู…ุงู„ูƒ ูˆุงุญุฏ ู„ู„ู…ู†ุธู…ุฉ. +HttpsUrl = ุฑุงุจุท HTTPS invalid_ssh_key = ูุดู„ ุชุญู‚ู‚ ู…ูุชุงุญ ุงู„ู€SSH: %s AuthName = ุงุณู… ุงู„ุฃุฐู† +SSPISeparatorReplacement = ุงู„ูุงุตู„ุฉ openid_been_used = ุนู†ูˆุงู† ุงู„ู€OpenID "%s" ู…ูุณุชุฎุฏู… ุจุงู„ูุนู„. git_ref_name_error = `ูŠุฌุจ ุฃู† ูŠูƒูˆู† ุงุณู…ู‹ุง ู…ุฑุฌุนูŠู‹ุง ุฌูŠุฏู‹ุง ู„ู€ Git.` include_error = ` ูŠุฌุจ ุฃู† ูŠุญุชูˆูŠ ุนู„ู‰ ุณู„ุณู„ุฉ ูุฑุนูŠุฉ "%s".` @@ -2060,17 +1822,18 @@ glob_pattern_error = `ุงู„ู†ู…ุท ุงู„ุดุงู…ู„ ุบูŠุฑ ุตุงู„ุญ: %s.` CommitChoice = ุฅุฎุชูŠุงุฑ ุงู„ุฅุฏุงุน regex_pattern_error = ` ู†ู…ุท ุงู„ุชุนุจูŠุฑ ุงู„ู†ู…ุทูŠ ุบูŠุฑ ุตุงู„ุญ: %s.` username_error = ` ูŠูู…ูƒู†ู‡ ุฃู† ูŠุญุชูˆูŠ ุนู„ู‰ ุญุฑูˆู ุฅู†ุฌู„ูŠุฒูŠุฉ ูˆุฃุฑู‚ุงู… ูˆุดุฑุทุฉ ("-") ูˆุดุฑุทุฉ ุณูู„ูŠุฉ ("_") ูˆ ู†ู‚ุทุฉ (".") ูู‚ุท. ูˆูŠู…ูƒู†ู‡ ุงู† ูŠุจุฏุฃ ูˆูŠู†ุชู‡ูŠ ุจุญุฑู ุงูˆ ุจุฑู‚ู….` -Biography = ุงู„ู†ุจุฐุฉ -Website = ู…ูˆู‚ุน ุงู„ูˆูŠุจ -To = ุงุณู… ุงู„ูุฑุน -AccessToken = ุฑู…ุฒ ุงู„ูˆุตูˆู„ -repository_force_private = ูˆุถุน ุงู„ุฎุงุต ุงู„ุฅุฌุจุงุฑูŠ ู…ูุนู‘ู„: ู„ุง ูŠู…ูƒู† ุชุญูˆูŠู„ ุงู„ู…ุณุชูˆุฏุนุงุช ุงู„ุฎุงุตุฉ ุฅู„ู‰ ุนุงู…ุฉ. + FullName = ุงู„ุงุณู… ุงู„ูƒุงู…ู„ Description = ุงู„ูˆุตู Pronouns = ุงู„ุถู…ุงุฆุฑ -username_claiming_cooldown = ู„ุง ูŠู…ูƒู† ุงู„ู…ุทุงู„ุจุฉ ุจุงุณู… ุงู„ู…ุณุชุฎุฏู…ุŒ ู„ุฃู† ูุชุฑุฉ ุชุจุงุทุคู‡ ู„ู… ุชู†ุชู‡ู ุจุนุฏ. ูŠู…ูƒู† ุงู„ู…ุทุงู„ุจุฉ ุจู‡ ุนู†ุฏ %[1]s. +Biography = ุงู„ู†ุจุฐุฉ +Website = ู…ูˆู‚ุน ุงู„ูˆูŠุจ Location = ุงู„ู…ูˆู‚ุน +To = ุงุณู… ุงู„ูุฑุน +AccessToken = ุฑู…ุฒ ุงู„ูˆุตูˆู„ invalid_group_team_map_error = ` ุงู„ุชุนูŠูŠู† ุบูŠุฑ ุตุงู„ุญ: %s ` +username_claiming_cooldown = ู„ุง ูŠู…ูƒู† ุงู„ู…ุทุงู„ุจุฉ ุจุงุณู… ุงู„ู…ุณุชุฎุฏู…ุŒ ู„ุฃู† ูุชุฑุฉ ุชุจุงุทุคู‡ ู„ู… ุชู†ุชู‡ู ุจุนุฏ. ูŠู…ูƒู† ุงู„ู…ุทุงู„ุจุฉ ุจู‡ ุนู†ุฏ %[1]s. +repository_force_private = ูˆุถุน ุงู„ุฎุงุต ุงู„ุฅุฌุจุงุฑูŠ ู…ูุนู‘ู„: ู„ุง ูŠู…ูƒู† ุชุญูˆูŠู„ ุงู„ู…ุณุชูˆุฏุนุงุช ุงู„ุฎุงุตุฉ ุฅู„ู‰ ุนุงู…ุฉ. visit_rate_limit = ุชู†ุงูˆู„ุช ุงู„ุฒูŠุงุฑุฉ ุนู† ุจูุนุฏ ุงู„ุญุฏ ู…ู† ู…ุนุฏู„ู‡ุง. email_domain_is_not_allowed = ู†ุทุงู‚ ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ู„ู„ู…ุณุชุฎุฏู… %s ูŠุชุนุงุฑุถ ู…ุน ู‚ุงุฆู…ุฉ ุงู„ู†ุทุงู‚ุงุช ุงู„ู…ุณู…ูˆุญุฉ ุŒ ุฃูˆ ุงู„ู…ู…ู†ูˆุนุฉ. ูŠุฑุฌู‰ ุงู„ุชุฃูƒุฏ ู…ู† ุฅุฏุฎุงู„ ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ุจุดูƒู„ ุตุญูŠุญ. unset_password = ุงู„ู…ุณุชุฎุฏู… ุงู„ู…ุณุฌู„ ู„ู… ูŠู‚ู… ุจุชุนูŠูŠู† ูƒู„ู…ุฉ ู…ุฑูˆุฑ. @@ -2081,35 +1844,53 @@ required_prefix = ุงู„ู…ูุฏุฎู„ ูŠุฌุจ ุฃู† ูŠุจุฏุฃ ู…ุน "%s" [home] filter = ุชุตููŠุงุช ุฃุฎุฑู‰ show_archived = ู…ุคุฑุดู -my_orgs = ุงู„ู…ู†ุธู…ุงุช +search_repos = ุงู„ุนุซูˆุฑ ุนู„ู‰ ู…ุณุชูˆุฏุนโ€ฆ +my_orgs = ู…ูู†ุธู‘ู…ุงุชูŠ uname_holder = ุงุณู… ุงู„ู…ุณุชุฎุฏู… ุฃูˆ ุนู†ูˆุงู† ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ my_repos = ุงู„ู…ุณุชูˆุฏุนุงุช show_both_archived_unarchived = ูŠูุนุฑุถ ุงู„ู…ุคุฑุดู ูˆุบูŠุฑ ุงู„ู…ุคุฑุดู feed_of = ู…ูˆุฌุฒ "%s" issues.in_your_repos = ููŠ ู…ุณุชูˆุฏุนุงุชูƒ -switch_dashboard_context = ุจุฏู‘ู„ ุณูŠุงู‚ ู„ูˆุญุฉ ุงู„ุชุญูƒู… +switch_dashboard_context = ุชุบูŠูŠุฑ ุฅุทุงุฑ ู„ูˆุญุฉ ุงู„ุชุญูƒู… show_both_private_public = ูŠูุนุฑุถ ุงู„ุนุงู… ูˆุงู„ุฎุงุต filter_by_team_repositories = ุชุตููŠุฉ ุญุณุจ ู…ุณุชูˆุฏุนุงุช ุงู„ูุฑูŠู‚ show_only_private = ูŠูุนุฑุถ ุงู„ุฎุงุต ูู‚ุท show_private = ุฎุงุต +password_holder = ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ +show_more_repos = ุฅุธู‡ุงุฑ ุงู„ู…ุฒูŠุฏ ู…ู† ุงู„ู…ุณุชูˆุฏุนุงุชโ€ฆ show_only_public = ูŠูุนุฑุถ ุงู„ุนุงู… ูู‚ุท +collaborative_repos = ุงู„ู…ุณุชูˆุฏุนุงุช ุงู„ุชุนุงูˆู†ูŠุฉ show_only_unarchived = ูŠูุนุฑุถ ุบูŠุฑ ุงู„ู…ุคุฑุดู ูู‚ุท +my_mirrors = ู…ุฑุงูŠุงูŠ show_only_archived = ูŠูุนุฑุถ ุงู„ู…ุคุฑุดู ูู‚ุท view_home = ุนุฑุถ %s [explore] +search.match.tooltip = ุฅุดู…ู„ ูู‚ุท ุงู„ู†ุชุงุฆุฌ ุงู„ุชูŠ ุชุทุงุจู‚ ุงู„ุจุญุซ ูƒู„ูŠุงู‹ +search.type.tooltip = ู†ูˆุน ุงู„ุจุญุซ +code_search_results = ู†ุชุงุฆุฌ ุงู„ุจุญุซ ุนู† "%s" go_to = ุฅุฐู‡ุจ ุฅู„ู‰ repos = ุงู„ู…ุณุชูˆุฏุนุงุช users = ุงู„ู…ุณุชุฎุฏู…ูŠู† +code_search_unavailable = ุงู„ุจุญุซ ุงู„ุจุฑู…ุฌูŠ ุบูŠุฑ ู…ุชูˆูุฑ ุญุงู„ูŠุงู‹. ู…ู† ูุถู„ูƒ ุฑุงุณู„ ู…ุฏูŠุฑ ุงู„ู…ูˆู‚ุน. +search = ุงู„ุจุญุซ +user_no_results = ู„ุง ูŠูˆุฌุฏ ู…ุณุชุฎุฏู…ูˆู† ู…ุชุทุงุจู‚ูˆู†. +org_no_results = ู„ุง ุชูˆุฌุฏ ู…ู†ุธู…ุงุช ู…ุชุทุงุจู‚ุฉ. code = ู†ุต ุจุฑู…ุฌูŠ +search.match = ู…ุทุงุจู‚ +search.fuzzy.tooltip = ุฅุดู…ู„ ุงู„ู†ุชุงุฆุฌ ุงู„ุชูŠ ุชุทุงุจู‚ ุงู„ุจุญุซ ุชู‚ุฑูŠุจุงู‹ +search.fuzzy = ุชุทุงุจู‚ ุบุงู…ุถ organizations = ุงู„ู…ู†ุธู…ุงุช +repo_no_results = ู„ุง ุชูˆุฌุฏ ู…ุณุชูˆุฏุนุงุช ู…ุทุงุจู‚ุฉ. +code_no_results = ู„ู… ูŠุชู… ุงู„ุนุซูˆุฑ ุนู„ู‰ ุจุฑู…ุฌูŠุฉ ุชุทุงุจู‚ ุงู„ุจุญุซ. relevant_repositories_tooltip = ุชู… ุฃุฎูุงุก ุงู„ู…ุณุชูˆุฏุนุงุช ุงู„ุชูŠ ู‡ูŠ ู…ุดุชู‚ุงุช ูˆุฃูŠุถุงู‹ ุงู„ุชูŠ ู„ูŠุณ ู„ู‡ุง ู…ูˆุถูˆุนุŒ ูˆู„ุง ุฃูŠู‚ูˆู†ุฉุŒ ูˆู„ุง ูŠูˆุฌุฏ ูˆุตู. relevant_repositories = ูŠุชู… ุงุธู‡ุงุฑ ุงู„ู…ุณุชูˆุฏุนุงุช ุงู„ู…ุชุนู„ู‚ุฉ ูู‚ุท. ุฃุธู‡ุฑ ุงู„ู†ุชุงุฆุฌ ุบูŠุฑ ุงู„ู…ุตูุงุฉ. code_last_indexed_at = ููู‡ุฑุณ ุขุฎุฑ ู…ุฑุฉ %s + +stars_one = %d ู†ุฌู…ุฉ stars_few = %d ู†ุฌูˆู… forks_one = %d ู†ุณุฎุฉ forks_few = %d ู†ูุณูŽุฎ -stars_one = %d ู†ุฌู…ุฉ [actions] variables.none = ู„ุง ุชูˆุฌุฏ ู…ุชุบูŠุฑุงุช ุจุนุฏ. @@ -2143,6 +1924,7 @@ runners.labels = ุงู„ุชุตู†ูŠูุงุช runners.status.unspecified = ู…ุฌู‡ูˆู„ runs.commit = ุฅูŠุฏุงุน status.success = "ู†ุฌุญ" +runs.no_workflows.documentation =ู„ู…ุนุฑูุฉ ุงู„ู…ุฒูŠุฏ ุนู† ุฅุฌุฑุงุกุงุช ููˆุฑุฌูŠูˆุŒ ุจุฑุฌุงุก ุฑุคูŠุฉ ุงู„ุชูˆุซูŠู‚. runs.empty_commit_message = (ุฑุณุงู„ุฉ ุฅูŠุฏุงุน ูุงุฑุบุฉ) status.cancelled = "ู…ู„ุบูŠ" runs.status_no_select = ูƒู„ ุงู„ุญุงู„ุงุช @@ -2286,6 +2068,8 @@ search = ุงู„ุจุญุซโ€ฆ type_tooltip = ู†ูˆุน ุงู„ุจุญุซ fuzzy = ุฃุฌุนุฏ fuzzy_tooltip = ู‚ู… ุจุชุถู…ูŠู† ุงู„ู†ุชุงุฆุฌ ุงู„ุชูŠ ุชุชุทุงุจู‚ ุฃูŠุถู‹ุง ู…ุน ู…ุตุทู„ุญ ุงู„ุจุญุซ ุจุดูƒู„ ูˆุซูŠู‚ +match = ุชุชู†ุงุณุจ +match_tooltip = ู‚ู… ุจุชุถู…ูŠู† ุงู„ู†ุชุงุฆุฌ ุงู„ุชูŠ ุชุทุงุจู‚ ู…ุตุทู„ุญ ุงู„ุจุญุซ ุงู„ู…ุญุฏุฏ ูู‚ุท repo_kind = ุจุญุซ ููŠ ุงู„ู…ุณุชูˆุฏุนุงุชโ€ฆ user_kind = ุจุญุซ ุนู† ุงู„ู…ุณุชุฎุฏู…ูŠู†โ€ฆ team_kind = ุจุญุซ ุนู† ุงู„ูุฑู‚โ€ฆ @@ -2296,12 +2080,12 @@ no_results = ู„ุง ุชูˆุฌุฏ ู†ุชุงุฆุฌ ู…ุทุงุจู‚ุฉ. issue_kind = ุงู„ุจุญุซ ุถู…ู† ุงู„ุฃุนุทุงู„โ€ฆ pull_kind = ุงู„ุจุญุซ ุถู…ู† ุทู„ุจุงุช ุงู„ุณุญุจโ€ฆ keyword_search_unavailable = ุงู„ุจุญุซ ู…ู† ุฎู„ุงู„ ุงู„ูƒู„ู…ุงุช ุงู„ู…ูุชุงุญูŠุฉ ู„ูŠุณ ู…ุชูˆูุฑ ุญุงู„ูŠุงู‹. ุฑุฌุงุกุงู‹ ุชูˆุงุตู„ ู…ุน ู…ุดุฑู ุงู„ู…ูˆู‚ุน. -package_kind = ุงู„ุจุญุซ ุถู…ู† ุงู„ุญุฒู…โ€ฆ -regexp_tooltip = ุชุนุงู…ู„ ู…ุน ุนุจุงุฑุฉ ุงู„ุจุญุซ ุนู„ู‰ ุฃู†ู‡ุง ุชุนุจูŠุฑ ู†ู…ุทูŠ -commit_kind = ุงู„ุจุญุซ ุถู…ู† ุงู„ุฅูŠุฏุงุนุงุชโ€ฆ union = ู…ุทุงุจู‚ุฉ ุนุงู…ุฉ -runner_kind = ุงู„ุจุญุซ ุถู…ู† ุงู„ู…ุดุบู‘ูู„ุงุชโ€ฆ +union_tooltip = ุนุฑุถ ุงู„ู†ุชุงุฆุฌ ุงู„ุชูŠ ุชุทุงุจู‚ ุฃูŠ ู…ู† ุงู„ูƒู„ู…ุงุช ุงู„ู…ูุชุงุญูŠุฉ ุงู„ู…ูุตูˆู„ุฉ ุจู…ุณุงูุงุช exact = ู…ุทุงุจู‚ exact_tooltip = ุนุฑุถ ุงู„ู†ุชุงุฆุฌ ุงู„ุชูŠ ุชุทุงุจู‚ ู…ุตุทู„ุญ ุงู„ุจุญุซ ุจุงู„ุถุจุท ูู‚ุท regexp = RegExp -union_tooltip = ุนุฑุถ ุงู„ู†ุชุงุฆุฌ ุงู„ุชูŠ ุชุทุงุจู‚ ุฃูŠ ู…ู† ุงู„ูƒู„ู…ุงุช ุงู„ู…ูุชุงุญูŠุฉ ุงู„ู…ูุตูˆู„ุฉ ุจู…ุณุงูุงุช +regexp_tooltip = ุชุนุงู…ู„ ู…ุน ุนุจุงุฑุฉ ุงู„ุจุญุซ ุนู„ู‰ ุฃู†ู‡ุง ุชุนุจูŠุฑ ู†ู…ุทูŠ +package_kind = ุงู„ุจุญุซ ุถู…ู† ุงู„ุญุฒู…โ€ฆ +commit_kind = ุงู„ุจุญุซ ุถู…ู† ุงู„ุฅูŠุฏุงุนุงุชโ€ฆ +runner_kind = ุงู„ุจุญุซ ุถู…ู† ุงู„ู…ุดุบู‘ูู„ุงุชโ€ฆ diff --git a/options/locale/locale_be.ini b/options/locale/locale_be.ini index 25aff3019c..fe04dadc3e 100644 --- a/options/locale/locale_be.ini +++ b/options/locale/locale_be.ini @@ -7,20 +7,10 @@ sign_in = ะฃะฒะฐะนัั†ั– sign_in_or = ะฐะฑะพ sign_out = ะ’ั‹ะนัั†ั– sign_up = ะ—ะฐั€ัะณั–ัั‚ั€ะฐะฒะฐั†ั†ะฐ -link_account = ะ—ะฒัะทะฐั†ัŒ ัƒะปั–ะบะพะฒั‹ ะทะฐะฟั–ั +link_account = ะ—ะฒัะทะฐั†ัŒ ะฃะปั–ะบะพะฒั‹ ะทะฐะฟั–ั register = ะ ัะณั–ัั‚ั€ะฐั†ั‹ั version = ะ’ะตั€ัั–ั powered_by = ะŸั€ะฐั†ัƒะต ะฝะฐ โ„…s page = ะกั‚ะฐั€ะพะฝะบะฐ home = ะ“ะฐะปะพัžะฝะฐั ะกั‚ะฐั€ะพะฝะบะฐ -sign_in_with_provider = ะฃะฒะฐะนัั†ั– ะท %s -template = ะจะฐะฑะปะพะฝ -language = ะœะพะฒะฐ -notifications = ะะฟะฐะฒััˆั‡ัะฝะฝั– -create_new = ะกั‚ะฒะฐั€ั‹ั†ัŒโ€ฆ -user_profile_and_more = ะŸั€ะพั„ั–ะปัŒ ั– ะฝะฐะปะฐะดั‹โ€ฆ -signed_in_as = ะฃะฒะฐะนัˆะพัž ัะบ -enable_javascript = ะ“ัั‚ั‹ ะฒัะฑ-ัะฐะนั‚ ะฟะฐั‚ั€ะฐะฑัƒะต JavaScript. -toc = ะ—ะผะตัั‚ -licenses = ะ›ั–ั†ัะฝะทั–ั– -return_to_forgejo = ะ’ัั€ะฝัƒั†ั†ะฐ ะดะฐ Forgejo \ No newline at end of file +sign_in_with_provider = ะฃะฒะฐะนัั†ั– ะท %s \ No newline at end of file diff --git a/options/locale/locale_bg.ini b/options/locale/locale_bg.ini index 720c4fa1e5..35e33f4430 100644 --- a/options/locale/locale_bg.ini +++ b/options/locale/locale_bg.ini @@ -40,6 +40,7 @@ new_mirror = ะะพะฒะพ ะพะณะปะตะดะฐะปะฝะพ re_type = ะŸะพั‚ะฒัŠั€ะดะตั‚ะต ะฟะฐั€ะพะปะฐั‚ะฐ copy = ะšะพะฟะธั€ะฐะฝะต enabled = ะ’ะบะปัŽั‡ะตะฝะพ +new_org = ะะพะฒะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธั milestones = ะ•ั‚ะฐะฟะธ rss_feed = RSS ะตะผะธัะธั never = ะะธะบะพะณะฐ @@ -53,9 +54,12 @@ add_all = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะฒัะธั‡ะบะพ new_project_column = ะะพะฒะฐ ะบะพะปะพะฝะฐ add = ะ”ะพะฑะฐะฒัะฝะต organization = ะžั€ะณะฐะฝะธะทะฐั†ะธั +new_migrate = ะะพะฒะฐ ะผะธะณั€ะฐั†ะธั save = ะ—ะฐะฟะฐะทะฒะฐะฝะต sign_in_with_provider = ะ’ะปะธะทะฐะฝะต ั %s ok = ะ”ะพะฑั€ะต +manage_org = ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธะธั‚ะต +new_repo = ะะพะฒะพ ั…ั€ะฐะฝะธะปะธั‰ะต register = ะ ะตะณะธัั‚ั€ะฐั†ะธั mirror = ะžะณะปะตะดะฐะปะฝะพ username = ะŸะพั‚ั€ะตะฑะธั‚ะตะปัะบะพ ะธะผะต @@ -70,6 +74,7 @@ issues = ะ—ะฐะดะฐั‡ะธ retry = ะŸะพะฒั‚ะพั€ะตะฝ ะพะฟะธั‚ remove = ะŸั€ะตะผะฐั…ะฒะฐะฝะต admin_panel = ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ัะฐะนั‚ะฐ +account_settings = ะะฐัั‚ั€ะพะนะบะธ ะฝะฐ ะฐะบะฐัƒะฝั‚ะฐ powered_by = ะžััŠั‰ะตัั‚ะฒะตะฝะพ ะพั‚ %s pull_requests = ะ—ะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต collaborative = ะกัŠะฒะผะตัั‚ะฝะธ @@ -136,6 +141,7 @@ webauthn_sign_in = ะะฐั‚ะธัะฝะตั‚ะต ะฑัƒั‚ะพะฝะฐ ะฝะฐ ะฒะฐัˆะธั ะบะปัŽั‡ ะทะฐ webauthn_error = ะะตัƒัะฟะตัˆะฝะพ ะฟั€ะพั‡ะธั‚ะฐะฝะต ะฝะฐ ะฒะฐัˆะธั ะบะปัŽั‡ ะทะฐ ัะธะณัƒั€ะฝะพัั‚. webauthn_unsupported_browser = ะ’ะฐัˆะธัั‚ ะฑั€ะฐัƒะทัŠั€ ะฒ ะผะพะผะตะฝั‚ะฐ ะฝะต ะฟะพะดะดัŠั€ะถะฐ WebAuthn. webauthn_error_duplicated = ะšะปัŽั‡ัŠั‚ ะทะฐ ัะธะณัƒั€ะฝะพัั‚ ะฝะต ะต ั€ะฐะทั€ะตัˆะตะฝ ะทะฐ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ. ะœะพะปั, ัƒะฒะตั€ะตั‚ะต ัะต, ั‡ะต ะบะปัŽั‡ัŠั‚ ะฝะต ะต ะฒะตั‡ะต ั€ะตะณะธัั‚ั€ะธั€ะฐะฝ. + tracked_time_summary = ะžะฑะพะฑั‰ะตะฝะธะต ะฝะฐ ะฟั€ะพัะปะตะดะตะฝะพั‚ะพ ะฒั€ะตะผะต ะฒัŠะท ะพัะฝะพะฒะฐ ะฝะฐ ั„ะธะปั‚ั€ะธั‚ะต ะฒ ัะฟะธััŠะบะฐ ััŠั ะทะฐะดะฐั‡ะธ [settings] @@ -151,9 +157,11 @@ oauth2_application_edit = ะ ะตะดะฐะบั‚ะธั€ะฐะฝะต repos = ะฅั€ะฐะฝะธะปะธั‰ะฐ can_write_info = ะŸะธัะฐะฝะต delete = ะ˜ะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ะฐะบะฐัƒะฝั‚ะฐ +social = ะกะพั†ะธะฐะปะฝะธ ะฐะบะฐัƒะฝั‚ะธ twofa = ะ”ะฒัƒั„ะฐะบั‚ะพั€ะฝะพ ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต (TOTP) update_theme = ะŸั€ะพะผัะฝะฐ ะฝะฐ ั‚ะตะผะฐั‚ะฐ can_read_info = ะงะตั‚ะตะฝะต +access_token_deletion_confirm_action = ะ˜ะทั‚ั€ะธะฒะฐะฝะต website = ะฃะตะฑัะฐะนั‚ cancel = ะžั‚ะบะฐะท delete_token = ะ˜ะทั‚ั€ะธะฒะฐะฝะต @@ -163,16 +171,19 @@ save_application = ะ—ะฐะฟะฐะทะฒะฐะฝะต privacy = ะŸะพะฒะตั€ะธั‚ะตะปะฝะพัั‚ avatar = ะŸั€ะพั„ะธะปะฝะฐ ัะฝะธะผะบะฐ add_key = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะบะปัŽั‡ +account_link = ะกะฒัŠั€ะทะฐะฝะธ ะฐะบะฐัƒะฝั‚ะธ delete_email = ะŸั€ะตะผะฐั…ะฒะฐะฝะต update_language = ะŸั€ะพะผัะฝะฐ ะฝะฐ ะตะทะธะบะฐ organization = ะžั€ะณะฐะฝะธะทะฐั†ะธะธ link_account = ะกะฒัŠั€ะทะฒะฐะฝะต ะฝะฐ ะฐะบะฐัƒะฝั‚ +add_new_gpg_key = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ GPG ะบะปัŽั‡ manage_gpg_keys = ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ GPG ะบะปัŽั‡ะพะฒะตั‚ะต manage_ssh_keys = ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ SSH ะบะปัŽั‡ะพะฒะตั‚ะต old_password = ะขะตะบัƒั‰ะฐ ะฟะฐั€ะพะปะฐ public_profile = ะŸัƒะฑะปะธั‡ะตะฝ ะฟั€ะพั„ะธะป full_name = ะŸัŠะปะฝะพ ะธะผะต security = ะกะธะณัƒั€ะฝะพัั‚ +add_new_key = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ SSH ะบะปัŽั‡ account = ะะบะฐัƒะฝั‚ update_avatar = ะžะฑะฝะพะฒัะฒะฐะฝะต ะฝะฐ ะฟั€ะพั„ะธะปะฝะฐั‚ะฐ ัะฝะธะผะบะฐ ssh_gpg_keys = SSH / GPG ะบะปัŽั‡ะพะฒะต @@ -184,6 +195,7 @@ biography_placeholder = ะ ะฐะทะบะฐะถะตั‚ะต ะฝะฐ ะดั€ัƒะณะธั‚ะต ะผะฐะปะบะพ ะทะฐ orgs = ะžั€ะณะฐะฝะธะทะฐั†ะธะธ continue = ะŸั€ะพะดัŠะปะถะฐะฒะฐะฝะต blocked_users = ะ‘ะปะพะบะธั€ะฐะฝะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะปะธ +emails = ะะดั€ะตัะธ ะฝะฐ ะตะป. ะฟะพั‰ะฐ update_profile = ะžะฑะฝะพะฒัะฒะฐะฝะต ะฝะฐ ะฟั€ะพั„ะธะปะฐ profile = ะŸั€ะพั„ะธะป change_password = ะŸั€ะพะผัะฝะฐ ะฝะฐ ะฟะฐั€ะพะปะฐั‚ะฐ @@ -218,6 +230,7 @@ comment_type_group_title = ะ—ะฐะณะปะฐะฒะธะต comment_type_group_label = ะ•ั‚ะธะบะตั‚ change_username_prompt = ะ‘ะตะปะตะถะบะฐ: ะŸั€ะพะผัะฝะฐั‚ะฐ ะฝะฐ ะฟะพั‚ั€ะตะฑะธั‚ะตะปัะบะพั‚ะพ ะฒะธ ะธะผะต ะฟั€ะพะผะตะฝั ััŠั‰ะพ URL ะฝะฐ ะฒะฐัˆะธั ะฐะบะฐัƒะฝั‚. update_language_not_found = ะ•ะทะธะบัŠั‚ โ€ž%sโ€œ ะฝะต ะต ะฝะฐะปะธั‡ะตะฝ. +keep_activity_private_popup = ะ’ะฐัˆะฐั‚ะฐ ะดะตะนะฝะพัั‚ ั‰ะต ะฑัŠะดะต ะฒะธะดะธะผะฐ ัะฐะผะพ ะทะฐ ะฒะฐั ะธ ะฐะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€ะธั‚ะต ะฝะฐ ัะฐะนั‚ะฐ uploaded_avatar_not_a_image = ะšะฐั‡ะตะฝะธัั‚ ั„ะฐะนะป ะฝะต ะต ะธะทะพะฑั€ะฐะถะตะฝะธะต. uploaded_avatar_is_too_big = ะ ะฐะทะผะตั€ัŠั‚ ะฝะฐ ะบะฐั‡ะตะฝะธั ั„ะฐะนะป (%d KiB) ะฝะฐะดะฒะธัˆะฐะฒะฐ ะผะฐะบัะธะผะฐะปะฝะธั ั€ะฐะทะผะตั€ (%d KiB). change_password_success = ะŸะฐั€ะพะปะฐั‚ะฐ ะฒะธ ะต ะพะฑะฝะพะฒะตะฝะฐ. ะžั‚ัะตะณะฐ ะฝะฐั‚ะฐั‚ัŠะบ ะธะทะฟะพะปะทะฒะฐะนั‚ะต ะฝะพะฒะฐั‚ะฐ ัะธ ะฟะฐั€ะพะปะฐ, ะทะฐ ะดะฐ ะฒะปะตะทะตั‚ะต. @@ -267,10 +280,13 @@ confirm_delete_account = ะŸะพั‚ะฒัŠั€ะถะดะฐะฒะฐะฝะต ะฝะฐ ะธะทั‚ั€ะธะฒะฐะฝะตั‚ะพ email_notifications.onmention = ะ•ะป. ะฟะธัะผะพ ัะฐะผะพ ะฟั€ะธ ัะฟะพะผะตะฝะฐะฒะฐะฝะต pronouns_unspecified = ะะตะฟะพัะพั‡ะตะฝะธ pronouns = ะœะตัั‚ะพะธะผะตะฝะธั +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 = ะŸะตั€ัะพะฝะฐะปะธะทะธั€ะฐะฝะธ ะผะตัั‚ะพะธะผะตะฝะธั comment_type_group_review_request = ะ˜ัะบะฐะฝะต ะทะฐ ั€ะตั†ะตะฝะทะธั ssh_key_been_used = ะขะพะทะธ SSH ะบะปัŽั‡ ะฒะตั‡ะต ะต ะดะพะฑะฐะฒะตะฝ ะบัŠะผ ััŠั€ะฒัŠั€ะฐ. create_oauth2_application = ะกัŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะฝะพะฒะพ OAuth2 ะฟั€ะธะปะพะถะตะฝะธะต @@ -357,7 +373,7 @@ add_email_confirmation_sent = ะ˜ะทะฟั€ะฐั‚ะตะฝะพ ะต ะตะป. ะฟะธัะผะพ ะทะฐ ะฟะพั‚ additional_repo_units_hint_description = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ะฟะพะดัะบะฐะทะบะฐ โ€žะ’ะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะฟะพะฒะตั‡ะตโ€œ ะทะฐ ั…ั€ะฐะฝะธะปะธั‰ะฐ, ะบะพะธั‚ะพ ะฝัะผะฐั‚ ะฒะบะปัŽั‡ะตะฝะธ ะฒัะธั‡ะบะธ ะฝะฐะปะธั‡ะฝะธ ะตะปะตะผะตะฝั‚ะธ. email_notifications.submit = ะ—ะฐะดะฐะฒะฐะฝะต ะฝะฐ ะฟั€ะตะดะฟะพั‡ะธั‚. ะทะฐ ะตะป. ะฟะพั‰ะฐ email_notifications.andyourown = ะ˜ ะฒะฐัˆะธั‚ะต ัะพะฑัั‚ะฒะตะฝะธ ะธะทะฒะตัั‚ะธั -email_deletion_desc = ะขะพะทะธ ะฐะดั€ะตั ะทะฐ ะตะป. ะฟะพั‰ะฐ ะธ ัะฒัŠั€ะทะฐะฝะฐั‚ะฐ ะธะฝั„ะพั€ะผะฐั†ะธั ั‰ะต ะฑัŠะดะฐั‚ ะฟั€ะตะผะฐั…ะฝะฐั‚ะธ ะพั‚ ะฒะฐัˆะธั ะฐะบะฐัƒะฝั‚. Git ะฟะพะดะฐะฒะฐะฝะธัั‚ะฐ ะพั‚ ั‚ะพะทะธ ะฐะดั€ะตั ะทะฐ ะตะป. ะฟะพั‰ะฐ ั‰ะต ะพัั‚ะฐะฝะฐั‚ ะฝะตะฟั€ะพะผะตะฝะตะฝะธ. ะŸั€ะพะดัŠะปะถะฐะฒะฐะฝะต? +email_deletion_desc = ะะดั€ะตััŠั‚ ะทะฐ ะตะป. ะฟะพั‰ะฐ ะธ ัะฒัŠั€ะทะฐะฝะฐั‚ะฐ ะธะฝั„ะพั€ะผะฐั†ะธั ั‰ะต ะฑัŠะดะฐั‚ ะฟั€ะตะผะฐั…ะฝะฐั‚ะธ ะพั‚ ะฒะฐัˆะธั ะฐะบะฐัƒะฝั‚. Git ะฟะพะดะฐะฒะฐะฝะธัั‚ะฐ ะพั‚ ั‚ะพะทะธ ะฐะดั€ะตั ะทะฐ ะตะป. ะฟะพั‰ะฐ ั‰ะต ะพัั‚ะฐะฝะฐั‚ ะฝะตะฟั€ะพะผะตะฝะตะฝะธ. ะŸั€ะพะดัŠะปะถะฐะฒะฐะฝะต? add_email_success = ะะพะฒะธัั‚ ะฐะดั€ะตั ะทะฐ ะตะป. ะฟะพั‰ะฐ ะต ะดะพะฑะฐะฒะตะฝ. remove_account_link = ะŸั€ะตะผะฐั…ะฒะฐะฝะต ะฝะฐ ัะฒัŠั€ะทะฐะฝ ะฐะบะฐัƒะฝั‚ webauthn_alternative_tip = ะœะพะถะต ะดะฐ ะธัะบะฐั‚ะต ะดะฐ ะบะพะฝั„ะธะณัƒั€ะธั€ะฐั‚ะต ะดะพะฟัŠะปะฝะธั‚ะตะปะตะฝ ะผะตั‚ะพะด ะทะฐ ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต. @@ -366,19 +382,20 @@ hidden_comment_types = ะกะบั€ะธั‚ะธ ั‚ะธะฟะพะฒะต ะบะพะผะตะฝั‚ะฐั€ะธ comment_type_group_lock = ะกัŠัั‚ะพัะฝะธะต ะฝะฐ ะทะฐะบะปัŽั‡ะฒะฐะฝะต can_not_add_email_activations_pending = ะ˜ะผะฐ ั‡ะฐะบะฐั‰ะฐ ะฐะบั‚ะธะฒะฐั†ะธั, ะพะฟะธั‚ะฐะนั‚ะต ะพั‚ะฝะพะฒะพ ัะปะตะด ะฝัะบะพะปะบะพ ะผะธะฝัƒั‚ะธ, ะฐะบะพ ะธัะบะฐั‚ะต ะดะฐ ะดะพะฑะฐะฒะธั‚ะต ะฝะพะฒะฐ ะตะป. ะฟะพั‰ะฐ. storage_overview = ะŸั€ะตะณะปะตะด ะฝะฐ ััŠั…ั€ะฐะฝะตะฝะธะตั‚ะพ + webauthn = ะ”ะฒัƒั„ะฐะบั‚ะพั€ะฝะพ ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต (ะšะปัŽั‡ะพะฒะต ะทะฐ ัะธะณัƒั€ะฝะพัั‚) +quota.sizes.all = ะ’ัะธั‡ะบะธ +quota.sizes.repos.all = ะฅั€ะฐะฝะธะปะธั‰ะฐ quota.sizes.repos.public = ะŸัƒะฑะปะธั‡ะฝะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ quota.sizes.repos.private = ะงะฐัั‚ะฝะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ quota.sizes.git.all = Git ััŠะดัŠั€ะถะฐะฝะธะต quota.sizes.git.lfs = Git LFS quota.sizes.assets.attachments.all = ะŸั€ะธะบะฐั‡ะตะฝะธ ั„ะฐะนะปะพะฒะต +quota.sizes.assets.attachments.issues = ะŸั€ะธะบะฐั‡ะตะฝะธ ั„ะฐะนะปะพะฒะต ะบัŠะผ ะทะฐะดะฐั‡ะธ quota.sizes.assets.attachments.releases = ะŸั€ะธะบะฐั‡ะตะฝะธ ั„ะฐะนะปะพะฒะต ะบัŠะผ ะธะทะดะฐะฝะธั quota.sizes.assets.artifacts = ะั€ั‚ะตั„ะฐะบั‚ะธ quota.sizes.assets.packages.all = ะŸะฐะบะตั‚ะธ quota.sizes.wiki = ะฃะธะบะธ -quota.sizes.all = ะ’ัะธั‡ะบะธ -quota.sizes.repos.all = ะฅั€ะฐะฝะธะปะธั‰ะฐ -quota.sizes.assets.attachments.issues = ะŸั€ะธะบะฐั‡ะตะฝะธ ั„ะฐะนะปะพะฒะต ะบัŠะผ ะทะฐะดะฐั‡ะธ [packages] container.labels.value = ะกั‚ะพะนะฝะพัั‚ @@ -437,112 +454,113 @@ details.documentation_site = ะฃะตะฑัะฐะนั‚ ะฝะฐ ะดะพะบัƒะผะตะฝั‚ะฐั†ะธัั‚ะฐ arch.version.conflicts = ะ’ ะบะพะฝั„ะปะธะบั‚ alpine.repository.branches = ะšะปะพะฝะพะฒะต arch.pacman.repo.multi.item = ะšะพะฝั„ะธะณัƒั€ะฐั†ะธั ะทะฐ %s -container.multi_arch = ะžะก / ะั€ั…ะธั‚ะตะบั‚ัƒั€ะฐ -rpm.repository = ะ˜ะฝั„ะพั€ะผะฐั†ะธั ะทะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ -container.pull = ะ˜ะทะดัŠั€ะฟะฐะนั‚ะต ะพะฑั€ะฐะทะฐ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: -helm.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: -debian.repository.distributions = ะ”ะธัั‚ั€ะธะฑัƒั†ะธะธ -npm.dependencies.optional = ะžะฟั†ะธะพะฝะฐะปะฝะธ ะทะฐะฒะธัะธะผะพัั‚ะธ -owner.settings.cargo.title = ะ˜ะฝะดะตะบั ะฝะฐ ั€ะตะณะธัั‚ัŠั€ะฐ ะฝะฐ Cargo -owner.settings.cleanuprules.keep.pattern.container = ะ’ะตั€ัะธัั‚ะฐ latest ะฒะธะฝะฐะณะธ ัะต ะทะฐะฟะฐะทะฒะฐ ะทะฐ Container ะฟะฐะบะตั‚ะธ. -owner.settings.cleanuprules.remove.pattern = ะŸั€ะตะผะฐั…ะฒะฐะฝะต ะฝะฐ ะฒะตั€ัะธะธ, ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‰ะธ ะฝะฐ -rpm.distros.suse = ะฝะฐ ะดะธัั‚ั€ะธะฑัƒั†ะธะธ, ะฑะฐะทะธั€ะฐะฝะธ ะฝะฐ SUSE -owner.settings.cleanuprules.preview.overview = %d ะฟะฐะบะตั‚ะฐ ัะฐ ะฝะฐัั€ะพั‡ะตะฝะธ ะทะฐ ะฟั€ะตะผะฐั…ะฒะฐะฝะต. -owner.settings.cleanuprules.preview = ะŸั€ะตะณะปะตะด ะฝะฐ ะฟั€ะฐะฒะธะปะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต -arch.version.properties = ะกะฒะพะนัั‚ะฒะฐ ะฝะฐ ะฒะตั€ัะธัั‚ะฐ -conan.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: -conan.details.repository = ะฅั€ะฐะฝะธะปะธั‰ะต -composer.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั Composer, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -chef.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -chef.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป ~/.chef/config.rb: -pub.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั Dart, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -npm.details.tag = ะœะฐั€ะบะตั€ -npm.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั npm, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -maven.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะฒัŠะฒ ั„ะฐะนะปะฐ ะฝะฐ ะฒะฐัˆะธั ะฟั€ะพะตะบั‚ pom.xml: -debian.repository.components = ะšะพะผะฟะพะฝะตะฝั‚ะธ -debian.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -cran.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -cran.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป Rprofile.site: -rpm.distros.redhat = ะฝะฐ ะดะธัั‚ั€ะธะฑัƒั†ะธะธ, ะฑะฐะทะธั€ะฐะฝะธ ะฝะฐ RedHat -alt.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: -rpm.repository.architectures = ะั€ั…ะธั‚ะตะบั‚ัƒั€ะธ -alt.registry.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -alt.setup = ะ”ะพะฑะฐะฒะตั‚ะต ั…ั€ะฐะฝะธะปะธั‰ะต ะบัŠะผ ัะฟะธััŠะบะฐ ััŠั ัะฒัŠั€ะทะฐะฝะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ (ะธะทะฑะตั€ะตั‚ะต ะฝะตะพะฑั…ะพะดะธะผะฐั‚ะฐ ะฐั€ั…ะธั‚ะตะบั‚ัƒั€ะฐ ะฒะผะตัั‚ะพ โ€ž_arch_โ€œ): -alt.repository = ะ˜ะฝั„ะพั€ะผะฐั†ะธั ะทะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ -owner.settings.cargo.initialize.error = ะะตัƒัะฟะตัˆะฝะพ ะธะฝะธั†ะธะฐะปะธะทะธั€ะฐะฝะต ะฝะฐ ะธะฝะดะตะบัะฐ ะฝะฐ Cargo: %v -owner.settings.cargo.initialize = ะ˜ะฝะธั†ะธะฐะปะธะทะธั€ะฐะฝะต ะฝะฐ ะธะฝะดะตะบั -settings.delete.description = ะ˜ะทั‚ั€ะธะฒะฐะฝะตั‚ะพ ะฝะฐ ะฟะฐะบะตั‚ ะต ั‚ั€ะฐะนะฝะพ ะธ ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะพั‚ะผะตะฝะตะฝะพ. -alt.repository.multiple_groups = ะขะพะทะธ ะฟะฐะบะตั‚ ะต ะฝะฐะปะธั‡ะตะฝ ะฒ ะฝัะบะพะปะบะพ ะณั€ัƒะฟะธ. -alt.repository.architectures = ะั€ั…ะธั‚ะตะบั‚ัƒั€ะธ -owner.settings.chef.title = ะ ะตะณะธัั‚ัŠั€ ะฝะฐ Chef -owner.settings.cleanuprules.remove.days = ะŸั€ะตะผะฐั…ะฒะฐะฝะต ะฝะฐ ะฒะตั€ัะธะธ, ะฟะพ-ัั‚ะฐั€ะธ ะพั‚ -owner.settings.cleanuprules.keep.pattern = ะ—ะฐะฟะฐะทะฒะฐะฝะต ะฝะฐ ะฒะตั€ัะธะธ, ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‰ะธ ะฝะฐ -owner.settings.cleanuprules.keep.count.n = %d ะฒะตั€ัะธะธ ะฝะฐ ะฟะฐะบะตั‚ -owner.settings.cleanuprules.keep.count.1 = 1 ะฒะตั€ัะธั ะฝะฐ ะฟะฐะบะตั‚ -owner.settings.cleanuprules.keep.count = ะ—ะฐะฟะฐะทะฒะฐะฝะต ะฝะฐ ะฝะฐะน-ะฝะพะฒะธั‚ะต -owner.settings.cleanuprules.enabled = ะ’ะบะปัŽั‡ะตะฝะพ -owner.settings.cleanuprules.preview.none = ะŸั€ะฐะฒะธะปะพั‚ะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต ะฝะต ััŠะฒะฟะฐะดะฐ ั ะฝะธั‚ะพ ะตะดะธะฝ ะฟะฐะบะตั‚. -owner.settings.cleanuprules.none = ะ’ัะต ะพั‰ะต ะฝัะผะฐ ะฟั€ะฐะฒะธะปะฐ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต. -owner.settings.cleanuprules.add = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะฟั€ะฐะฒะธะปะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต -owner.settings.cleanuprules.title = ะŸั€ะฐะฒะธะปะฐ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต -owner.settings.cargo.rebuild.success = ะ˜ะฝะดะตะบััŠั‚ ะฝะฐ Cargo ะฑะตัˆะต ัƒัะฟะตัˆะฝะพ ะฟั€ะตะธะทะณั€ะฐะดะตะฝ. + +desc = ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะฟะฐะบะตั‚ะธั‚ะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. +alpine.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€, ะบะฐั‚ะพ ะดะพะฑะฐะฒะธั‚ะต URL ะฐะดั€ะตัะฐ ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป /etc/apk/repositories: alpine.registry.key = ะ˜ะทั‚ะตะณะปะตั‚ะต ะฟัƒะฑะปะธั‡ะฝะธั RSA ะบะปัŽั‡ ะฝะฐ ั€ะตะณะธัั‚ัŠั€ะฐ ะฒ ะฟะฐะฟะบะฐั‚ะฐ /etc/apk/keys/, ะทะฐ ะดะฐ ะฟั€ะพะฒะตั€ะธั‚ะต ะฟะพะดะฟะธัะฐ ะฝะฐ ะธะฝะดะตะบัะฐ: alpine.registry.info = ะ˜ะทะฑะตั€ะตั‚ะต $branch ะธ $repository ะพั‚ ัะฟะธััŠะบะฐ ะฟะพ-ะดะพะปัƒ. +alpine.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +arch.version.properties = ะกะฒะพะนัั‚ะฒะฐ ะฝะฐ ะฒะตั€ัะธัั‚ะฐ +arch.version.makedepends = ะ—ะฐะฒะธัะธะผะพัั‚ะธ ะทะฐ ะธะทะณั€ะฐะถะดะฐะฝะตั‚ะพ arch.version.checkdepends = ะ—ะฐะฒะธัะธะผะพัั‚ะธ ะทะฐ ะฟั€ะพะฒะตั€ะบะฐั‚ะฐ +chef.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป ~/.chef/config.rb: +chef.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +composer.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป ~/.composer/config.json: +composer.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั Composer, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: composer.dependencies = ะ—ะฐะฒะธัะธะผะพัั‚ะธ -swift.install = ะ”ะพะฑะฐะฒะตั‚ะต ะฟะฐะบะตั‚ะฐ ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป Package.swift: -settings.link.error = ะะตัƒัะฟะตัˆะฝะพ ะพะฑะฝะพะฒัะฒะฐะฝะต ะฝะฐ ะฒั€ัŠะทะบะฐั‚ะฐ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. -swift.install2 = ะธ ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -rpm.repository.multiple_groups = ะขะพะทะธ ะฟะฐะบะตั‚ ะต ะฝะฐะปะธั‡ะตะฝ ะฒ ะฝัะบะพะปะบะพ ะณั€ัƒะฟะธ. +conan.details.repository = ะฅั€ะฐะฝะธะปะธั‰ะต +conan.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: +conan.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั Conan, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: conda.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะบะฐั‚ะพ Conda ั…ั€ะฐะฝะธะปะธั‰ะต ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป .condarc: conda.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั Conda, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -owner.settings.cargo.rebuild.error = ะะตัƒัะฟะตัˆะฝะพ ะฟั€ะตะธะทะณั€ะฐะถะดะฐะฝะต ะฝะฐ ะธะฝะดะตะบัะฐ ะฝะฐ Cargo: %v -owner.settings.cargo.rebuild = ะŸั€ะตะธะทะณั€ะฐะถะดะฐะฝะต ะฝะฐ ะธะฝะดะตะบั -settings.link.button = ะžะฑะฝะพะฒัะฒะฐะฝะต ะฝะฐ ะฒั€ัŠะทะบะฐั‚ะฐ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ -settings.link.select = ะ˜ะทะฑะตั€ะตั‚ะต ั…ั€ะฐะฝะธะปะธั‰ะต -debian.repository.architectures = ะั€ั…ะธั‚ะตะบั‚ัƒั€ะธ -rpm.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: +container.pull = ะ˜ะทะดัŠั€ะฟะฐะนั‚ะต ะพะฑั€ะฐะทะฐ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: +container.multi_arch = ะžะก / ะั€ั…ะธั‚ะตะบั‚ัƒั€ะฐ +container.layers = ะกะปะพะตะฒะต ะฝะฐ ะพะฑั€ะฐะทะฐ +cran.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป Rprofile.site: +cran.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: debian.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: -helm.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -swift.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: -settings.link = ะกะฒัŠั€ะทะฒะฐะฝะต ะฝะฐ ั‚ะพะทะธ ะฟะฐะบะตั‚ ั ั…ั€ะฐะฝะธะปะธั‰ะต -settings.link.description = ะะบะพ ัะฒัŠั€ะถะตั‚ะต ะฟะฐะบะตั‚ ั ั…ั€ะฐะฝะธะปะธั‰ะต, ะฟะฐะบะตั‚ัŠั‚ ัะต ะธะทะฑั€ะพัะฒะฐ ะฒ ัะฟะธััŠะบะฐ ั ะฟะฐะบะตั‚ะธ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. -settings.link.success = ะ’ั€ัŠะทะบะฐั‚ะฐ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะฑะตัˆะต ัƒัะฟะตัˆะฝะพ ะพะฑะฝะพะฒะตะฝะฐ. -owner.settings.cleanuprules.pattern_full_match = ะŸั€ะธะปะฐะณะฐะฝะต ะฝะฐ ัˆะฐะฑะปะพะฝะฐ ะบัŠะผ ะฟัŠะปะฝะพั‚ะพ ะธะผะต ะฝะฐ ะฟะฐะบะตั‚ะฐ -owner.settings.cleanuprules.keep.title = ะ’ะตั€ัะธะธั‚ะต, ะบะพะธั‚ะพ ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‚ ะฝะฐ ั‚ะตะทะธ ะฟั€ะฐะฒะธะปะฐ, ัะต ะทะฐะฟะฐะทะฒะฐั‚, ะดะพั€ะธ ะฐะบะพ ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‚ ะฝะฐ ะฟั€ะฐะฒะธะปะพ ะทะฐ ะฟั€ะตะผะฐั…ะฒะฐะฝะต ะฟะพ-ะดะพะปัƒ. -debian.repository = ะ˜ะฝั„ะพั€ะผะฐั†ะธั ะทะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ -maven.install = ะ—ะฐ ะดะฐ ะธะทะฟะพะปะทะฒะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะฒะบะปัŽั‡ะตั‚ะต ัะปะตะดะฝะพั‚ะพ ะฒ ะฑะปะพะบะฐ dependencies ะฒัŠะฒ ั„ะฐะนะปะฐ pom.xml: -nuget.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั NuGet, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -alt.install = ะ˜ะฝัั‚ะฐะปะธั€ะฐะฝะต ะฝะฐ ะฟะฐะบะตั‚ -owner.settings.cleanuprules.edit = ะ ะตะดะฐะบั‚ะธั€ะฐะฝะต ะฝะฐ ะฟั€ะฐะฒะธะปะพั‚ะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต -rpm.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -pypi.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั pip, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -arch.version.makedepends = ะ—ะฐะฒะธัะธะผะพัั‚ะธ ะทะฐ ะธะทะณั€ะฐะถะดะฐะฝะตั‚ะพ -alpine.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -desc = ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะฟะฐะบะตั‚ะธั‚ะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. -owner.settings.cargo.rebuild.no_index = ะะต ะผะพะถะต ะดะฐ ัะต ะฟั€ะตะธะทะณั€ะฐะดะธ, ะฝัะผะฐ ะธะฝะธั†ะธะฐะปะธะทะธั€ะฐะฝ ะธะฝะดะตะบั. -owner.settings.cargo.rebuild.description = ะŸั€ะตะธะทะณั€ะฐะถะดะฐะฝะตั‚ะพ ะผะพะถะต ะดะฐ ะฑัŠะดะต ะฟะพะปะตะทะฝะพ, ะฐะบะพ ะธะฝะดะตะบััŠั‚ ะฝะต ะต ัะธะฝั…ั€ะพะฝะธะทะธั€ะฐะฝ ััŠั ััŠั…ั€ะฐะฝะตะฝะธั‚ะต Cargo ะฟะฐะบะตั‚ะธ. -owner.settings.cargo.initialize.description = ะะตะพะฑั…ะพะดะธะผะพ ะต ัะฟะตั†ะธะฐะปะฝะพ Git ั…ั€ะฐะฝะธะปะธั‰ะต ะทะฐ ะธะฝะดะตะบั, ะทะฐ ะดะฐ ัะต ะธะทะฟะพะปะทะฒะฐ ั€ะตะณะธัั‚ัŠั€ัŠั‚ ะฝะฐ Cargo. ะ˜ะทะฟะพะปะทะฒะฐะฝะตั‚ะพ ะฝะฐ ั‚ะฐะทะธ ะพะฟั†ะธั ั‰ะต (ะฟั€ะต)ััŠะทะดะฐะดะต ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะธ ั‰ะต ะณะพ ะบะพะฝั„ะธะณัƒั€ะธั€ะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ. -pypi.requires = ะ˜ะทะธัะบะฒะฐ Python debian.registry.info = ะ˜ะทะฑะตั€ะตั‚ะต $distribution ะธ $component ะพั‚ ัะฟะธััŠะบะฐ ะฟะพ-ะดะพะปัƒ. -alpine.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€, ะบะฐั‚ะพ ะดะพะฑะฐะฒะธั‚ะต URL ะฐะดั€ะตัะฐ ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป /etc/apk/repositories: -owner.settings.cargo.initialize.success = ะ˜ะฝะดะตะบััŠั‚ ะฝะฐ Cargo ะฑะตัˆะต ัƒัะฟะตัˆะฝะพ ััŠะทะดะฐะดะตะฝ. -npm.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะฒัŠะฒ ั„ะฐะนะปะฐ ะฝะฐ ะฒะฐัˆะธั ะฟั€ะพะตะบั‚ .npmrc: -owner.settings.chef.keypair = ะ“ะตะฝะตั€ะธั€ะฐะฝะต ะฝะฐ ะดะฒะพะนะบะฐ ะบะปัŽั‡ะพะฒะต -owner.settings.chef.keypair.description = ะ—ะฐัะฒะบะธั‚ะต, ะธะทะฟั€ะฐั‚ะตะฝะธ ะดะพ ั€ะตะณะธัั‚ัŠั€ะฐ ะฝะฐ Chef, ั‚ั€ัะฑะฒะฐ ะดะฐ ะฑัŠะดะฐั‚ ะบั€ะธะฟั‚ะพะณั€ะฐั„ัะบะธ ะฟะพะดะฟะธัะฐะฝะธ ะบะฐั‚ะพ ัั€ะตะดัั‚ะฒะพ ะทะฐ ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต. ะŸั€ะธ ะณะตะฝะตั€ะธั€ะฐะฝะต ะฝะฐ ะดะฒะพะนะบะฐ ะบะปัŽั‡ะพะฒะต, ัะฐะผะพ ะฟัƒะฑะปะธั‡ะฝะธัั‚ ะบะปัŽั‡ ัะต ััŠั…ั€ะฐะฝัะฒะฐ ะฒัŠะฒ Forgejo. ะงะฐัั‚ะฝะธัั‚ ะบะปัŽั‡ ะฒะธ ัะต ะฟั€ะตะดะพัั‚ะฐะฒั, ะทะฐ ะดะฐ ัะต ะธะทะฟะพะปะทะฒะฐ ั knife. ะ“ะตะฝะตั€ะธั€ะฐะฝะตั‚ะพ ะฝะฐ ะฝะพะฒะฐ ะดะฒะพะนะบะฐ ะบะปัŽั‡ะพะฒะต ั‰ะต ะฟั€ะตะทะฐะฟะธัˆะต ะฟั€ะตะดะธัˆะฝะฐั‚ะฐ. -owner.settings.cleanuprules.remove.title = ะ’ะตั€ัะธะธั‚ะต, ะบะพะธั‚ะพ ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‚ ะฝะฐ ั‚ะตะทะธ ะฟั€ะฐะฒะธะปะฐ, ัะต ะฟั€ะตะผะฐั…ะฒะฐั‚, ะพัะฒะตะฝ ะฐะบะพ ะฟั€ะฐะฒะธะปะพ ะฟะพ-ะณะพั€ะต ะฝะต ะบะฐะทะฒะฐ ะดะฐ ัะต ะทะฐะฟะฐะทัั‚. -nuget.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: -owner.settings.cleanuprules.success.update = ะŸั€ะฐะฒะธะปะพั‚ะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต ะต ะพะฑะฝะพะฒะตะฝะพ. -settings.delete.notice = ะะฐ ะฟัŠั‚ ัั‚ะต ะดะฐ ะธะทั‚ั€ะธะตั‚ะต %s (%s). ะขะฐะทะธ ะพะฟะตั€ะฐั†ะธั ะต ะฝะตะพะฑั€ะฐั‚ะธะผะฐ, ัะธะณัƒั€ะฝะธ ะปะธ ัั‚ะต? -npm.install2 = ะธะปะธ ะณะพ ะดะพะฑะฐะฒะตั‚ะต ะฒัŠะฒ ั„ะฐะนะปะฐ package.json: -owner.settings.cleanuprules.success.delete = ะŸั€ะฐะฒะธะปะพั‚ะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต ะต ะธะทั‚ั€ะธั‚ะพ. -vagrant.install = ะ—ะฐ ะดะฐ ะดะพะฑะฐะฒะธั‚ะต Vagrant box, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -nuget.dependency.framework = ะฆะตะปะตะฒะฐ ะฟะปะฐั‚ั„ะพั€ะผะฐ +debian.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +debian.repository = ะ˜ะฝั„ะพั€ะผะฐั†ะธั ะทะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ +debian.repository.distributions = ะ”ะธัั‚ั€ะธะฑัƒั†ะธะธ +debian.repository.components = ะšะพะผะฟะพะฝะตะฝั‚ะธ +debian.repository.architectures = ะั€ั…ะธั‚ะตะบั‚ัƒั€ะธ +helm.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: +helm.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +maven.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะฒัŠะฒ ั„ะฐะนะปะฐ ะฝะฐ ะฒะฐัˆะธั ะฟั€ะพะตะบั‚ pom.xml: +maven.install = ะ—ะฐ ะดะฐ ะธะทะฟะพะปะทะฒะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะฒะบะปัŽั‡ะตั‚ะต ัะปะตะดะฝะพั‚ะพ ะฒ ะฑะปะพะบะฐ dependencies ะฒัŠะฒ ั„ะฐะนะปะฐ pom.xml: maven.install2 = ะ˜ะทะฟัŠะปะฝะตั‚ะต ะฟั€ะตะท ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: maven.download = ะ—ะฐ ะดะฐ ะธะทั‚ะตะณะปะธั‚ะต ะทะฐะฒะธัะธะผะพัั‚ั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ะฟั€ะตะท ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: -container.layers = ะกะปะพะตะฒะต ะฝะฐ ะพะฑั€ะฐะทะฐ -conan.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั Conan, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: -composer.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป ~/.composer/config.json: +nuget.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: +nuget.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั NuGet, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +nuget.dependency.framework = ะฆะตะปะตะฒะฐ ะฟะปะฐั‚ั„ะพั€ะผะฐ +npm.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะฒัŠะฒ ั„ะฐะนะปะฐ ะฝะฐ ะฒะฐัˆะธั ะฟั€ะพะตะบั‚ .npmrc: +npm.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั npm, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +npm.install2 = ะธะปะธ ะณะพ ะดะพะฑะฐะฒะตั‚ะต ะฒัŠะฒ ั„ะฐะนะปะฐ package.json: +npm.dependencies.optional = ะžะฟั†ะธะพะฝะฐะปะฝะธ ะทะฐะฒะธัะธะผะพัั‚ะธ +npm.details.tag = ะœะฐั€ะบะตั€ +pub.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั Dart, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +pypi.requires = ะ˜ะทะธัะบะฒะฐ Python +pypi.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ ั pip, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +rpm.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: +rpm.distros.redhat = ะฝะฐ ะดะธัั‚ั€ะธะฑัƒั†ะธะธ, ะฑะฐะทะธั€ะฐะฝะธ ะฝะฐ RedHat +rpm.distros.suse = ะฝะฐ ะดะธัั‚ั€ะธะฑัƒั†ะธะธ, ะฑะฐะทะธั€ะฐะฝะธ ะฝะฐ SUSE +rpm.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +rpm.repository = ะ˜ะฝั„ะพั€ะผะฐั†ะธั ะทะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ +rpm.repository.architectures = ะั€ั…ะธั‚ะตะบั‚ัƒั€ะธ +rpm.repository.multiple_groups = ะขะพะทะธ ะฟะฐะบะตั‚ ะต ะฝะฐะปะธั‡ะตะฝ ะฒ ะฝัะบะพะปะบะพ ะณั€ัƒะฟะธ. +alt.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: +alt.registry.install = ะ—ะฐ ะดะฐ ะธะฝัั‚ะฐะปะธั€ะฐั‚ะต ะฟะฐะบะตั‚ะฐ, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +alt.install = ะ˜ะฝัั‚ะฐะปะธั€ะฐะฝะต ะฝะฐ ะฟะฐะบะตั‚ +alt.setup = ะ”ะพะฑะฐะฒะตั‚ะต ั…ั€ะฐะฝะธะปะธั‰ะต ะบัŠะผ ัะฟะธััŠะบะฐ ััŠั ัะฒัŠั€ะทะฐะฝะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ (ะธะทะฑะตั€ะตั‚ะต ะฝะตะพะฑั…ะพะดะธะผะฐั‚ะฐ ะฐั€ั…ะธั‚ะตะบั‚ัƒั€ะฐ ะฒะผะตัั‚ะพ โ€ž_arch_โ€œ): +alt.repository = ะ˜ะฝั„ะพั€ะผะฐั†ะธั ะทะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ +alt.repository.architectures = ะั€ั…ะธั‚ะตะบั‚ัƒั€ะธ +alt.repository.multiple_groups = ะขะพะทะธ ะฟะฐะบะตั‚ ะต ะฝะฐะปะธั‡ะตะฝ ะฒ ะฝัะบะพะปะบะพ ะณั€ัƒะฟะธ. +swift.registry = ะะฐัั‚ั€ะพะนั‚ะต ั‚ะพะทะธ ั€ะตะณะธัั‚ัŠั€ ะพั‚ ะบะพะผะฐะฝะดะฝะธั ั€ะตะด: +swift.install = ะ”ะพะฑะฐะฒะตั‚ะต ะฟะฐะบะตั‚ะฐ ะฒัŠะฒ ะฒะฐัˆะธั ั„ะฐะนะป Package.swift: +swift.install2 = ะธ ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +vagrant.install = ะ—ะฐ ะดะฐ ะดะพะฑะฐะฒะธั‚ะต Vagrant box, ะธะทะฟัŠะปะฝะตั‚ะต ัะปะตะดะฝะฐั‚ะฐ ะบะพะผะฐะฝะดะฐ: +settings.link = ะกะฒัŠั€ะทะฒะฐะฝะต ะฝะฐ ั‚ะพะทะธ ะฟะฐะบะตั‚ ั ั…ั€ะฐะฝะธะปะธั‰ะต +settings.link.description = ะะบะพ ัะฒัŠั€ะถะตั‚ะต ะฟะฐะบะตั‚ ั ั…ั€ะฐะฝะธะปะธั‰ะต, ะฟะฐะบะตั‚ัŠั‚ ัะต ะธะทะฑั€ะพัะฒะฐ ะฒ ัะฟะธััŠะบะฐ ั ะฟะฐะบะตั‚ะธ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. +settings.link.select = ะ˜ะทะฑะตั€ะตั‚ะต ั…ั€ะฐะฝะธะปะธั‰ะต +settings.link.button = ะžะฑะฝะพะฒัะฒะฐะฝะต ะฝะฐ ะฒั€ัŠะทะบะฐั‚ะฐ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ +settings.link.success = ะ’ั€ัŠะทะบะฐั‚ะฐ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะฑะตัˆะต ัƒัะฟะตัˆะฝะพ ะพะฑะฝะพะฒะตะฝะฐ. +settings.link.error = ะะตัƒัะฟะตัˆะฝะพ ะพะฑะฝะพะฒัะฒะฐะฝะต ะฝะฐ ะฒั€ัŠะทะบะฐั‚ะฐ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. +settings.delete.description = ะ˜ะทั‚ั€ะธะฒะฐะฝะตั‚ะพ ะฝะฐ ะฟะฐะบะตั‚ ะต ั‚ั€ะฐะนะฝะพ ะธ ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะพั‚ะผะตะฝะตะฝะพ. +settings.delete.notice = ะะฐ ะฟัŠั‚ ัั‚ะต ะดะฐ ะธะทั‚ั€ะธะตั‚ะต %s (%s). ะขะฐะทะธ ะพะฟะตั€ะฐั†ะธั ะต ะฝะตะพะฑั€ะฐั‚ะธะผะฐ, ัะธะณัƒั€ะฝะธ ะปะธ ัั‚ะต? +owner.settings.cargo.title = ะ˜ะฝะดะตะบั ะฝะฐ ั€ะตะณะธัั‚ัŠั€ะฐ ะฝะฐ Cargo +owner.settings.cargo.initialize = ะ˜ะฝะธั†ะธะฐะปะธะทะธั€ะฐะฝะต ะฝะฐ ะธะฝะดะตะบั +owner.settings.cargo.initialize.description = ะะตะพะฑั…ะพะดะธะผะพ ะต ัะฟะตั†ะธะฐะปะฝะพ Git ั…ั€ะฐะฝะธะปะธั‰ะต ะทะฐ ะธะฝะดะตะบั, ะทะฐ ะดะฐ ัะต ะธะทะฟะพะปะทะฒะฐ ั€ะตะณะธัั‚ัŠั€ัŠั‚ ะฝะฐ Cargo. ะ˜ะทะฟะพะปะทะฒะฐะฝะตั‚ะพ ะฝะฐ ั‚ะฐะทะธ ะพะฟั†ะธั ั‰ะต (ะฟั€ะต)ััŠะทะดะฐะดะต ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะธ ั‰ะต ะณะพ ะบะพะฝั„ะธะณัƒั€ะธั€ะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ. +owner.settings.cargo.initialize.error = ะะตัƒัะฟะตัˆะฝะพ ะธะฝะธั†ะธะฐะปะธะทะธั€ะฐะฝะต ะฝะฐ ะธะฝะดะตะบัะฐ ะฝะฐ Cargo: %v +owner.settings.cargo.initialize.success = ะ˜ะฝะดะตะบััŠั‚ ะฝะฐ Cargo ะฑะตัˆะต ัƒัะฟะตัˆะฝะพ ััŠะทะดะฐะดะตะฝ. +owner.settings.cargo.rebuild = ะŸั€ะตะธะทะณั€ะฐะถะดะฐะฝะต ะฝะฐ ะธะฝะดะตะบั +owner.settings.cargo.rebuild.description = ะŸั€ะตะธะทะณั€ะฐะถะดะฐะฝะตั‚ะพ ะผะพะถะต ะดะฐ ะฑัŠะดะต ะฟะพะปะตะทะฝะพ, ะฐะบะพ ะธะฝะดะตะบััŠั‚ ะฝะต ะต ัะธะฝั…ั€ะพะฝะธะทะธั€ะฐะฝ ััŠั ััŠั…ั€ะฐะฝะตะฝะธั‚ะต Cargo ะฟะฐะบะตั‚ะธ. +owner.settings.cargo.rebuild.error = ะะตัƒัะฟะตัˆะฝะพ ะฟั€ะตะธะทะณั€ะฐะถะดะฐะฝะต ะฝะฐ ะธะฝะดะตะบัะฐ ะฝะฐ Cargo: %v +owner.settings.cargo.rebuild.success = ะ˜ะฝะดะตะบััŠั‚ ะฝะฐ Cargo ะฑะตัˆะต ัƒัะฟะตัˆะฝะพ ะฟั€ะตะธะทะณั€ะฐะดะตะฝ. +owner.settings.cargo.rebuild.no_index = ะะต ะผะพะถะต ะดะฐ ัะต ะฟั€ะตะธะทะณั€ะฐะดะธ, ะฝัะผะฐ ะธะฝะธั†ะธะฐะปะธะทะธั€ะฐะฝ ะธะฝะดะตะบั. +owner.settings.cleanuprules.title = ะŸั€ะฐะฒะธะปะฐ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต +owner.settings.cleanuprules.add = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะฟั€ะฐะฒะธะปะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต +owner.settings.cleanuprules.edit = ะ ะตะดะฐะบั‚ะธั€ะฐะฝะต ะฝะฐ ะฟั€ะฐะฒะธะปะพั‚ะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต +owner.settings.cleanuprules.none = ะ’ัะต ะพั‰ะต ะฝัะผะฐ ะฟั€ะฐะฒะธะปะฐ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต. +owner.settings.cleanuprules.preview = ะŸั€ะตะณะปะตะด ะฝะฐ ะฟั€ะฐะฒะธะปะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต +owner.settings.cleanuprules.preview.overview = %d ะฟะฐะบะตั‚ะฐ ัะฐ ะฝะฐัั€ะพั‡ะตะฝะธ ะทะฐ ะฟั€ะตะผะฐั…ะฒะฐะฝะต. +owner.settings.cleanuprules.preview.none = ะŸั€ะฐะฒะธะปะพั‚ะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต ะฝะต ััŠะฒะฟะฐะดะฐ ั ะฝะธั‚ะพ ะตะดะธะฝ ะฟะฐะบะตั‚. +owner.settings.cleanuprules.enabled = ะ’ะบะปัŽั‡ะตะฝะพ +owner.settings.cleanuprules.pattern_full_match = ะŸั€ะธะปะฐะณะฐะฝะต ะฝะฐ ัˆะฐะฑะปะพะฝะฐ ะบัŠะผ ะฟัŠะปะฝะพั‚ะพ ะธะผะต ะฝะฐ ะฟะฐะบะตั‚ะฐ +owner.settings.cleanuprules.keep.title = ะ’ะตั€ัะธะธั‚ะต, ะบะพะธั‚ะพ ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‚ ะฝะฐ ั‚ะตะทะธ ะฟั€ะฐะฒะธะปะฐ, ัะต ะทะฐะฟะฐะทะฒะฐั‚, ะดะพั€ะธ ะฐะบะพ ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‚ ะฝะฐ ะฟั€ะฐะฒะธะปะพ ะทะฐ ะฟั€ะตะผะฐั…ะฒะฐะฝะต ะฟะพ-ะดะพะปัƒ. +owner.settings.cleanuprules.keep.count = ะ—ะฐะฟะฐะทะฒะฐะฝะต ะฝะฐ ะฝะฐะน-ะฝะพะฒะธั‚ะต +owner.settings.cleanuprules.keep.count.1 = 1 ะฒะตั€ัะธั ะฝะฐ ะฟะฐะบะตั‚ +owner.settings.cleanuprules.keep.count.n = %d ะฒะตั€ัะธะธ ะฝะฐ ะฟะฐะบะตั‚ +owner.settings.cleanuprules.keep.pattern = ะ—ะฐะฟะฐะทะฒะฐะฝะต ะฝะฐ ะฒะตั€ัะธะธ, ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‰ะธ ะฝะฐ +owner.settings.cleanuprules.keep.pattern.container = ะ’ะตั€ัะธัั‚ะฐ latest ะฒะธะฝะฐะณะธ ัะต ะทะฐะฟะฐะทะฒะฐ ะทะฐ Container ะฟะฐะบะตั‚ะธ. +owner.settings.cleanuprules.remove.title = ะ’ะตั€ัะธะธั‚ะต, ะบะพะธั‚ะพ ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‚ ะฝะฐ ั‚ะตะทะธ ะฟั€ะฐะฒะธะปะฐ, ัะต ะฟั€ะตะผะฐั…ะฒะฐั‚, ะพัะฒะตะฝ ะฐะบะพ ะฟั€ะฐะฒะธะปะพ ะฟะพ-ะณะพั€ะต ะฝะต ะบะฐะทะฒะฐ ะดะฐ ัะต ะทะฐะฟะฐะทัั‚. +owner.settings.cleanuprules.remove.days = ะŸั€ะตะผะฐั…ะฒะฐะฝะต ะฝะฐ ะฒะตั€ัะธะธ, ะฟะพ-ัั‚ะฐั€ะธ ะพั‚ +owner.settings.cleanuprules.remove.pattern = ะŸั€ะตะผะฐั…ะฒะฐะฝะต ะฝะฐ ะฒะตั€ัะธะธ, ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‰ะธ ะฝะฐ +owner.settings.cleanuprules.success.update = ะŸั€ะฐะฒะธะปะพั‚ะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต ะต ะพะฑะฝะพะฒะตะฝะพ. +owner.settings.cleanuprules.success.delete = ะŸั€ะฐะฒะธะปะพั‚ะพ ะทะฐ ะฟะพั‡ะธัั‚ะฒะฐะฝะต ะต ะธะทั‚ั€ะธั‚ะพ. +owner.settings.chef.title = ะ ะตะณะธัั‚ัŠั€ ะฝะฐ Chef +owner.settings.chef.keypair = ะ“ะตะฝะตั€ะธั€ะฐะฝะต ะฝะฐ ะดะฒะพะนะบะฐ ะบะปัŽั‡ะพะฒะต +owner.settings.chef.keypair.description = ะ—ะฐัะฒะบะธั‚ะต, ะธะทะฟั€ะฐั‚ะตะฝะธ ะดะพ ั€ะตะณะธัั‚ัŠั€ะฐ ะฝะฐ Chef, ั‚ั€ัะฑะฒะฐ ะดะฐ ะฑัŠะดะฐั‚ ะบั€ะธะฟั‚ะพะณั€ะฐั„ัะบะธ ะฟะพะดะฟะธัะฐะฝะธ ะบะฐั‚ะพ ัั€ะตะดัั‚ะฒะพ ะทะฐ ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต. ะŸั€ะธ ะณะตะฝะตั€ะธั€ะฐะฝะต ะฝะฐ ะดะฒะพะนะบะฐ ะบะปัŽั‡ะพะฒะต, ัะฐะผะพ ะฟัƒะฑะปะธั‡ะฝะธัั‚ ะบะปัŽั‡ ัะต ััŠั…ั€ะฐะฝัะฒะฐ ะฒัŠะฒ Forgejo. ะงะฐัั‚ะฝะธัั‚ ะบะปัŽั‡ ะฒะธ ัะต ะฟั€ะตะดะพัั‚ะฐะฒั, ะทะฐ ะดะฐ ัะต ะธะทะฟะพะปะทะฒะฐ ั knife. ะ“ะตะฝะตั€ะธั€ะฐะฝะตั‚ะพ ะฝะฐ ะฝะพะฒะฐ ะดะฒะพะนะบะฐ ะบะปัŽั‡ะพะฒะต ั‰ะต ะฟั€ะตะทะฐะฟะธัˆะต ะฟั€ะตะดะธัˆะฝะฐั‚ะฐ. [tool] hours = %d ั‡ะฐัะฐ @@ -613,6 +631,7 @@ release.source_code = ะŸั€ะพะณั€ะฐะผะตะฝ ะบะพะด settings = ะะฐัั‚ั€ะพะนะบะธ forks = ะ ะฐะทะบะปะพะฝะตะฝะธั editor.or = ะธะปะธ +search = ะขัŠั€ัะตะฝะต issues.new_label_desc_placeholder = ะžะฟะธัะฐะฝะธะต watch_guest_user = ะ’ะปะตะทั‚ะต, ะทะฐ ะดะฐ ะฝะฐะฑะปัŽะดะฐะฒะฐั‚ะต ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต. migrate_items_milestones = ะ•ั‚ะฐะฟะธ @@ -655,6 +674,7 @@ pulls.made_using_agit = AGit issues.num_comments = %d ะบะพะผะตะฝั‚ะฐั€ะฐ issues.filter_sort.leastcomment = ะะฐะน-ะผะฐะปะบะพ ะบะพะผะตะฝั‚ะธั€ะฐะฝะธ issues.filter_sort.mostcomment = ะะฐะน-ะผะฝะพะณะพ ะบะพะผะตะฝั‚ะธั€ะฐะฝะธ +issues.keyword_search_unavailable = ะ’ ะผะพะผะตะฝั‚ะฐ ั‚ัŠั€ัะตะฝะตั‚ะพ ะฟะพ ะบะปัŽั‡ะพะฒะฐ ะดัƒะผะฐ ะฝะต ะต ะฝะฐะปะธั‡ะฝะพ. ะœะพะปั, ัะฒัŠั€ะถะตั‚ะต ัะต ั ะฒะฐัˆะธั ะฐะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€ ะฝะฐ ัะฐะนั‚ะฐ. repo_desc_helper = ะ’ัŠะฒะตะดะตั‚ะต ะบั€ะฐั‚ะบะพ ะพะฟะธัะฐะฝะธะต (ะพะฟั†ะธะพะฝะฐะปะฝะพ) mirror_address = ะšะปะพะฝะธั€ะฐะฝะต ะพั‚ URL owner_helper = ะัะบะพะธ ะพั€ะณะฐะฝะธะทะฐั†ะธะธ ะผะพะถะต ะดะฐ ะฝะต ัะต ะฟะพะบะฐะทะฒะฐั‚ ะฒ ะฟะฐะดะฐั‰ะพั‚ะพ ะผะตะฝัŽ ะฟะพั€ะฐะดะธ ะพะณั€ะฐะฝะธั‡ะตะฝะธะต ะทะฐ ะผะฐะบัะธะผะฐะปะตะฝ ะฑั€ะพะน ั…ั€ะฐะฝะธะปะธั‰ะฐ. @@ -671,6 +691,7 @@ readme = README migrate.clone_address = ะœะธะณั€ะธั€ะฐะฝะต / ะšะปะพะฝะธั€ะฐะฝะต ะพั‚ URL migrated_from_fake = ะœะธะณั€ะธั€ะฐะฝะพ ะพั‚ %[1]s migrate.migrate = ะœะธะณั€ะธั€ะฐะฝะต ะพั‚ %s +settings.search_user_placeholder = ะŸะพั‚ัŠั€ัะตั‚ะต ะฟะพั‚ั€ะตะฑะธั‚ะตะปโ€ฆ issues.new_label = ะะพะฒ ะตั‚ะธะบะตั‚ issues.new_label_placeholder = ะ˜ะผะต ะฝะฐ ะตั‚ะธะบะตั‚ะฐ issues.label_count = %d ะตั‚ะธะบะตั‚ะฐ @@ -770,6 +791,7 @@ activity.title.issues_n = %d ะทะฐะดะฐั‡ะธ wiki.pages = ะกั‚ั€ะฐะฝะธั†ะธ activity.git_stats_author_1 = %d ะฐะฒั‚ะพั€ activity.git_stats_and_deletions = ะธ +project_board = ะŸั€ะพะตะบั‚ะธ wiki.save_page = ะ—ะฐะฟะฐะทะฒะฐะฝะต ะฝะฐ ัั‚ั€ะฐะฝะธั†ะฐั‚ะฐ activity.git_stats_author_n = %d ะฐะฒั‚ะพั€ะธ wiki.delete_page_button = ะ˜ะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ัั‚ั€ะฐะฝะธั†ะฐั‚ะฐ @@ -832,6 +854,8 @@ repo_size = ะ ะฐะทะผะตั€ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ settings.danger_zone = ะžะฟะฐัะฝะฐ ะทะพะฝะฐ issues.closed_by = ะพั‚ %[3]s ะฑะต ะทะฐั‚ะฒะพั€ะตะฝะฐ %[1]s issues.delete_comment_confirm = ะกะธะณัƒั€ะฝะธ ะปะธ ัั‚ะต, ั‡ะต ะธัะบะฐั‚ะต ะดะฐ ะธะทั‚ั€ะธะตั‚ะต ั‚ะพะทะธ ะบะพะผะตะฝั‚ะฐั€? +issues.author_helper = ะขะพะทะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะป ะต ะฐะฒั‚ะพั€ัŠั‚. +issues.ref_closed_from = `ะทะฐั‚ะฒะพั€ะธ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ %[4]s %[2]s` milestones.due_date = ะšั€ะฐะตะฝ ัั€ะพะบ (ะพะฟั†ะธะพะฝะฐะปะฝะพ) settings.wiki_delete_notices_1 = - ะขะพะฒะฐ ั‰ะต ะธะทั‚ั€ะธะต ะฟะตั€ะผะฐะฝะตะฝั‚ะฝะพ ะธ ั‰ะต ะดะตะฐะบั‚ะธะฒะธั€ะฐ ัƒะธะบะธั‚ะพ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ %s. settings.wiki_deletion_success = ะ”ะฐะฝะฝะธั‚ะต ะฝะฐ ัƒะธะบะธั‚ะพ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ัะฐ ะธะทั‚ั€ะธั‚ะธ. @@ -877,12 +901,14 @@ pulls.reopened_at = `ะพั‚ะฒะพั€ะธ ะฝะฐะฝะพะฒะพ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธ issues.reopened_at = `ะพั‚ะฒะพั€ะธ ะฝะฐะฝะพะฒะพ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ %s` projects.column.edit = ะ ะตะดะฐะบั‚ะธั€ะฐะฝะต ะฝะฐ ะบะพะปะพะฝะฐั‚ะฐ issues.close = ะ—ะฐั‚ะฒะฐั€ัะฝะต ะฝะฐ ะทะฐะดะฐั‡ะฐั‚ะฐ +issues.ref_reopened_from = `ะพั‚ะฒะพั€ะธ ะฝะฐะฝะพะฒะพ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ %[4]s %[2]s` projects.deletion = ะ˜ะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ะฟั€ะพะตะบั‚ะฐ projects.edit_success = ะŸั€ะพะตะบั‚ัŠั‚ โ€ž%sโ€œ ะต ะพะฑะฝะพะฒะตะฝ. projects.deletion_success = ะŸั€ะพะตะบั‚ัŠั‚ ะต ะธะทั‚ั€ะธั‚. issues.create_comment = ะšะพะผะตะฝั‚ะธั€ะฐะฝะต unescape_control_characters = ะžั‚ะตะบั€ะฐะฝะธั€ะฐะฝะต editor.file_delete_success = ะคะฐะนะปัŠั‚ โ€ž%sโ€œ ะต ะธะทั‚ั€ะธั‚. +projects.type.uncategorized = ะะตะบะฐั‚ะตะณะพั€ะธะทะธั€ะฐะฝะพ projects.column.set_default = ะ—ะฐะดะฐะฒะฐะฝะต ะฟะพ ะฟะพะดั€ะฐะทะฑะธั€ะฐะฝะต projects.column.assigned_to = ะ’ัŠะทะปะพะถะตะฝะพ ะฝะฐ issues.reopen_comment_issue = ะžั‚ะฒะฐั€ัะฝะต ะฝะฐะฝะพะฒะพ ั ะบะพะผะตะฝั‚ะฐั€ @@ -967,12 +993,14 @@ editor.filename_cannot_be_empty = ะ˜ะผะตั‚ะพ ะฝะฐ ั„ะฐะนะปะฐ ะฝะต ะผะพะถะต ะดะฐ release.title_empty = ะ—ะฐะณะปะฐะฒะธะตั‚ะพ ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะฟั€ะฐะทะฝะพ. settings.webhook.payload = ะกัŠะดัŠั€ะถะฐะฝะธะต settings.deploy_key_content = ะกัŠะดัŠั€ะถะฐะฝะธะต +clone_in_vsc = ะšะปะพะฝะธั€ะฐะฝะต ะฒัŠะฒ VS Code use_template = ะ˜ะทะฟะพะปะทะฒะฐะฝะต ะฝะฐ ั‚ะพะทะธ ัˆะฐะฑะปะพะฝ download_file = ะ˜ะทั‚ะตะณะปัะฝะต ะฝะฐ ั„ะฐะนะปะฐ editor.add_file = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ั„ะฐะนะป editor.edit_file = ะ ะตะดะฐะบั‚ะธั€ะฐะฝะต ะฝะฐ ั„ะฐะนะปะฐ editor.this_file_locked = ะคะฐะนะปัŠั‚ ะต ะทะฐะบะปัŽั‡ะตะฝ editor.delete_this_file = ะ˜ะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ั„ะฐะนะปะฐ +clone_in_vscodium = ะšะปะพะฝะธั€ะฐะฝะต ะฒัŠะฒ VSCodium download_zip = ะ˜ะทั‚ะตะณะปัะฝะต ะฝะฐ ZIP download_tar = ะ˜ะทั‚ะตะณะปัะฝะต ะฝะฐ TAR.GZ desc.public = ะŸัƒะฑะปะธั‡ะฝะพ @@ -1053,6 +1081,7 @@ issues.lock.reason = ะŸั€ะธั‡ะธะฝะฐ ะทะฐ ะทะฐะบะปัŽั‡ะฒะฐะฝะตั‚ะพ pulls.create = ะกัŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต issues.label.filter_sort.reverse_by_size = ะะฐะน-ะณะพะปัะผ ั€ะฐะทะผะตั€ issues.unlock = ะžั‚ะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะพะฑััŠะถะดะฐะฝะตั‚ะพ +issues.due_date_form_add = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะบั€ะฐะตะฝ ัั€ะพะบ release.save_draft = ะ—ะฐะฟะฐะทะฒะฐะฝะต ะฝะฐ ั‡ะตั€ะฝะพะฒะฐ release.add_tag = ะกัŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะผะฐั€ะบะตั€ release.publish = ะŸัƒะฑะปะธะบัƒะฒะฐะฝะต ะฝะฐ ะธะทะดะฐะฝะธะต @@ -1105,7 +1134,9 @@ editor.fail_to_update_file_summary = ะกัŠะพะฑั‰ะตะฝะธะต ะทะฐ ะณั€ะตัˆะบะฐ: editor.fail_to_update_file = ะะตัƒัะฟะตัˆะฝะพ ะพะฑะฝะพะฒัะฒะฐะฝะต/ััŠะทะดะฐะฒะฐะฝะต ะฝะฐ ั„ะฐะนะป โ€ž%sโ€œ. editor.add_subdir = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะดะธั€ะตะบั‚ะพั€ะธัโ€ฆ commits.commits = ะŸะพะดะฐะฒะฐะฝะธั +commits.find = ะขัŠั€ัะตะฝะต commits.search_all = ะ’ัะธั‡ะบะธ ะบะปะพะฝะพะฒะต +commits.search = ะŸะพั‚ัŠั€ัะตั‚ะต ะฟะพะดะฐะฒะฐะฝะธัโ€ฆ commit.operations = ะžะฟะตั€ะฐั†ะธะธ issues.deleted_milestone = `(ะธะทั‚ั€ะธั‚)` issues.deleted_project = `(ะธะทั‚ั€ะธั‚)` @@ -1134,11 +1165,13 @@ activity.git_stats_push_to_all_branches = ะบัŠะผ ะฒัะธั‡ะบะธ ะบะปะพะฝะพะฒะต. release.deletion_tag_success = ะœะฐั€ะบะตั€ัŠั‚ ะต ะธะทั‚ั€ะธั‚. release.cancel = ะžั‚ะบะฐะท release.deletion = ะ˜ะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ะธะทะดะฐะฝะธะตั‚ะพ +release.download_count = ะ˜ะทั‚ะตะณะปัะฝะธั: %s release.tag_name_invalid = ะ˜ะผะตั‚ะพ ะฝะฐ ะผะฐั€ะบะตั€ะฐ ะฝะต ะต ะฒะฐะปะธะดะฝะพ. diff.stats_desc = %d ะฟั€ะพะผะตะฝะตะฝะธ ั„ะฐะนะปะฐ ั %d ะดะพะฑะฐะฒัะฝะธั ะธ %d ะธะทั‚ั€ะธะฒะฐะฝะธั release.tag_name_already_exist = ะ’ะตั‡ะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ ะธะทะดะฐะฝะธะต ั ั‚ะพะฒะฐ ะธะผะต ะฝะฐ ะผะฐั€ะบะตั€. branch.branch_already_exists = ะšะปะพะฝัŠั‚ โ€ž%sโ€œ ะฒะตั‡ะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ ะฒ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต. diff.download_patch = ะ˜ะทั‚ะตะณะปัะฝะต ะฝะฐ ั„ะฐะนะป-ะบั€ัŠะฟะบะฐ +diff.show_diff_stats = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ัั‚ะฐั‚ะธัั‚ะธะบะฐ diff.commit = ะฟะพะดะฐะฒะฐะฝะต diff.download_diff = ะ˜ะทั‚ะตะณะปัะฝะต ะฝะฐ ั„ะฐะนะป-ั€ะฐะทะปะธะบะธ diff.whitespace_show_everything = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ะฒัะธั‡ะบะธ ะฟั€ะพะผะตะฝะธ @@ -1153,11 +1186,12 @@ issues.push_commit_1 = ะดะพะฑะฐะฒะธ %d ะฟะพะดะฐะฒะฐะฝะต %s fork_visibility_helper = ะ’ะธะดะธะผะพัั‚ั‚ะฐ ะฝะฐ ั€ะฐะทะบะปะพะฝะตะฝะพ ั…ั€ะฐะฝะธะปะธั‰ะต ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะฟั€ะพะผะตะฝะตะฝะฐ. language_other = ะ”ั€ัƒะณะธ stars_remove_warning = ะขะพะฒะฐ ั‰ะต ะฟั€ะตะผะฐั…ะฝะต ะฒัะธั‡ะบะธ ะทะฒะตะทะดะธ ะพั‚ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต. -tree_path_not_found.tag = ะŸัŠั‚ัั‚ %[1]s ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ ะฒ ะผะฐั€ะบะตั€ %[2]s -tree_path_not_found.commit = ะŸัŠั‚ัั‚ %[1]s ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ ะฒ ะฟะพะดะฐะฒะฐะฝะต %[2]s -tree_path_not_found.branch = ะŸัŠั‚ัั‚ %[1]s ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ ะฒ ะบะปะพะฝ %[2]s +tree_path_not_found_tag = ะŸัŠั‚ัั‚ %[1]s ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ ะฒ ะผะฐั€ะบะตั€ %[2]s +tree_path_not_found_commit = ะŸัŠั‚ัั‚ %[1]s ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ ะฒ ะฟะพะดะฐะฒะฐะฝะต %[2]s +tree_path_not_found_branch = ะŸัŠั‚ัั‚ %[1]s ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ ะฒ ะบะปะพะฝ %[2]s transfer.accept = ะŸั€ะธะตะผะฐะฝะต ะฝะฐ ะฟั€ะตั…ะฒัŠั€ะปัะฝะตั‚ะพ transfer.reject = ะžั‚ั…ะฒัŠั€ะปัะฝะต ะฝะฐ ะฟั€ะตั…ะฒัŠั€ะปัะฝะตั‚ะพ +archive.issue.nocomment = ะขะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต ะต ะฐั€ั…ะธะฒะธั€ะฐะฝะพ. ะะต ะผะพะถะตั‚ะต ะดะฐ ะบะพะผะตะฝั‚ะธั€ะฐั‚ะต ะฒ ะทะฐะดะฐั‡ะธั‚ะต. forked_from = ั€ะฐะทะบะปะพะฝะตะฝะพ ะพั‚ issues.delete_branch_at = `ะธะทั‚ั€ะธ ะบะปะพะฝะฐ %s %s` pulls.has_viewed_file = ะŸั€ะตะณะปะตะดะฐะฝะพ @@ -1193,6 +1227,7 @@ branch.delete_html = ะ˜ะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ะบะปะพะฝะฐ tag.create_success = ะœะฐั€ะบะตั€ัŠั‚ โ€ž%sโ€œ ะต ััŠะทะดะฐะดะตะฝ. branch.new_branch_from = ะกัŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะฝะพะฒ ะบะปะพะฝ ะพั‚ โ€ž%sโ€œ branch.new_branch = ะกัŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะฝะพะฒ ะบะปะพะฝ +branch.confirm_rename_branch = ะŸั€ะตะธะผะตะฝัƒะฒะฐะฝะต ะฝะฐ ะบะปะพะฝะฐ branch.create_from = ะพั‚ โ€ž%sโ€œ settings.add_team_duplicate = ะ•ะบะธะฟัŠั‚ ะฒะตั‡ะต ั€ะฐะทะฟะพะปะฐะณะฐ ั ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต settings.slack_domain = ะ”ะพะผะตะนะฝ @@ -1218,6 +1253,7 @@ branch.deletion_failed = ะะตัƒัะฟะตัˆะฝะพ ะธะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ะบะปะพะฝะฐ branch.rename_branch_to = ะŸั€ะตะธะผะตะฝัƒะฒะฐะฝะต ะพั‚ โ€ž%sโ€œ ะฝะฐ: settings.web_hook_name_msteams = Microsoft Teams settings.web_hook_name_dingtalk = DingTalk +issues.error_removing_due_date = ะะตัƒัะฟะตัˆะฝะพ ะฟั€ะตะผะฐั…ะฒะฐะฝะต ะฝะฐ ะบั€ะฐะนะฝะธั ัั€ะพะบ. branch.renamed = ะšะปะพะฝัŠั‚ %s ะต ะฟั€ะตะธะผะตะฝัƒะฒะฐะฝ ะฝะฐ %s. settings.teams = ะ•ะบะธะฟะธ settings.add_team = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะตะบะธะฟ @@ -1231,6 +1267,8 @@ branch.download = ะ˜ะทั‚ะตะณะปัะฝะต ะฝะฐ ะบะปะพะฝะฐ โ€ž%sโ€œ branch.rename = ะŸั€ะตะธะผะตะฝัƒะฒะฐะฝะต ะฝะฐ ะบะปะพะฝะฐ โ€ž%sโ€œ empty_message = ะ’ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต ะฝัะผะฐ ััŠะดัŠั€ะถะฐะฝะธะต. open_with_editor = ะžั‚ะฒะฐั€ัะฝะต ั %s +search.search_repo = ะขัŠั€ัะตะฝะต ะฒ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ +search.results = ะ ะตะทัƒะปั‚ะฐั‚ะธ ะพั‚ ั‚ัŠั€ัะตะฝะตั‚ะพ ะฝะฐ "%s" ะฒ %s object_format = ะคะพั€ะผะฐั‚ ะฝะฐ ะพะฑะตะบั‚ะธั‚ะต release.releases_for = ะ˜ะทะดะฐะฝะธั ะทะฐ %s release.tags_for = ะœะฐั€ะบะตั€ะธ ะทะฐ %s @@ -1238,10 +1276,12 @@ pulls.cmd_instruction_hint = ะ’ะธะถั‚ะต ะธะฝัั‚ั€ัƒะบั†ะธะธั‚ะต ะทะฐ ะบะพะผะฐะฝ pulls.showing_only_single_commit = ะŸะพะบะฐะทะฐะฝะธ ัะฐ ัะฐะผะพ ะฟั€ะพะผะตะฝะธั‚ะต ะฒ ะฟะพะดะฐะฒะฐะฝะต %[1]s issues.lock_no_reason = ะทะฐะบะปัŽั‡ะธ ะธ ะพะณั€ะฐะฝะธั‡ะธ ะพะฑััŠะถะดะฐะฝะตั‚ะพ ะดะพ ััŠั‚ั€ัƒะดะฝะธั†ะธ %s pulls.expand_files = ะ ะฐะทะณัŠะฒะฐะฝะต ะฝะฐ ะฒัะธั‡ะบะธ ั„ะฐะนะปะพะฒะต +pulls.title_desc_few = ะธัะบะฐ ะดะฐ ัะปะตะต %[1]d ะฟะพะดะฐะฒะฐะฝะธั ะพั‚ %[2]s ะฒ %[3]s issues.content_history.deleted = ะธะทั‚ั€ะธั‚ะพ activity.git_stats_exclude_merges = ะก ะธะทะบะปัŽั‡ะตะฝะธะต ะฝะฐ ัะปะธะฒะฐะฝะธัั‚ะฐ, activity.navbar.pulse = ะŸะพัะปะตะดะฝะฐ ะดะตะนะฝะพัั‚ activity.no_git_activity = ะะต ะต ะธะผะฐะปะพ ะฝะธะบะฐะบะฒะฐ ะดะตะนะฝะพัั‚ ั ะฟะพะดะฐะฒะฐะฝะธั ะฟั€ะตะท ั‚ะพะทะธ ะฟะตั€ะธะพะด. +pulls.merged_title_desc_few = ัะปั %[1]d ะฟะพะดะฐะฒะฐะฝะธั ะพั‚ %[2]s ะฒ %[3]s %[4]s diff.stats_desc_file = %d ะฟั€ะพะผะตะฝะธ: %d ะดะพะฑะฐะฒัะฝะธั ะธ %d ะธะทั‚ั€ะธะฒะฐะฝะธั issues.content_history.created = ััŠะทะดะฐะดะตะฝะพ pulls.status_checks_success = ะ’ัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ @@ -1256,7 +1296,9 @@ pulls.collapse_files = ะกะฒะธะฒะฐะฝะต ะฝะฐ ะฒัะธั‡ะบะธ ั„ะฐะนะปะพะฒะต pulls.show_all_commits = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ะฒัะธั‡ะบะธ ะฟะพะดะฐะฒะฐะฝะธั diff.whitespace_button = ะŸั€ะฐะทะฝะธ ะทะฝะฐั†ะธ issues.content_history.edited = ั€ะตะดะฐะบั‚ะธั€ะฐะฝะพ +pulls.title_desc_one = ะธัะบะฐ ะดะฐ ัะปะตะต %[1]d ะฟะพะดะฐะฒะฐะฝะต ะพั‚ %[2]s ะฒ %[3]s pulls.showing_specified_commit_range = ะŸะพะบะฐะทะฐะฝะธ ัะฐ ัะฐะผะพ ะฟั€ะพะผะตะฝะธั‚ะต ะผะตะถะดัƒ %[1]s..%[2]s +pulls.merged_title_desc_one = ัะปั %[1]d ะฟะพะดะฐะฒะฐะฝะต ะพั‚ %[2]s ะฒ %[3]s %[4]s pulls.no_merge_access = ะะต ัั‚ะต ัƒะฟัŠะปะฝะพะผะพั‰ะตะฝะธ ะดะฐ ัะปะตะตั‚ะต ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต. activity.navbar.code_frequency = ะงะตัั‚ะพั‚ะฐ ะฝะฐ ะฟั€ะพะผะตะฝะธั‚ะต activity.git_stats_pushed_1 = ะต ะธะทั‚ะปะฐัะบะฐะป @@ -1297,6 +1339,7 @@ issues.dependency.issue_close_blocked = ะขั€ัะฑะฒะฐ ะดะฐ ะทะฐั‚ะฒะพั€ะธั‚ะต ะฒ issues.dependency.blocks_short = ะ‘ะปะพะบะธั€ะฐ issues.dependency.remove_header = ะŸั€ะตะผะฐั…ะฒะฐะฝะต ะฝะฐ ะทะฐะฒะธัะธะผะพัั‚ issues.dependency.issue_remove_text = ะขะพะฒะฐ ั‰ะต ะฟั€ะตะผะฐั…ะฝะต ะทะฐะฒะธัะธะผะพัั‚ั‚ะฐ ะพั‚ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ. ะŸั€ะพะดัŠะปะถะฐะฒะฐะฝะต? +issues.reference_link = ะŸั€ะตะฟั€ะฐั‚ะบะฐ: %s pulls.closed = ะ—ะฐัะฒะบะฐั‚ะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะต ะทะฐั‚ะฒะพั€ะตะฝะฐ pulls.merged_success = ะ—ะฐัะฒะบะฐั‚ะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะต ัƒัะฟะตัˆะฝะพ ัะปัั‚ะฐ ะธ ะทะฐั‚ะฒะพั€ะตะฝะฐ branch.confirm_create_branch = ะกัŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะบะปะพะฝ @@ -1366,6 +1409,7 @@ issues.new.no_reviewers = ะัะผะฐ ั€ะตั†ะตะฝะทะตะฝั‚ะธ issues.filter_reviewers = ะคะธะปั‚ั€ะธั€ะฐะฝะต ะฝะฐ ั€ะตั†ะตะฝะทะตะฝั‚ issues.filter_type.reviewed_by_you = ะ ะตั†ะตะฝะทะธั€ะฐะฝะธ ะพั‚ ะฒะฐั issues.filter_type.review_requested = ะŸะพะธัะบะฐะฝะธ ั€ะตั†ะตะฝะทะธะธ +issues.review.review = ะ ะตั†ะตะฝะทะธั issues.review.comment = ั€ะตั†ะตะฝะทะธั€ะฐ %s branch.deleted_by = ะ˜ะทั‚ั€ะธั‚ ะพั‚ %s branch.restore = ะ’ัŠะทัั‚ะฐะฝะพะฒัะฒะฐะฝะต ะฝะฐ ะบะปะพะฝะฐ โ€ž%sโ€œ @@ -1549,16 +1593,20 @@ migrate.migrating_topics = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ั‚ะตะผะธ projects.desc = ะฃะฟั€ะฐะฒะปัะฒะฐะนั‚ะต ะทะฐะดะฐั‡ะธ ะธ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต ะฒ ะฟั€ะพะตะบั‚ะฝะธ ั‚ะฐะฑะปะฐ. issues.choose.invalid_templates = %v ะฝะตะฒะฐะปะธะดะฝะธ ัˆะฐะฑะปะพะฝะฐ ัะฐ ะฝะฐะผะตั€ะตะฝะธ pulls.edit.already_changed = ะะตัƒัะฟะตัˆะฝะพ ะทะฐะฟะฐะทะฒะฐะฝะต ะฝะฐ ะฟั€ะพะผะตะฝะธั‚ะต ะฒ ะทะฐัะฒะบะฐั‚ะฐ ะทะฐ ัะปะธะฒะฐะฝะต. ะ˜ะทะณะปะตะถะดะฐ ััŠะดัŠั€ะถะฐะฝะธะตั‚ะพ ะฒะตั‡ะต ะต ะฟั€ะพะผะตะฝะตะฝะพ ะพั‚ ะดั€ัƒะณ ะฟะพั‚ั€ะตะฑะธั‚ะตะป. ะœะพะปั, ะฟั€ะตะทะฐั€ะตะดะตั‚ะต ัั‚ั€ะฐะฝะธั†ะฐั‚ะฐ ะธ ะพะฟะธั‚ะฐะนั‚ะต ะดะฐ ั€ะตะดะฐะบั‚ะธั€ะฐั‚ะต ะพั‚ะฝะพะฒะพ, ะทะฐ ะดะฐ ะธะทะฑะตะณะฝะตั‚ะต ะฟั€ะตะทะฐะฟะธัะฒะฐะฝะตั‚ะพ ะฝะฐ ั‚ะตั…ะฝะธั‚ะต ะฟั€ะพะผะตะฝะธ +migrate.gitbucket.description = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะดะฐะฝะฝะธ ะพั‚ GitBucket ะธะฝัั‚ะฐะฝั†ะธะธ. migrate.migrating_git = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ Git ะดะฐะฝะฝะธ commits.newer = ะŸะพ-ะฝะพะฒะธ issues.choose.blank_about = ะกัŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะทะฐะดะฐั‡ะฐ ะพั‚ ัั‚ะฐะฝะดะฐั€ั‚ะตะฝ ัˆะฐะฑะปะพะฝ. issues.filter_no_results = ะัะผะฐ ั€ะตะทัƒะปั‚ะฐั‚ะธ issues.filter_no_results_placeholder = ะžะฟะธั‚ะฐะนั‚ะต ะดะฐ ะบะพั€ะธะณะธั€ะฐั‚ะต ั„ะธะปั‚ั€ะธั‚ะต ัะธ ะทะฐ ั‚ัŠั€ัะตะฝะต. archive.nocomment = ะšะพะผะตะฝั‚ะธั€ะฐะฝะตั‚ะพ ะฝะต ะต ะฒัŠะทะผะพะถะฝะพ, ั‚ัŠะน ะบะฐั‚ะพ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะต ะฐั€ั…ะธะฒะธั€ะฐะฝะพ. +migrate.gitlab.description = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะดะฐะฝะฝะธ ะพั‚ gitlab.com ะธะปะธ ะดั€ัƒะณะธ GitLab ะธะฝัั‚ะฐะฝั†ะธะธ. transfer.no_permission_to_accept = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ะฟั€ะธะตะผะตั‚ะต ั‚ะพะฒะฐ ะฟั€ะตั…ะฒัŠั€ะปัะฝะต. transfer.no_permission_to_reject = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ะพั‚ั…ะฒัŠั€ะปะธั‚ะต ั‚ะพะฒะฐ ะฟั€ะตั…ะฒัŠั€ะปัะฝะต. editor.file_changed_while_editing = ะกัŠะดัŠั€ะถะฐะฝะธะตั‚ะพ ะฝะฐ ั„ะฐะนะปะฐ ะต ะฟั€ะพะผะตะฝะตะฝะพ, ะพั‚ะบะฐะบั‚ะพ ัั‚ะต ะณะพ ะพั‚ะฒะพั€ะธะปะธ. ะฉั€ะฐะบะฝะตั‚ะต ั‚ัƒะบ, ะทะฐ ะดะฐ ะณะพ ะฒะธะดะธั‚ะต, ะธะปะธ ะŸะพะดะฐะนั‚ะต ะฟั€ะพะผะตะฝะธั‚ะต ะพั‚ะฝะพะฒะพ, ะทะฐ ะดะฐ ะณะธ ะฟั€ะตะทะฐะฟะธัˆะตั‚ะต. sync_fork.button = ะกะธะฝั…ั€ะพะฝะธะทะธั€ะฐะฝะต +migrate.onedev.description = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะดะฐะฝะฝะธ ะพั‚ code.onedev.io ะธะปะธ ะดั€ัƒะณะธ OneDev ะธะฝัั‚ะฐะฝั†ะธะธ. +migrate.codebase.description = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะดะฐะฝะฝะธ ะพั‚ codebasehq.com. migrate.migrating_labels = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะตั‚ะธะบะตั‚ะธ migrate.migrating_releases = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะธะทะดะฐะฝะธั editor.push_rejected_no_message = ะŸั€ะพะผัะฝะฐั‚ะฐ ะฑะตัˆะต ะพั‚ั…ะฒัŠั€ะปะตะฝะฐ ะพั‚ ััŠั€ะฒัŠั€ะฐ ะฑะตะท ััŠะพะฑั‰ะตะฝะธะต. ะœะพะปั, ะฟั€ะพะฒะตั€ะตั‚ะต Git ะบัƒะบะธั‚ะต. @@ -1579,6 +1627,7 @@ editor.cannot_commit_to_protected_branch = ะะต ะผะพะถะต ะดะฐ ัะต ะฟะพะดะฐะฒะฐ editor.no_commit_to_branch = ะะต ะผะพะถะต ะดะฐ ัะต ะฟะพะดะฐะฒะฐ ะดะธั€ะตะบั‚ะฝะพ ะฒ ะบะปะพะฝะฐ, ะทะฐั‰ะพั‚ะพ: editor.push_rejected = ะŸั€ะพะผัะฝะฐั‚ะฐ ะฑะตัˆะต ะพั‚ั…ะฒัŠั€ะปะตะฝะฐ ะพั‚ ััŠั€ะฒัŠั€ะฐ. ะœะพะปั, ะฟั€ะพะฒะตั€ะตั‚ะต Git ะบัƒะบะธั‚ะต. cite_this_repo = ะฆะธั‚ะธั€ะฐะฝะต ะฝะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต +migrate.gitea.description = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะดะฐะฝะฝะธ ะพั‚ gitea.com ะธะปะธ ะดั€ัƒะณะธ Gitea ะธะฝัั‚ะฐะฝั†ะธะธ. editor.push_rejected_summary = ะŸัŠะปะฝะพ ััŠะพะฑั‰ะตะฝะธะต ะฝะฐ ะพั‚ั…ะฒัŠั€ะปัะฝะตั‚ะพ: sync_fork.branch_behind_one = ะขะพะทะธ ะบะปะพะฝ ะต %[1]d ะฟะพะดะฐะฒะฐะฝะต ะทะฐะด %[2]s sync_fork.branch_behind_few = ะขะพะทะธ ะบะปะพะฝ ะต %[1]d ะฟะพะดะฐะฒะฐะฝะธั ะทะฐะด %[2]s @@ -1587,6 +1636,9 @@ editor.commit_id_not_matching = ะคะฐะนะปัŠั‚ ะต ะฟั€ะพะผะตะฝะตะฝ, ะดะพะบะฐั‚ะพ editor.user_no_push_to_branch = ะŸะพั‚ั€ะตะฑะธั‚ะตะปัั‚ ะฝะต ะผะพะถะต ะดะฐ ะธะทั‚ะปะฐัะบะฒะฐ ะฒ ะบะปะพะฝะฐ archive.pull.noreview = ะขะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต ะต ะฐั€ั…ะธะฒะธั€ะฐะฝะพ. ะะต ะผะพะถะตั‚ะต ะดะฐ ั€ะตั†ะตะฝะทะธั€ะฐั‚ะต ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต. migrate.migrating_failed.error = ะะตัƒัะฟะตัˆะฝะพ ะผะธะณั€ะธั€ะฐะฝะต: %s +migrate.github.description = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะดะฐะฝะฝะธ ะพั‚ github.com ะธะปะธ GitHub Enterprise ััŠั€ะฒัŠั€. +migrate.forgejo.description = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะดะฐะฝะฝะธ ะพั‚ codeberg.org ะธะปะธ ะดั€ัƒะณะธ Forgejo ะธะฝัั‚ะฐะฝั†ะธะธ. +migrate.gogs.description = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะดะฐะฝะฝะธ ะพั‚ notabug.org ะธะปะธ ะดั€ัƒะณะธ Gogs ะธะฝัั‚ะฐะฝั†ะธะธ. migrate.migrating_milestones = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ะตั‚ะฐะฟะธ migrate.failed = ะœะธะณั€ะธั€ะฐะฝะตั‚ะพ ะต ะฝะตัƒัะฟะตัˆะฝะพ: %v pulls.nothing_to_compare_and_allow_empty_pr = ะขะตะทะธ ะบะปะพะฝะพะฒะต ัะฐ ั€ะฐะฒะฝะธ. ะขะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ั‰ะต ะฑัŠะดะต ะฟั€ะฐะทะฝะฐ. @@ -1608,14 +1660,15 @@ pulls.required_status_check_missing = ะัะบะพะธ ะทะฐะดัŠะปะถะธั‚ะตะปะฝะธ ะฟั€ะพ pulls.change_target_branch_at = `ะฟั€ะพะผะตะฝะธ ั†ะตะปะตะฒะธั ะบะปะพะฝ ะพั‚ %s ะฝะฐ %s %s` issues.time_spent_total = ะžะฑั‰ะพ ะธะทั€ะฐะทั…ะพะดะฒะฐะฝะพ ะฒั€ะตะผะต issues.del_time_history = `ะธะทั‚ั€ะธ ะธะทั€ะฐะทั…ะพะดะฒะฐะฝะพั‚ะพ ะฒั€ะตะผะต %s` -pulls.nothing_to_compare_have_tag = ะ˜ะทะฑั€ะฐะฝะธั‚ะต ะบะปะพะฝะพะฒะต/ะผะฐั€ะบะตั€ะธ ัะฐ ั€ะฐะฒะฝะธ. +pulls.nothing_to_compare_have_tag = ะ˜ะทะฑั€ะฐะฝะธั‚ะต ะบะปะพะฝ/ะผะฐั€ะบะตั€ ัะฐ ั€ะฐะฒะฝะธ. pulls.cannot_auto_merge_desc = ะขะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ัะปัั‚ะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะฟะพั€ะฐะดะธ ะบะพะฝั„ะปะธะบั‚ะธ. issues.tracker_auto_close = ะขะฐะนะผะตั€ัŠั‚ ั‰ะต ะฑัŠะดะต ัะฟั€ัะฝ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ, ะบะพะณะฐั‚ะพ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ ะฑัŠะดะต ะทะฐั‚ะฒะพั€ะตะฝะฐ -issues.force_push_codes = `ะธะทั‚ะปะฐัะบะฐ ะฟั€ะธะฝัƒะดะธั‚ะตะปะฝะพ %[1]s ะพั‚ %[2]s %[8]s ะบัŠะผ %[4]s %[9]s %[6]s` +issues.force_push_codes = `ะธะทั‚ะปะฐัะบะฐ ะฟั€ะธะฝัƒะดะธั‚ะตะปะฝะพ %[1]s ะพั‚ %[2]s ะบัŠะผ %[4]s %[6]s` pulls.blocked_by_official_review_requests = ะขะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะต ะฑะปะพะบะธั€ะฐะฝะฐ, ะทะฐั‰ะพั‚ะพ ะปะธะฟัะฒะฐ ะพะดะพะฑั€ะตะฝะธะต ะพั‚ ะตะดะธะฝ ะธะปะธ ะฟะพะฒะตั‡ะต ะพั„ะธั†ะธะฐะปะฝะธ ั€ะตั†ะตะฝะทะตะฝั‚ะธ. issues.tracker = ะŸั€ะพัะปะตะดัะฒะฐะฝะต ะฝะฐ ะฒั€ะตะผะตั‚ะพ issues.add_time_history = `ะดะพะฑะฐะฒะธ ะธะทั€ะฐะทั…ะพะดะฒะฐะฝะพ ะฒั€ะตะผะต %s` migrate.repo_desc_helper = ะžัั‚ะฐะฒะตั‚ะต ะฟั€ะฐะทะฝะพ, ะทะฐ ะดะฐ ะฒะฝะตัะตั‚ะต ััŠั‰ะตัั‚ะฒัƒะฒะฐั‰ะพั‚ะพ ะพะฟะธัะฐะฝะธะต +migrate.git.description = ะœะธะณั€ะธั€ะฐะฝะต ัะฐะผะพ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะต ะพั‚ ะฒััะบะฐ Git ัƒัะปัƒะณะฐ. mirror_sync = ัะธะฝั…ั€ะพะฝะธะทะธั€ะฐะฝะพ migrate_repo = ะœะธะณั€ะธั€ะฐะฝะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะต migrate_options = ะžะฟั†ะธะธ ะทะฐ ะผะธะณั€ะธั€ะฐะฝะตั‚ะพ @@ -1645,176 +1698,178 @@ migrate.migrating_failed_no_addr = ะœะธะณั€ะธั€ะฐะฝะตั‚ะพ ะต ะฝะตัƒัะฟะตัˆะฝะพ. issues.force_push_compare = ะกั€ะฐะฒะฝัะฒะฐะฝะต pulls.status_checking = ะัะบะพะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ะฒ ะพั‡ะฐะบะฒะฐะฝะต pulls.nothing_to_compare = ะขะตะทะธ ะบะปะพะฝะพะฒะต ัะฐ ั€ะฐะฒะฝะธ. ะะต ะต ะฝัƒะถะฝะพ ะดะฐ ััŠะทะดะฐะฒะฐั‚ะต ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต. -admin.flags_replaced = ะคะปะฐะณะพะฒะตั‚ะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ัะฐ ะทะฐะผะตะฝะตะฝะธ -editor.cannot_edit_lfs_files = LFS ั„ะฐะนะปะพะฒะต ะฝะต ะผะพะณะฐั‚ ะดะฐ ัะต ั€ะตะดะฐะบั‚ะธั€ะฐั‚ ะฒ ัƒะตะฑ ะธะฝั‚ะตั€ั„ะตะนัะฐ. -commits.ssh_key_fingerprint = ะžั‚ะฟะตั‡ะฐั‚ัŠะบ ะฝะฐ SSH ะบะปัŽั‡ -issues.comment_on_locked = ะะต ะผะพะถะตั‚ะต ะดะฐ ะบะพะผะตะฝั‚ะธั€ะฐั‚ะต ะทะฐะบะปัŽั‡ะตะฝะฐ ะทะฐะดะฐั‡ะฐ. -commit.revert = ะ’ั€ัŠั‰ะฐะฝะต -migrate.cancel_migrating_title = ะžั‚ะบะฐะท ะพั‚ ะผะธะณั€ะฐั†ะธัั‚ะฐ -migrate.cancel_migrating_confirm = ะ˜ัะบะฐั‚ะต ะปะธ ะดะฐ ะพั‚ะบะฐะถะตั‚ะต ั‚ะฐะทะธ ะผะธะณั€ะฐั†ะธั? -issues.choose.invalid_config = ะšะพะฝั„ะธะณัƒั€ะฐั†ะธัั‚ะฐ ะฝะฐ ะทะฐะดะฐั‡ะธั‚ะต ััŠะดัŠั€ะถะฐ ะณั€ะตัˆะบะธ: -unit_disabled = ะะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€ัŠั‚ ะฝะฐ ัะฐะนั‚ะฐ ะต ะธะทะบะปัŽั‡ะธะป ั‚ะฐะทะธ ัะตะบั†ะธั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. -issues.blocked_by_user = ะะต ะผะพะถะตั‚ะต ะดะฐ ััŠะทะดะฐะฒะฐั‚ะต ะทะฐะดะฐั‡ะธ ะฒ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต, ะทะฐั‰ะพั‚ะพ ัั‚ะต ะฑะปะพะบะธั€ะฐะฝะธ ะพั‚ ะฟั€ะธั‚ะตะถะฐั‚ะตะปั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. -commits.signed_by = ะŸะพะดะฟะธัะฐะฝะพ ะพั‚ -commits.signed_by_untrusted_user = ะŸะพะดะฟะธัะฐะฝะพ ะพั‚ ะฝะตะดะพะฒะตั€ะตะฝ ะฟะพั‚ั€ะตะฑะธั‚ะตะป -commits.signed_by_untrusted_user_unmatched = ะŸะพะดะฟะธัะฐะฝะพ ะพั‚ ะฝะตะดะพะฒะตั€ะตะฝ ะฟะพั‚ั€ะตะฑะธั‚ะตะป, ะบะพะนั‚ะพ ะฝะต ััŠะฒะฟะฐะดะฐ ั ะฟะพะดะฐะฒะฐั‰ะธั -issues.lock.notice_1 = - ะ”ั€ัƒะณะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะปะธ ะฝะต ะผะพะณะฐั‚ ะดะฐ ะดะพะฑะฐะฒัั‚ ะฝะพะฒะธ ะบะพะผะตะฝั‚ะฐั€ะธ ะบัŠะผ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ. -issues.unlock.notice_2 = - ะ’ะธะฝะฐะณะธ ะผะพะถะตั‚ะต ะดะฐ ะทะฐะบะปัŽั‡ะธั‚ะต ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ ะพั‚ะฝะพะฒะพ ะฒ ะฑัŠะดะตั‰ะต. -issues.unlock.title = ะžั‚ะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะพะฑััŠะถะดะฐะฝะตั‚ะพ ะฟะพ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ. -issues.dependency.no_permission_1 = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ะฟั€ะพั‡ะตั‚ะตั‚ะต %d ะทะฐะฒะธัะธะผะพัั‚ -issues.reopen.blocked_by_user = ะะต ะผะพะถะตั‚ะต ะดะฐ ะพั‚ะฒะพั€ะธั‚ะต ะฝะฐะฝะพะฒะพ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ, ะทะฐั‰ะพั‚ะพ ัั‚ะต ะฑะปะพะบะธั€ะฐะฝะธ ะพั‚ ะฟั€ะธั‚ะตะถะฐั‚ะตะปั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะธะปะธ ะพั‚ ะฐะฒั‚ะพั€ะฐ ะฝะฐ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ. -compare.compare_base = ะพัะฝะพะฒะฐ -compare.compare_head = ัั€ะฐะฒะฝัะฒะฐะฝะต -template.one_item = ะขั€ัะฑะฒะฐ ะดะฐ ะธะทะฑะตั€ะตั‚ะต ะฟะพะฝะต ะตะดะธะฝ ะตะปะตะผะตะฝั‚ ะพั‚ ัˆะฐะฑะปะพะฝะฐ -admin.failed_to_replace_flags = ะะตัƒัะฟะตัˆะฝะฐ ะทะฐะผัะฝะฐ ะฝะฐ ั„ะปะฐะณะพะฒะตั‚ะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ -mirror_interval_invalid = ะ˜ะฝั‚ะตั€ะฒะฐะปัŠั‚ ะฝะฐ ะพะณะปะตะดะฐะปะพั‚ะพ ะฝะต ะต ะฒะฐะปะธะดะตะฝ. -mirror_use_ssh.not_available = SSH ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะตั‚ะพ ะฝะต ะต ะฝะฐะปะธั‡ะฝะพ. -mirror_address_desc = ะŸะพัั‚ะฐะฒะตั‚ะต ะฒัะธั‡ะบะธ ะฝะตะพะฑั…ะพะดะธะผะธ ะดะฐะฝะฝะธ ะทะฐ ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต ะฒ ัะตะบั†ะธัั‚ะฐ โ€žะฃะฟัŠะปะฝะพะผะพั‰ะฐะฒะฐะฝะตโ€œ. -template.git_hooks = Git ะบัƒะบะธ -template.invalid = ะขั€ัะฑะฒะฐ ะดะฐ ะธะทะฑะตั€ะตั‚ะต ัˆะฐะฑะปะพะฝะฝะพ ั…ั€ะฐะฝะธะปะธั‰ะต -issues.review.outdated = ะžัั‚ะฐั€ัะป -issues.dependency.add_error_dep_issue_not_exist = ะ—ะฐะฒะธัะธะผะฐั‚ะฐ ะทะฐะดะฐั‡ะฐ ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ. -template.items = ะ•ะปะตะผะตะฝั‚ะธ ะฝะฐ ัˆะฐะฑะปะพะฝะฐ -issues.review.dismissed = ะพั‚ั…ะฒัŠั€ะปะธ ั€ะตั†ะตะฝะทะธัั‚ะฐ ะฝะฐ %s %s -audio_not_supported_in_browser = ะ’ะฐัˆะธัั‚ ะฑั€ะฐัƒะทัŠั€ ะฝะต ะฟะพะดะดัŠั€ะถะฐ HTML5 ั‚ะฐะณะฐ โ€žaudioโ€œ. -stored_lfs = ะกัŠั…ั€ะฐะฝะตะฝะพ ั Git LFS -commit_graph.select = ะ˜ะทะฑะตั€ะตั‚ะต ะบะปะพะฝะพะฒะต -issues.content_history.options = ะžะฟั†ะธะธ -editor.commit_email = ะ•ะป. ะฟะพั‰ะฐ ะฝะฐ ะฟะพะดะฐะฒะฐะฝะตั‚ะพ -commit.revert-header = ะ’ั€ัŠั‰ะฐะฝะต: %s -commits.desc = ะ ะฐะทะณะปะตะถะดะฐะฝะต ะฝะฐ ะธัั‚ะพั€ะธัั‚ะฐ ะฝะฐ ะฟั€ะพะผะตะฝะธั‚ะต ะฒ ะฟั€ะพะณั€ะฐะผะฝะธั ะบะพะด. -commits.search.tooltip = ะœะพะถะตั‚ะต ะดะฐ ะดะพะฑะฐะฒะธั‚ะต ะฟั€ะตั„ะธะบั ะบัŠะผ ะบะปัŽั‡ะพะฒะธั‚ะต ะดัƒะผะธ ั โ€žauthor:โ€œ, โ€žcommitter:โ€œ, โ€žafter:โ€œ ะธะปะธ โ€žbefore:โ€œ, ะฝะฐะฟั€. โ€žrevert author:Alice before:2019-01-13โ€œ. -issues.unlock_error = ะะต ะผะพะถะต ะดะฐ ัะต ะพั‚ะบะปัŽั‡ะธ ะทะฐะดะฐั‡ะฐ, ะบะพัั‚ะพ ะฝะต ะต ะทะฐะบะปัŽั‡ะตะฝะฐ. -issues.lock.unknown_reason = ะะต ะผะพะถะต ะดะฐ ัะต ะทะฐะบะปัŽั‡ะธ ะทะฐะดะฐั‡ะฐ ั ะฝะตะธะทะฒะตัั‚ะฝะฐ ะฟั€ะธั‡ะธะฝะฐ. -issues.cancel_tracking_history = `ะพั‚ะผะตะฝะธ ะฟั€ะพัะปะตะดัะฒะฐะฝะตั‚ะพ ะฝะฐ ะฒั€ะตะผะตั‚ะพ %s` -issues.dependency.add_error_dep_not_same_repo = ะ˜ ะดะฒะตั‚ะต ะทะฐะดะฐั‡ะธ ั‚ั€ัะฑะฒะฐ ะดะฐ ัะฐ ะฒ ะตะดะฝะพ ะธ ััŠั‰ะพ ั…ั€ะฐะฝะธะปะธั‰ะต. -issues.review.remove_review_requests = ะฟั€ะตะผะฐั…ะฝะฐ ะทะฐัะฒะบะธั‚ะต ะทะฐ ั€ะตั†ะตะฝะทะธั ะทะฐ %[1]s %[2]s -issues.review.content.empty = ะขั€ัะฑะฒะฐ ะดะฐ ะพัั‚ะฐะฒะธั‚ะต ะบะพะผะตะฝั‚ะฐั€, ะฟะพัะพั‡ะฒะฐั‰ ะธัะบะฐะฝะธั‚ะต ะฟั€ะพะผะตะฝะธ. -issues.review.hide_outdated = ะกะบั€ะธะฒะฐะฝะต ะฝะฐ ะพัั‚ะฐั€ะตะปะธ -pulls.desc = ะ’ะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต ะธ ั€ะตั†ะตะฝะทะธะธ ะฝะฐ ะบะพะด. -issues.review.show_outdated = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ะพัั‚ะฐั€ะตะปะธ -ambiguous_runes_header = `ะขะพะทะธ ั„ะฐะนะป ััŠะดัŠั€ะถะฐ ะดะฒัƒัะผะธัะปะตะฝะธ ะฃะฝะธะบะพะด ะทะฝะฐั†ะธ` -admin.update_flags = ะžะฑะฝะพะฒัะฒะฐะฝะต ะฝะฐ ั„ะปะฐะณะพะฒะตั‚ะต -issues.dependency.blocked_by_short = ะ—ะฐะฒะธัะธ ะพั‚ -mirror_lfs = ะกัŠั…ั€ะฐะฝะตะฝะธะต ะฝะฐ ะณะพะปะตะผะธ ั„ะฐะนะปะพะฒะต (LFS) -mirror_use_ssh.text = ะ˜ะทะฟะพะปะทะฒะฐะฝะต ะฝะฐ SSH ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต -mirror_denied_combination = ะะต ะผะพะถะต ะดะฐ ัะต ะธะทะฟะพะปะทะฒะฐ ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต ั ะฟัƒะฑะปะธั‡ะตะฝ ะบะปัŽั‡ ะธ ะฟะฐั€ะพะปะฐ ะตะดะฝะพะฒั€ะตะผะตะฝะฝะพ. + rss.must_be_on_branch = ะขั€ัะฑะฒะฐ ะดะฐ ัั‚ะต ะฝะฐ ะบะปะพะฝ, ะทะฐ ะดะฐ ะธะผะฐั‚ะต RSS ะตะผะธัะธั. admin.manage_flags = ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ั„ะปะฐะณะพะฒะตั‚ะต admin.enabled_flags = ะคะปะฐะณะพะฒะต, ะฒะบะปัŽั‡ะตะฝะธ ะทะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ: -mirror_password_help = ะŸั€ะพะผะตะฝะตั‚ะต ะฟะพั‚ั€ะตะฑะธั‚ะตะปัะบะพั‚ะพ ะธะผะต, ะทะฐ ะดะฐ ะธะทั‚ั€ะธะตั‚ะต ะทะฐะฟะฐะทะตะฝะฐ ะฟะฐั€ะพะปะฐ. -issues.review.remove_review_request = ะฟั€ะตะผะฐั…ะฝะฐ ะทะฐัะฒะบะฐั‚ะฐ ะทะฐ ั€ะตั†ะตะฝะทะธั ะทะฐ %[1]s %[2]s -issues.review.outdated_description = ะกัŠะดัŠั€ะถะฐะฝะธะตั‚ะพ ะต ะฟั€ะพะผะตะฝะตะฝะพ, ัะปะตะด ะบะฐั‚ะพ ะต ะฝะฐะฟั€ะฐะฒะตะฝ ั‚ะพะทะธ ะบะพะผะตะฝั‚ะฐั€ -issues.dependency.setting = ะ’ะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะทะฐะฒะธัะธะผะพัั‚ะธ ะทะฐ ะทะฐะดะฐั‡ะธ ะธ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต -issues.dependency.add_error_same_issue = ะะต ะผะพะถะตั‚ะต ะดะฐ ะฝะฐะฟั€ะฐะฒะธั‚ะต ะทะฐะดะฐั‡ะฐ ะทะฐะฒะธัะธะผะฐ ะพั‚ ัะฐะผะฐั‚ะฐ ะฝะตั. -issues.review.self.rejection = ะะต ะผะพะถะตั‚ะต ะดะฐ ะฟะพะธัะบะฐั‚ะต ะฟั€ะพะผะตะฝะธ ะฒ ัะพะฑัั‚ะฒะตะฝะฐั‚ะฐ ัะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต. -issues.filter_type.all_pull_requests = ะ’ัะธั‡ะบะธ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต +admin.update_flags = ะžะฑะฝะพะฒัะฒะฐะฝะต ะฝะฐ ั„ะปะฐะณะพะฒะตั‚ะต +admin.failed_to_replace_flags = ะะตัƒัะฟะตัˆะฝะฐ ะทะฐะผัะฝะฐ ะฝะฐ ั„ะปะฐะณะพะฒะตั‚ะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ +admin.flags_replaced = ะคะปะฐะณะพะฒะตั‚ะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ัะฐ ะทะฐะผะตะฝะตะฝะธ fork_to_different_account = ะ ะฐะทะบะปะพะฝัะฒะฐะฝะต ะฒ ะดั€ัƒะณ ะฐะบะฐัƒะฝั‚ -mirror_sync_on_commit = ะกะธะฝั…ั€ะพะฝะธะทะธั€ะฐะฝะต ะฟั€ะธ ะธะทั‚ะปะฐัะบะฒะฐะฝะต ะฝะฐ ะฟะพะดะฐะฒะฐะฝะธั -mirror_address_protocol_invalid = ะŸั€ะตะดะพัั‚ะฐะฒะตะฝะธัั‚ URL ะต ะฝะตะฒะฐะปะธะดะตะฝ. ะกะฐะผะพ http(s):// ะธะปะธ git:// ะฐะดั€ะตัะธ ะผะพะณะฐั‚ ะดะฐ ัะต ะธะทะฟะพะปะทะฒะฐั‚ ะทะฐ ะพะณะปะตะดะฐะปะฝะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ. -template.git_hooks_tooltip = ะ’ ะผะพะผะตะฝั‚ะฐ ะฝะต ะผะพะถะตั‚ะต ะดะฐ ะฟั€ะพะผะตะฝัั‚ะต ะธะปะธ ะฟั€ะตะผะฐั…ะฒะฐั‚ะต Git ะบัƒะบะธ, ัะปะตะด ะบะฐั‚ะพ ัะฐ ะดะพะฑะฐะฒะตะฝะธ. ะ˜ะทะฑะตั€ะตั‚ะต ั‚ะพะฒะฐ ัะฐะผะพ ะฐะบะพ ัะต ะดะพะฒะตั€ัะฒะฐั‚ะต ะฝะฐ ัˆะฐะฑะปะพะฝะฝะพั‚ะพ ั…ั€ะฐะฝะธะปะธั‰ะต. -editor.commit_signed_changes = ะŸะพะดะฐะฒะฐะฝะต ะฝะฐ ะฟะพะดะฟะธัะฐะฝะธ ะฟั€ะพะผะตะฝะธ -editor.require_signed_commit = ะšะปะพะฝัŠั‚ ะธะทะธัะบะฒะฐ ะฟะพะดะฟะธัะฐะฝะพ ะฟะพะดะฐะฒะฐะฝะต -issues.desc = ะžั€ะณะฐะฝะธะทะธั€ะฐะนั‚ะต ะดะพะบะปะฐะดะธ ะทะฐ ะณั€ะตัˆะบะธ, ะทะฐะดะฐั‡ะธ ะธ ะตั‚ะฐะฟะธ. -issues.lock_duplicate = ะ—ะฐะดะฐั‡ะฐ ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะทะฐะบะปัŽั‡ะตะฝะฐ ะดะฒะฐ ะฟัŠั‚ะธ. -issues.lock.notice_2 = - ะ’ะธะต ะธ ะดั€ัƒะณะธ ััŠั‚ั€ัƒะดะฝะธั†ะธ ั ะดะพัั‚ัŠะฟ ะดะพ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต ะฒัะต ะพั‰ะต ะผะพะถะตั‚ะต ะดะฐ ะพัั‚ะฐะฒัั‚ะต ะบะพะผะตะฝั‚ะฐั€ะธ, ะบะพะธั‚ะพ ะดั€ัƒะณะธั‚ะต ะดะฐ ะฒะธะถะดะฐั‚. -issues.due_date_invalid = ะšั€ะฐะนะฝะธัั‚ ัั€ะพะบ ะต ะฝะตะฒะฐะปะธะดะตะฝ ะธะปะธ ะธะทะฒัŠะฝ ะพะฑั…ะฒะฐั‚ะฐ. ะœะพะปั, ะธะทะฟะพะปะทะฒะฐะนั‚ะต ั„ะพั€ะผะฐั‚ะฐ โ€žะณะณะณะณ-ะผะผ-ะดะดโ€œ. mirror_interval = ะ˜ะฝั‚ะตั€ะฒะฐะป ะฝะฐ ะพะณะปะตะดะฐะปะพั‚ะพ (ะฒะฐะปะธะดะฝะธ ะตะดะธะฝะธั†ะธ ะทะฐ ะฒั€ะตะผะต ัะฐ โ€žhโ€œ, โ€žmโ€œ, โ€žsโ€œ). 0 ะทะฐ ะธะทะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะฟะตั€ะธะพะดะธั‡ะฝะฐั‚ะฐ ัะธะฝั…ั€ะพะฝะธะทะฐั†ะธั. (ะœะธะฝะธะผะฐะปะตะฝ ะธะฝั‚ะตั€ะฒะฐะป: %s) +mirror_interval_invalid = ะ˜ะฝั‚ะตั€ะฒะฐะปัŠั‚ ะฝะฐ ะพะณะปะตะดะฐะปะพั‚ะพ ะฝะต ะต ะฒะฐะปะธะดะตะฝ. +mirror_use_ssh.text = ะ˜ะทะฟะพะปะทะฒะฐะฝะต ะฝะฐ SSH ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต +mirror_use_ssh.helper = Forgejo ั‰ะต ััŠะทะดะฐะดะต ะพะณะปะตะดะฐะปะพ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ั‡ั€ะตะท Git ะฟั€ะตะท SSH ะธ ั‰ะต ะณะตะฝะตั€ะธั€ะฐ ะดะฒะพะนะบะฐ ะบะปัŽั‡ะพะฒะต ะทะฐ ะฒะฐั, ะบะพะณะฐั‚ะพ ะธะทะฑะตั€ะตั‚ะต ั‚ะฐะทะธ ะพะฟั†ะธั. ะขั€ัะฑะฒะฐ ะดะฐ ัะต ัƒะฒะตั€ะธั‚ะต, ั‡ะต ะณะตะฝะตั€ะธั€ะฐะฝะธัั‚ ะฟัƒะฑะปะธั‡ะตะฝ ะบะปัŽั‡ ะต ัƒะฟัŠะปะฝะพะผะพั‰ะตะฝ ะดะฐ ะธะทั‚ะปะฐัะบะฒะฐ ะบัŠะผ ั†ะตะปะตะฒะพั‚ะพ ั…ั€ะฐะฝะธะปะธั‰ะต. ะะต ะผะพะถะตั‚ะต ะดะฐ ะธะทะฟะพะปะทะฒะฐั‚ะต ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต, ะฑะฐะทะธั€ะฐะฝะพ ะฝะฐ ะฟะฐั€ะพะปะฐ, ะบะพะณะฐั‚ะพ ะธะทะฑะธั€ะฐั‚ะต ั‚ะพะฒะฐ. +mirror_use_ssh.not_available = SSH ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะตั‚ะพ ะฝะต ะต ะฝะฐะปะธั‡ะฝะพ. +mirror_denied_combination = ะะต ะผะพะถะต ะดะฐ ัะต ะธะทะฟะพะปะทะฒะฐ ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต ั ะฟัƒะฑะปะธั‡ะตะฝ ะบะปัŽั‡ ะธ ะฟะฐั€ะพะปะฐ ะตะดะฝะพะฒั€ะตะผะตะฝะฝะพ. +mirror_sync_on_commit = ะกะธะฝั…ั€ะพะฝะธะทะธั€ะฐะฝะต ะฟั€ะธ ะธะทั‚ะปะฐัะบะฒะฐะฝะต ะฝะฐ ะฟะพะดะฐะฒะฐะฝะธั +mirror_address_desc = ะŸะพัั‚ะฐะฒะตั‚ะต ะฒัะธั‡ะบะธ ะฝะตะพะฑั…ะพะดะธะผะธ ะดะฐะฝะฝะธ ะทะฐ ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต ะฒ ัะตะบั†ะธัั‚ะฐ โ€žะฃะฟัŠะปะฝะพะผะพั‰ะฐะฒะฐะฝะตโ€œ. +mirror_address_url_invalid = ะŸั€ะตะดะพัั‚ะฐะฒะตะฝะธัั‚ URL ะต ะฝะตะฒะฐะปะธะดะตะฝ. ะขั€ัะฑะฒะฐ ะดะฐ ะตะบั€ะฐะฝะธั€ะฐั‚ะต ะฟั€ะฐะฒะธะปะฝะพ ะฒัะธั‡ะบะธ ะบะพะผะฟะพะฝะตะฝั‚ะธ ะฝะฐ URL ะฐะดั€ะตัะฐ. +mirror_address_protocol_invalid = ะŸั€ะตะดะพัั‚ะฐะฒะตะฝะธัั‚ URL ะต ะฝะตะฒะฐะปะธะดะตะฝ. ะกะฐะผะพ http(s):// ะธะปะธ git:// ะฐะดั€ะตัะธ ะผะพะณะฐั‚ ะดะฐ ัะต ะธะทะฟะพะปะทะฒะฐั‚ ะทะฐ ะพะณะปะตะดะฐะปะฝะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ. +mirror_lfs = ะกัŠั…ั€ะฐะฝะตะฝะธะต ะฝะฐ ะณะพะปะตะผะธ ั„ะฐะนะปะพะฒะต (LFS) +mirror_password_help = ะŸั€ะพะผะตะฝะตั‚ะต ะฟะพั‚ั€ะตะฑะธั‚ะตะปัะบะพั‚ะพ ะธะผะต, ะทะฐ ะดะฐ ะธะทั‚ั€ะธะตั‚ะต ะทะฐะฟะฐะทะตะฝะฐ ะฟะฐั€ะพะปะฐ. +unit_disabled = ะะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€ัŠั‚ ะฝะฐ ัะฐะนั‚ะฐ ะต ะธะทะบะปัŽั‡ะธะป ั‚ะฐะทะธ ัะตะบั†ะธั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. summary_card_alt = ะšะฐั€ั‚ะฐ ั ะพะฑะพะฑั‰ะตะฝะธะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะต %s +template.items = ะ•ะปะตะผะตะฝั‚ะธ ะฝะฐ ัˆะฐะฑะปะพะฝะฐ +template.git_content = Git ััŠะดัŠั€ะถะฐะฝะธะต (ัั‚ะฐะฝะดะฐั€ั‚ะตะฝ ะบะปะพะฝ) +template.git_hooks = Git ะบัƒะบะธ +template.git_hooks_tooltip = ะ’ ะผะพะผะตะฝั‚ะฐ ะฝะต ะผะพะถะตั‚ะต ะดะฐ ะฟั€ะพะผะตะฝัั‚ะต ะธะปะธ ะฟั€ะตะผะฐั…ะฒะฐั‚ะต Git ะบัƒะบะธ, ัะปะตะด ะบะฐั‚ะพ ัะฐ ะดะพะฑะฐะฒะตะฝะธ. ะ˜ะทะฑะตั€ะตั‚ะต ั‚ะพะฒะฐ ัะฐะผะพ ะฐะบะพ ัะต ะดะพะฒะตั€ัะฒะฐั‚ะต ะฝะฐ ัˆะฐะฑะปะพะฝะฝะพั‚ะพ ั…ั€ะฐะฝะธะปะธั‰ะต. +template.one_item = ะขั€ัะฑะฒะฐ ะดะฐ ะธะทะฑะตั€ะตั‚ะต ะฟะพะฝะต ะตะดะธะฝ ะตะปะตะผะตะฝั‚ ะพั‚ ัˆะฐะฑะปะพะฝะฐ +template.invalid = ะขั€ัะฑะฒะฐ ะดะฐ ะธะทะฑะตั€ะตั‚ะต ัˆะฐะฑะปะพะฝะฝะพ ั…ั€ะฐะฝะธะปะธั‰ะต +migrate.cancel_migrating_title = ะžั‚ะบะฐะท ะพั‚ ะผะธะณั€ะฐั†ะธัั‚ะฐ +migrate.cancel_migrating_confirm = ะ˜ัะบะฐั‚ะต ะปะธ ะดะฐ ะพั‚ะบะฐะถะตั‚ะต ั‚ะฐะทะธ ะผะธะณั€ะฐั†ะธั? +invisible_runes_description = `ะขะพะทะธ ั„ะฐะนะป ััŠะดัŠั€ะถะฐ ะฝะตะฒะธะดะธะผะธ ะฃะฝะธะบะพะด ะทะฝะฐั†ะธ, ะบะพะธั‚ะพ ัะฐ ะฝะตั€ะฐะทะปะธั‡ะธะผะธ ะทะฐ ั…ะพั€ะฐั‚ะฐ, ะฝะพ ะผะพะณะฐั‚ ะดะฐ ะฑัŠะดะฐั‚ ะพะฑั€ะฐะฑะพั‚ะตะฝะธ ะฟะพ ั€ะฐะทะปะธั‡ะตะฝ ะฝะฐั‡ะธะฝ ะพั‚ ะบะพะผะฟัŽั‚ัŠั€. ะะบะพ ัะผัั‚ะฐั‚ะต, ั‡ะต ั‚ะพะฒะฐ ะต ัƒะผะธัˆะปะตะฝะพ, ะผะพะถะตั‚ะต ัะฟะพะบะพะนะฝะพ ะดะฐ ะฟั€ะตะฝะตะฑั€ะตะณะฝะตั‚ะต ั‚ะพะฒะฐ ะฟั€ะตะดัƒะฟั€ะตะถะดะตะฝะธะต. ะ˜ะทะฟะพะปะทะฒะฐะนั‚ะต ะฑัƒั‚ะพะฝะฐ โ€žะ•ะบั€ะฐะฝะธั€ะฐะฝะตโ€œ, ะทะฐ ะดะฐ ะณะธ ั€ะฐะทะบั€ะธะตั‚ะต.` +ambiguous_runes_header = `ะขะพะทะธ ั„ะฐะนะป ััŠะดัŠั€ะถะฐ ะดะฒัƒัะผะธัะปะตะฝะธ ะฃะฝะธะบะพะด ะทะฝะฐั†ะธ` +ambiguous_runes_description = `ะขะพะทะธ ั„ะฐะนะป ััŠะดัŠั€ะถะฐ ะฃะฝะธะบะพะด ะทะฝะฐั†ะธ, ะบะพะธั‚ะพ ะผะพะณะฐั‚ ะดะฐ ะฑัŠะดะฐั‚ ะพะฑัŠั€ะบะฐะฝะธ ั ะดั€ัƒะณะธ ะทะฝะฐั†ะธ. ะะบะพ ัะผัั‚ะฐั‚ะต, ั‡ะต ั‚ะพะฒะฐ ะต ัƒะผะธัˆะปะตะฝะพ, ะผะพะถะตั‚ะต ัะฟะพะบะพะนะฝะพ ะดะฐ ะฟั€ะตะฝะตะฑั€ะตะณะฝะตั‚ะต ั‚ะพะฒะฐ ะฟั€ะตะดัƒะฟั€ะตะถะดะตะฝะธะต. ะ˜ะทะฟะพะปะทะฒะฐะนั‚ะต ะฑัƒั‚ะพะฝะฐ โ€žะ•ะบั€ะฐะฝะธั€ะฐะฝะตโ€œ, ะทะฐ ะดะฐ ะณะธ ั€ะฐะทะบั€ะธะตั‚ะต.` file_copy_permalink = ะšะพะฟะธั€ะฐะฝะต ะฝะฐ ะฟะพัั‚ะพัะฝะฝะฐ ะฒั€ัŠะทะบะฐ view_git_blame = ะŸั€ะตะณะปะตะด ะฝะฐ git blame -commit.revert-content = ะ˜ะทะฑะตั€ะตั‚ะต ะบะปะพะฝ, ะฒัŠั€ั…ัƒ ะบะพะนั‚ะพ ะดะฐ ัะต ะฒัŠั€ะฝะต: -issues.unlock.notice_1 = - ะ’ัะตะบะธ ั‰ะต ะผะพะถะต ะพั‚ะฝะพะฒะพ ะดะฐ ะบะพะผะตะฝั‚ะธั€ะฐ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ. -issues.delete.text = ะะฐะธัั‚ะธะฝะฐ ะปะธ ะธัะบะฐั‚ะต ะดะฐ ะธะทั‚ั€ะธะตั‚ะต ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ? (ะขะพะฒะฐ ั‰ะต ะฟั€ะตะผะฐั…ะฝะต ั‚ั€ะฐะนะฝะพ ั†ัะปะพั‚ะพ ััŠะดัŠั€ะถะฐะฝะธะต. ะŸะพะผะธัะปะตั‚ะต ะดะฐะปะธ ะฒะผะตัั‚ะพ ั‚ะพะฒะฐ ะดะฐ ะฝะต ั ะทะฐั‚ะฒะพั€ะธั‚ะต, ะฐะบะพ ะฒัŠะทะฝะฐะผะตั€ัะฒะฐั‚ะต ะดะฐ ั ะทะฐะฟะฐะทะธั‚ะต ะฐั€ั…ะธะฒะธั€ะฐะฝะฐ) -issues.add_time_sum_to_small = ะะต ะต ะฒัŠะฒะตะดะตะฝะพ ะฒั€ะตะผะต. -issues.dependency.no_permission_n = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ะฟั€ะพั‡ะตั‚ะตั‚ะต %d ะทะฐะฒะธัะธะผะพัั‚ะธ -issues.review.pending.tooltip = ะขะพะทะธ ะบะพะผะตะฝั‚ะฐั€ ะฒ ะผะพะผะตะฝั‚ะฐ ะฝะต ะต ะฒะธะดะธะผ ะทะฐ ะดั€ัƒะณะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะปะธ. ะ—ะฐ ะดะฐ ะธะทะฟั€ะฐั‚ะธั‚ะต ะธะทั‡ะฐะบะฒะฐั‰ะธั‚ะต ัะธ ะบะพะผะตะฝั‚ะฐั€ะธ, ะธะทะฑะตั€ะตั‚ะต โ€ž%sโ€œ -> โ€ž%s/%s/%sโ€œ ะฒ ะณะพั€ะฝะฐั‚ะฐ ั‡ะฐัั‚ ะฝะฐ ัั‚ั€ะฐะฝะธั†ะฐั‚ะฐ. -invisible_runes_description = `ะขะพะทะธ ั„ะฐะนะป ััŠะดัŠั€ะถะฐ ะฝะตะฒะธะดะธะผะธ ะฃะฝะธะบะพะด ะทะฝะฐั†ะธ, ะบะพะธั‚ะพ ัะฐ ะฝะตั€ะฐะทะปะธั‡ะธะผะธ ะทะฐ ั…ะพั€ะฐั‚ะฐ, ะฝะพ ะผะพะณะฐั‚ ะดะฐ ะฑัŠะดะฐั‚ ะพะฑั€ะฐะฑะพั‚ะตะฝะธ ะฟะพ ั€ะฐะทะปะธั‡ะตะฝ ะฝะฐั‡ะธะฝ ะพั‚ ะบะพะผะฟัŽั‚ัŠั€. ะะบะพ ัะผัั‚ะฐั‚ะต, ั‡ะต ั‚ะพะฒะฐ ะต ัƒะผะธัˆะปะตะฝะพ, ะผะพะถะตั‚ะต ัะฟะพะบะพะนะฝะพ ะดะฐ ะฟั€ะตะฝะตะฑั€ะตะณะฝะตั‚ะต ั‚ะพะฒะฐ ะฟั€ะตะดัƒะฟั€ะตะถะดะตะฝะธะต. ะ˜ะทะฟะพะปะทะฒะฐะนั‚ะต ะฑัƒั‚ะพะฝะฐ โ€žะ•ะบั€ะฐะฝะธั€ะฐะฝะตโ€œ, ะทะฐ ะดะฐ ะณะธ ั€ะฐะทะบั€ะธะตั‚ะต.` video_not_supported_in_browser = ะ’ะฐัˆะธัั‚ ะฑั€ะฐัƒะทัŠั€ ะฝะต ะฟะพะดะดัŠั€ะถะฐ HTML5 ั‚ะฐะณะฐ โ€žvideoโ€œ. +audio_not_supported_in_browser = ะ’ะฐัˆะธัั‚ ะฑั€ะฐัƒะทัŠั€ ะฝะต ะฟะพะดะดัŠั€ะถะฐ HTML5 ั‚ะฐะณะฐ โ€žaudioโ€œ. +stored_lfs = ะกัŠั…ั€ะฐะฝะตะฝะพ ั Git LFS +commit_graph.select = ะ˜ะทะฑะตั€ะตั‚ะต ะบะปะพะฝะพะฒะต +editor.cannot_edit_lfs_files = LFS ั„ะฐะนะปะพะฒะต ะฝะต ะผะพะณะฐั‚ ะดะฐ ัะต ั€ะตะดะฐะบั‚ะธั€ะฐั‚ ะฒ ัƒะตะฑ ะธะฝั‚ะตั€ั„ะตะนัะฐ. editor.filename_help = ะ”ะพะฑะฐะฒะตั‚ะต ะดะธั€ะตะบั‚ะพั€ะธั, ะบะฐั‚ะพ ะฒัŠะฒะตะดะตั‚ะต ะธะผะตั‚ะพ ั, ะฟะพัะปะตะดะฒะฐะฝะพ ะพั‚ ะฝะฐะบะปะพะฝะตะฝะฐ ั‡ะตั€ั‚ะฐ (โ€ž/โ€œ). ะŸั€ะตะผะฐั…ะฝะตั‚ะต ะดะธั€ะตะบั‚ะพั€ะธั, ะบะฐั‚ะพ ะฝะฐั‚ะธัะฝะตั‚ะต backspace ะฒ ะฝะฐั‡ะฐะปะพั‚ะพ ะฝะฐ ะฟะพะปะตั‚ะพ ะทะฐ ะฒัŠะฒะตะถะดะฐะฝะต. +editor.commit_signed_changes = ะŸะพะดะฐะฒะฐะฝะต ะฝะฐ ะฟะพะดะฟะธัะฐะฝะธ ะฟั€ะพะผะตะฝะธ +editor.require_signed_commit = ะšะปะพะฝัŠั‚ ะธะทะธัะบะฒะฐ ะฟะพะดะฟะธัะฐะฝะพ ะฟะพะดะฐะฒะฐะฝะต +editor.commit_email = ะ•ะป. ะฟะพั‰ะฐ ะฝะฐ ะฟะพะดะฐะฒะฐะฝะตั‚ะพ +commits.desc = ะ ะฐะทะณะปะตะถะดะฐะฝะต ะฝะฐ ะธัั‚ะพั€ะธัั‚ะฐ ะฝะฐ ะฟั€ะพะผะตะฝะธั‚ะต ะฒ ะฟั€ะพะณั€ะฐะผะฝะธั ะบะพะด. +commits.search.tooltip = ะœะพะถะตั‚ะต ะดะฐ ะดะพะฑะฐะฒะธั‚ะต ะฟั€ะตั„ะธะบั ะบัŠะผ ะบะปัŽั‡ะพะฒะธั‚ะต ะดัƒะผะธ ั โ€žauthor:โ€œ, โ€žcommitter:โ€œ, โ€žafter:โ€œ ะธะปะธ โ€žbefore:โ€œ, ะฝะฐะฟั€. โ€žrevert author:Alice before:2019-01-13โ€œ. +commits.signed_by = ะŸะพะดะฟะธัะฐะฝะพ ะพั‚ +commits.signed_by_untrusted_user = ะŸะพะดะฟะธัะฐะฝะพ ะพั‚ ะฝะตะดะพะฒะตั€ะตะฝ ะฟะพั‚ั€ะตะฑะธั‚ะตะป +commits.signed_by_untrusted_user_unmatched = ะŸะพะดะฟะธัะฐะฝะพ ะพั‚ ะฝะตะดะพะฒะตั€ะตะฝ ะฟะพั‚ั€ะตะฑะธั‚ะตะป, ะบะพะนั‚ะพ ะฝะต ััŠะฒะฟะฐะดะฐ ั ะฟะพะดะฐะฒะฐั‰ะธั +commits.ssh_key_fingerprint = ะžั‚ะฟะตั‡ะฐั‚ัŠะบ ะฝะฐ SSH ะบะปัŽั‡ commits.view_single_diff = ะŸั€ะตะณะปะตะด ะฝะฐ ะฟั€ะพะผะตะฝะธั‚ะต ะฒ ั‚ะพะทะธ ั„ะฐะนะป, ะฒัŠะฒะตะดะตะฝะธ ะฒ ั‚ะพะฒะฐ ะฟะพะดะฐะฒะฐะฝะต +commit.revert = ะ’ั€ัŠั‰ะฐะฝะต +commit.revert-header = ะ’ั€ัŠั‰ะฐะฝะต: %s +commit.revert-content = ะ˜ะทะฑะตั€ะตั‚ะต ะบะปะพะฝ, ะฒัŠั€ั…ัƒ ะบะพะนั‚ะพ ะดะฐ ัะต ะฒัŠั€ะฝะต: +issues.desc = ะžั€ะณะฐะฝะธะทะธั€ะฐะนั‚ะต ะดะพะบะปะฐะดะธ ะทะฐ ะณั€ะตัˆะบะธ, ะทะฐะดะฐั‡ะธ ะธ ะตั‚ะฐะฟะธ. issues.choose.ignore_invalid_templates = ะะตะฒะฐะปะธะดะฝะธั‚ะต ัˆะฐะฑะปะพะฝะธ ัะฐ ะธะณะฝะพั€ะธั€ะฐะฝะธ -issues.due_date_form = ะณะณะณะณ-ะผะผ-ะดะด -issues.dependency.no_permission.can_remove = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ะฟั€ะพั‡ะตั‚ะตั‚ะต ั‚ะฐะทะธ ะทะฐะฒะธัะธะผะพัั‚, ะฝะพ ะผะพะถะตั‚ะต ะดะฐ ั ะฟั€ะตะผะฐั…ะฝะตั‚ะต -issues.review.remove_review_request_self = ะพั‚ะบะฐะทะฐ ะดะฐ ั€ะตั†ะตะฝะทะธั€ะฐ %s -mirror_use_ssh.helper = Forgejo ั‰ะต ััŠะทะดะฐะดะต ะพะณะปะตะดะฐะปะพ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ั‡ั€ะตะท Git ะฟั€ะตะท SSH ะธ ั‰ะต ะณะตะฝะตั€ะธั€ะฐ ะดะฒะพะนะบะฐ ะบะปัŽั‡ะพะฒะต ะทะฐ ะฒะฐั, ะบะพะณะฐั‚ะพ ะธะทะฑะตั€ะตั‚ะต ั‚ะฐะทะธ ะพะฟั†ะธั. ะขั€ัะฑะฒะฐ ะดะฐ ัะต ัƒะฒะตั€ะธั‚ะต, ั‡ะต ะณะตะฝะตั€ะธั€ะฐะฝะธัั‚ ะฟัƒะฑะปะธั‡ะตะฝ ะบะปัŽั‡ ะต ัƒะฟัŠะปะฝะพะผะพั‰ะตะฝ ะดะฐ ะธะทั‚ะปะฐัะบะฒะฐ ะบัŠะผ ั†ะตะปะตะฒะพั‚ะพ ั…ั€ะฐะฝะธะปะธั‰ะต. ะะต ะผะพะถะตั‚ะต ะดะฐ ะธะทะฟะพะปะทะฒะฐั‚ะต ัƒะดะพัั‚ะพะฒะตั€ัะฒะฐะฝะต, ะฑะฐะทะธั€ะฐะฝะพ ะฝะฐ ะฟะฐั€ะพะปะฐ, ะบะพะณะฐั‚ะพ ะธะทะฑะธั€ะฐั‚ะต ั‚ะพะฒะฐ. -mirror_address_url_invalid = ะŸั€ะตะดะพัั‚ะฐะฒะตะฝะธัั‚ URL ะต ะฝะตะฒะฐะปะธะดะตะฝ. ะฃะฒะตั€ะตั‚ะต ัะต, ั‡ะต ะบะพะผะฟะพะฝะตะฝั‚ะธั‚ะต ะฝะฐ URL ะฐะดั€ะตัะฐ ัะฐ ะตะบั€ะฐะฝะธั€ะฐะฝะธ ะฟั€ะฐะฒะธะปะฝะพ. -template.git_content = Git ััŠะดัŠั€ะถะฐะฝะธะต (ัั‚ะฐะฝะดะฐั€ั‚ะตะฝ ะบะปะพะฝ) -ambiguous_runes_description = `ะขะพะทะธ ั„ะฐะนะป ััŠะดัŠั€ะถะฐ ะฃะฝะธะบะพะด ะทะฝะฐั†ะธ, ะบะพะธั‚ะพ ะผะพะณะฐั‚ ะดะฐ ะฑัŠะดะฐั‚ ะพะฑัŠั€ะบะฐะฝะธ ั ะดั€ัƒะณะธ ะทะฝะฐั†ะธ. ะะบะพ ัะผัั‚ะฐั‚ะต, ั‡ะต ั‚ะพะฒะฐ ะต ัƒะผะธัˆะปะตะฝะพ, ะผะพะถะตั‚ะต ัะฟะพะบะพะนะฝะพ ะดะฐ ะฟั€ะตะฝะตะฑั€ะตะณะฝะตั‚ะต ั‚ะพะฒะฐ ะฟั€ะตะดัƒะฟั€ะตะถะดะตะฝะธะต. ะ˜ะทะฟะพะปะทะฒะฐะนั‚ะต ะฑัƒั‚ะพะฝะฐ โ€žะ•ะบั€ะฐะฝะธั€ะฐะฝะตโ€œ, ะทะฐ ะดะฐ ะณะธ ั€ะฐะทะบั€ะธะตั‚ะต.` +issues.choose.invalid_config = ะšะพะฝั„ะธะณัƒั€ะฐั†ะธัั‚ะฐ ะฝะฐ ะทะฐะดะฐั‡ะธั‚ะต ััŠะดัŠั€ะถะฐ ะณั€ะตัˆะบะธ: +issues.filter_type.all_pull_requests = ะ’ัะธั‡ะบะธ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต +issues.role.member_helper = ะขะพะทะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะป ะต ัƒั‡ะฐัั‚ะฝะธะบ ะฒ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ, ะฟั€ะธั‚ะตะถะฐะฒะฐั‰ะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต. +issues.lock.unknown_reason = ะะต ะผะพะถะต ะดะฐ ัะต ะทะฐะบะปัŽั‡ะธ ะทะฐะดะฐั‡ะฐ ั ะฝะตะธะทะฒะตัั‚ะฝะฐ ะฟั€ะธั‡ะธะฝะฐ. +issues.lock_duplicate = ะ—ะฐะดะฐั‡ะฐ ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะทะฐะบะปัŽั‡ะตะฝะฐ ะดะฒะฐ ะฟัŠั‚ะธ. +issues.unlock_error = ะะต ะผะพะถะต ะดะฐ ัะต ะพั‚ะบะปัŽั‡ะธ ะทะฐะดะฐั‡ะฐ, ะบะพัั‚ะพ ะฝะต ะต ะทะฐะบะปัŽั‡ะตะฝะฐ. +issues.lock.notice_1 = - ะ”ั€ัƒะณะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะปะธ ะฝะต ะผะพะณะฐั‚ ะดะฐ ะดะพะฑะฐะฒัั‚ ะฝะพะฒะธ ะบะพะผะตะฝั‚ะฐั€ะธ ะบัŠะผ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ. +issues.lock.notice_2 = - ะ’ะธะต ะธ ะดั€ัƒะณะธ ััŠั‚ั€ัƒะดะฝะธั†ะธ ั ะดะพัั‚ัŠะฟ ะดะพ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต ะฒัะต ะพั‰ะต ะผะพะถะตั‚ะต ะดะฐ ะพัั‚ะฐะฒัั‚ะต ะบะพะผะตะฝั‚ะฐั€ะธ, ะบะพะธั‚ะพ ะดั€ัƒะณะธั‚ะต ะดะฐ ะฒะธะถะดะฐั‚. issues.lock.notice_3 = - ะ’ะธะฝะฐะณะธ ะผะพะถะตั‚ะต ะดะฐ ะพั‚ะบะปัŽั‡ะธั‚ะต ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ ะพั‚ะฝะพะฒะพ ะฒ ะฑัŠะดะตั‰ะต. +issues.unlock.notice_1 = - ะ’ัะตะบะธ ั‰ะต ะผะพะถะต ะพั‚ะฝะพะฒะพ ะดะฐ ะบะพะผะตะฝั‚ะธั€ะฐ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ. +issues.unlock.notice_2 = - ะ’ะธะฝะฐะณะธ ะผะพะถะตั‚ะต ะดะฐ ะทะฐะบะปัŽั‡ะธั‚ะต ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ ะพั‚ะฝะพะฒะพ ะฒ ะฑัŠะดะตั‰ะต. issues.lock.title = ะ—ะฐะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะพะฑััŠะถะดะฐะฝะตั‚ะพ ะฟะพ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ. +issues.unlock.title = ะžั‚ะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะพะฑััŠะถะดะฐะฝะตั‚ะพ ะฟะพ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ. +issues.comment_on_locked = ะะต ะผะพะถะตั‚ะต ะดะฐ ะบะพะผะตะฝั‚ะธั€ะฐั‚ะต ะทะฐะบะปัŽั‡ะตะฝะฐ ะทะฐะดะฐั‡ะฐ. +issues.delete.text = ะะฐะธัั‚ะธะฝะฐ ะปะธ ะธัะบะฐั‚ะต ะดะฐ ะธะทั‚ั€ะธะตั‚ะต ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ? (ะขะพะฒะฐ ั‰ะต ะฟั€ะตะผะฐั…ะฝะต ั‚ั€ะฐะนะฝะพ ั†ัะปะพั‚ะพ ััŠะดัŠั€ะถะฐะฝะธะต. ะŸะพะผะธัะปะตั‚ะต ะดะฐะปะธ ะฒะผะตัั‚ะพ ั‚ะพะฒะฐ ะดะฐ ะฝะต ั ะทะฐั‚ะฒะพั€ะธั‚ะต, ะฐะบะพ ะฒัŠะทะฝะฐะผะตั€ัะฒะฐั‚ะต ะดะฐ ั ะทะฐะฟะฐะทะธั‚ะต ะฐั€ั…ะธะฒะธั€ะฐะฝะฐ) +issues.cancel_tracking_history = `ะพั‚ะผะตะฝะธ ะฟั€ะพัะปะตะดัะฒะฐะฝะตั‚ะพ ะฝะฐ ะฒั€ะตะผะตั‚ะพ %s` +issues.add_time_sum_to_small = ะะต ะต ะฒัŠะฒะตะดะตะฝะพ ะฒั€ะตะผะต. +issues.due_date_form = ะณะณะณะณ-ะผะผ-ะดะด +issues.due_date_invalid = ะšั€ะฐะนะฝะธัั‚ ัั€ะพะบ ะต ะฝะตะฒะฐะปะธะดะตะฝ ะธะปะธ ะธะทะฒัŠะฝ ะพะฑั…ะฒะฐั‚ะฐ. ะœะพะปั, ะธะทะฟะพะปะทะฒะฐะนั‚ะต ั„ะพั€ะผะฐั‚ะฐ โ€žะณะณะณะณ-ะผะผ-ะดะดโ€œ. +issues.dependency.no_permission_1 = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ะฟั€ะพั‡ะตั‚ะตั‚ะต %d ะทะฐะฒะธัะธะผะพัั‚ +issues.dependency.no_permission_n = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ะฟั€ะพั‡ะตั‚ะตั‚ะต %d ะทะฐะฒะธัะธะผะพัั‚ะธ +issues.dependency.no_permission.can_remove = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ะฟั€ะพั‡ะตั‚ะตั‚ะต ั‚ะฐะทะธ ะทะฐะฒะธัะธะผะพัั‚, ะฝะพ ะผะพะถะตั‚ะต ะดะฐ ั ะฟั€ะตะผะฐั…ะฝะตั‚ะต issues.dependency.issue_batch_close_blocked = ะะต ะผะพะณะฐั‚ ะดะฐ ะฑัŠะดะฐั‚ ะทะฐั‚ะฒะพั€ะตะฝะธ ะณั€ัƒะฟะพะฒะพ ะธะทะฑั€ะฐะฝะธั‚ะต ะทะฐะดะฐั‡ะธ, ะทะฐั‰ะพั‚ะพ ะทะฐะดะฐั‡ะฐ #%d ะฒัะต ะพั‰ะต ะธะผะฐ ะพั‚ะฒะพั€ะตะฝะธ ะทะฐะฒะธัะธะผะพัั‚ะธ +issues.dependency.blocked_by_short = ะ—ะฐะฒะธัะธ ะพั‚ +issues.dependency.setting = ะ’ะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะทะฐะฒะธัะธะผะพัั‚ะธ ะทะฐ ะทะฐะดะฐั‡ะธ ะธ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต +issues.dependency.add_error_same_issue = ะะต ะผะพะถะตั‚ะต ะดะฐ ะฝะฐะฟั€ะฐะฒะธั‚ะต ะทะฐะดะฐั‡ะฐ ะทะฐะฒะธัะธะผะฐ ะพั‚ ัะฐะผะฐั‚ะฐ ะฝะตั. +issues.dependency.add_error_dep_issue_not_exist = ะ—ะฐะฒะธัะธะผะฐั‚ะฐ ะทะฐะดะฐั‡ะฐ ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ. issues.dependency.add_error_cannot_create_circular = ะะต ะผะพะถะตั‚ะต ะดะฐ ััŠะทะดะฐะดะตั‚ะต ะทะฐะฒะธัะธะผะพัั‚ ั ะดะฒะต ะทะฐะดะฐั‡ะธ, ะบะพะธั‚ะพ ัะต ะฑะปะพะบะธั€ะฐั‚ ะฒะทะฐะธะผะฝะพ. +issues.dependency.add_error_dep_not_same_repo = ะ˜ ะดะฒะตั‚ะต ะทะฐะดะฐั‡ะธ ั‚ั€ัะฑะฒะฐ ะดะฐ ัะฐ ะฒ ะตะดะฝะพ ะธ ััŠั‰ะพ ั…ั€ะฐะฝะธะปะธั‰ะต. +issues.review.self.rejection = ะะต ะผะพะถะตั‚ะต ะดะฐ ะฟะพะธัะบะฐั‚ะต ะฟั€ะพะผะตะฝะธ ะฒ ัะพะฑัั‚ะฒะตะฝะฐั‚ะฐ ัะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต. +issues.review.dismissed = ะพั‚ั…ะฒัŠั€ะปะธ ั€ะตั†ะตะฝะทะธัั‚ะฐ ะฝะฐ %s %s +issues.review.content.empty = ะขั€ัะฑะฒะฐ ะดะฐ ะพัั‚ะฐะฒะธั‚ะต ะบะพะผะตะฝั‚ะฐั€, ะฟะพัะพั‡ะฒะฐั‰ ะธัะบะฐะฝะธั‚ะต ะฟั€ะพะผะตะฝะธ. issues.review.add_review_requests = ะฟะพะธัะบะฐ ั€ะตั†ะตะฝะทะธะธ ะพั‚ %[1]s %[2]s +issues.review.remove_review_request = ะฟั€ะตะผะฐั…ะฝะฐ ะทะฐัะฒะบะฐั‚ะฐ ะทะฐ ั€ะตั†ะตะฝะทะธั ะทะฐ %[1]s %[2]s +issues.review.remove_review_requests = ะฟั€ะตะผะฐั…ะฝะฐ ะทะฐัะฒะบะธั‚ะต ะทะฐ ั€ะตั†ะตะฝะทะธั ะทะฐ %[1]s %[2]s +issues.review.remove_review_request_self = ะพั‚ะบะฐะทะฐ ะดะฐ ั€ะตั†ะตะฝะทะธั€ะฐ %s +issues.review.pending.tooltip = ะขะพะทะธ ะบะพะผะตะฝั‚ะฐั€ ะฒ ะผะพะผะตะฝั‚ะฐ ะฝะต ะต ะฒะธะดะธะผ ะทะฐ ะดั€ัƒะณะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะปะธ. ะ—ะฐ ะดะฐ ะธะทะฟั€ะฐั‚ะธั‚ะต ะธะทั‡ะฐะบะฒะฐั‰ะธั‚ะต ัะธ ะบะพะผะตะฝั‚ะฐั€ะธ, ะธะทะฑะตั€ะตั‚ะต โ€ž%sโ€œ -> โ€ž%s/%s/%sโ€œ ะฒ ะณะพั€ะฝะฐั‚ะฐ ั‡ะฐัั‚ ะฝะฐ ัั‚ั€ะฐะฝะธั†ะฐั‚ะฐ. +issues.review.outdated = ะžัั‚ะฐั€ัะป +issues.review.outdated_description = ะกัŠะดัŠั€ะถะฐะฝะธะตั‚ะพ ะต ะฟั€ะพะผะตะฝะตะฝะพ, ัะปะตะด ะบะฐั‚ะพ ะต ะฝะฐะฟั€ะฐะฒะตะฝ ั‚ะพะทะธ ะบะพะผะตะฝั‚ะฐั€ +issues.review.show_outdated = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ะพัั‚ะฐั€ะตะปะธ +issues.review.hide_outdated = ะกะบั€ะธะฒะฐะฝะต ะฝะฐ ะพัั‚ะฐั€ะตะปะธ +issues.content_history.options = ะžะฟั†ะธะธ +issues.blocked_by_user = ะะต ะผะพะถะตั‚ะต ะดะฐ ััŠะทะดะฐะฒะฐั‚ะต ะทะฐะดะฐั‡ะธ ะฒ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต, ะทะฐั‰ะพั‚ะพ ัั‚ะต ะฑะปะพะบะธั€ะฐะฝะธ ะพั‚ ะฟั€ะธั‚ะตะถะฐั‚ะตะปั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. comment.blocked_by_user = ะšะพะผะตะฝั‚ะธั€ะฐะฝะตั‚ะพ ะฝะต ะต ะฒัŠะทะผะพะถะฝะพ, ะทะฐั‰ะพั‚ะพ ัั‚ะต ะฑะปะพะบะธั€ะฐะฝะธ ะพั‚ ะฟั€ะธั‚ะตะถะฐั‚ะตะปั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะธะปะธ ะพั‚ ะฐะฒั‚ะพั€ะฐ. +issues.reopen.blocked_by_user = ะะต ะผะพะถะตั‚ะต ะดะฐ ะพั‚ะฒะพั€ะธั‚ะต ะฝะฐะฝะพะฒะพ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ, ะทะฐั‰ะพั‚ะพ ัั‚ะต ะฑะปะพะบะธั€ะฐะฝะธ ะพั‚ ะฟั€ะธั‚ะตะถะฐั‚ะตะปั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะธะปะธ ะพั‚ ะฐะฒั‚ะพั€ะฐ ะฝะฐ ั‚ะฐะทะธ ะทะฐะดะฐั‡ะฐ. +compare.compare_base = ะพัะฝะพะฒะฐ +compare.compare_head = ัั€ะฐะฒะฝัะฒะฐะฝะต +pulls.desc = ะ’ะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต ะธ ั€ะตั†ะตะฝะทะธะธ ะฝะฐ ะบะพะด. pulls.view = ะŸั€ะตะณะปะตะด ะฝะฐ ะทะฐัะฒะบะฐั‚ะฐ ะทะฐ ัะปะธะฒะฐะฝะต -pulls.no_merge_desc = ะขะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ัะปัั‚ะฐ, ะทะฐั‰ะพั‚ะพ ะฒัะธั‡ะบะธ ะพะฟั†ะธะธ ะทะฐ ัะปะธะฒะฐะฝะต ะฒ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ัะฐ ะธะทะบะปัŽั‡ะตะฝะธ. -pulls.no_merge_wip = ะขะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ัะปัั‚ะฐ, ะทะฐั‰ะพั‚ะพ ะต ะพั‚ะฑะตะปัะทะฐะฝะฐ ะบะฐั‚ะพ ะฒ ะฟั€ะพั†ะตั ะฝะฐ ั€ะฐะฑะพั‚ะฐ. -pulls.switch_comparison_type = ะŸั€ะตะฒะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ั‚ะธะฟะฐ ัั€ะฐะฒะฝะตะฝะธะต +pulls.allow_edits_from_maintainers_desc = ะŸะพั‚ั€ะตะฑะธั‚ะตะปะธ ั ะฟั€ะฐะฒะพ ะฝะฐ ะทะฐะฟะธั ะฒ ะพัะฝะพะฒะฝะธั ะบะปะพะฝ ะผะพะณะฐั‚ ััŠั‰ะพ ะดะฐ ะธะทั‚ะปะฐัะบะฒะฐั‚ ะบัŠะผ ั‚ะพะทะธ ะบะปะพะฝ +pulls.allow_edits_from_maintainers_err = ะžะฑะฝะพะฒัะฒะฐะฝะตั‚ะพ ะต ะฝะตัƒัะฟะตัˆะฝะพ pulls.has_changed_since_last_review = ะŸั€ะพะผะตะฝะตะฝะพ ัะปะตะด ะฟะพัะปะตะดะฝะฐั‚ะฐ ะฒะธ ั€ะตั†ะตะฝะทะธั +pulls.switch_comparison_type = ะŸั€ะตะฒะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ั‚ะธะฟะฐ ัั€ะฐะฒะฝะตะฝะธะต pulls.filter_branch = ะคะธะปั‚ั€ะธั€ะฐะฝะต ะฝะฐ ะบะปะพะฝ +pulls.review_only_possible_for_full_diff = ะ ะตั†ะตะฝะทะธั€ะฐะฝะตั‚ะพ ะต ะฒัŠะทะผะพะถะฝะพ ัะฐะผะพ ะฟั€ะธ ะฟั€ะตะณะปะตะด ะฝะฐ ะฟัŠะปะฝะธั‚ะต ั€ะฐะทะปะธะบะธ +pulls.wrong_commit_id = ID ะฝะฐ ะฟะพะดะฐะฒะฐะฝะตั‚ะพ ั‚ั€ัะฑะฒะฐ ะดะฐ ะฑัŠะดะต ID ะฝะฐ ะฟะพะดะฐะฒะฐะฝะต ะฒ ั†ะตะปะตะฒะธั ะบะปะพะฝ +pulls.blocked_by_user = ะะต ะผะพะถะตั‚ะต ะดะฐ ััŠะทะดะฐะดะตั‚ะต ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะฒ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต, ะทะฐั‰ะพั‚ะพ ัั‚ะต ะฑะปะพะบะธั€ะฐะฝะธ ะพั‚ ะฟั€ะธั‚ะตะถะฐั‚ะตะปั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. +pulls.no_merge_desc = ะขะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ัะปัั‚ะฐ, ะทะฐั‰ะพั‚ะพ ะฒัะธั‡ะบะธ ะพะฟั†ะธะธ ะทะฐ ัะปะธะฒะฐะฝะต ะฒ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ัะฐ ะธะทะบะปัŽั‡ะตะฝะธ. +pulls.no_merge_helper = ะ’ะบะปัŽั‡ะตั‚ะต ะพะฟั†ะธะธั‚ะต ะทะฐ ัะปะธะฒะฐะฝะต ะฒ ะฝะฐัั‚ั€ะพะนะบะธั‚ะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะธะปะธ ัะปะตะนั‚ะต ะทะฐัะฒะบะฐั‚ะฐ ะทะฐ ัะปะธะฒะฐะฝะต ั€ัŠั‡ะฝะพ. +pulls.no_merge_wip = ะขะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ัะปัั‚ะฐ, ะทะฐั‰ะพั‚ะพ ะต ะพั‚ะฑะตะปัะทะฐะฝะฐ ะบะฐั‚ะพ ะฒ ะฟั€ะพั†ะตั ะฝะฐ ั€ะฐะฑะพั‚ะฐ. pulls.squash_merge_pull_request = ะกัŠะทะดะฐะฒะฐะฝะต ะฝะฐ ัะฟะปะตัะบะฐะฝะพ ะฟะพะดะฐะฒะฐะฝะต -pulls.rebase_conflict_summary = ะกัŠะพะฑั‰ะตะฝะธะต ะทะฐ ะณั€ะตัˆะบะฐ -pulls.auto_merge_button_when_succeed = (ะšะพะณะฐั‚ะพ ะฟั€ะพะฒะตั€ะบะธั‚ะต ัะฐ ัƒัะฟะตัˆะฝะธ) -pulls.auto_merge_newly_scheduled_comment = `ะฝะฐัั€ะพั‡ะธ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะทะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ัะปะธะฒะฐะฝะต, ะบะพะณะฐั‚ะพ ะฒัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ %[1]s` -pulls.auto_merge_canceled_schedule_comment = `ะพั‚ะผะตะฝะธ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพั‚ะพ ัะปะธะฒะฐะฝะต ะฝะฐ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต, ะบะพะณะฐั‚ะพ ะฒัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ %[1]s` pulls.merge_manually = ะ ัŠั‡ะฝะพ ัะปัั‚ะฐ pulls.merge_commit_id = ID ะฝะฐ ะฟะพะดะฐะฒะฐะฝะตั‚ะพ ััŠั ัะปะธะฒะฐะฝะต pulls.require_signed_wont_sign = ะšะปะพะฝัŠั‚ ะธะทะธัะบะฒะฐ ะฟะพะดะฟะธัะฐะฝะธ ะฟะพะดะฐะฒะฐะฝะธั, ะฝะพ ั‚ะพะฒะฐ ัะปะธะฒะฐะฝะต ะฝัะผะฐ ะดะฐ ะฑัŠะดะต ะฟะพะดะฟะธัะฐะฝะพ -pulls.no_merge_helper = ะ’ะบะปัŽั‡ะตั‚ะต ะพะฟั†ะธะธั‚ะต ะทะฐ ัะปะธะฒะฐะฝะต ะฒ ะฝะฐัั‚ั€ะพะนะบะธั‚ะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะธะปะธ ัะปะตะนั‚ะต ะทะฐัะฒะบะฐั‚ะฐ ะทะฐ ัะปะธะฒะฐะฝะต ั€ัŠั‡ะฝะพ. -pulls.review_only_possible_for_full_diff = ะ ะตั†ะตะฝะทะธั€ะฐะฝะตั‚ะพ ะต ะฒัŠะทะผะพะถะฝะพ ัะฐะผะพ ะฟั€ะธ ะฟั€ะตะณะปะตะด ะฝะฐ ะฟัŠะปะฝะธั‚ะต ั€ะฐะทะปะธะบะธ +pulls.merge_conflict = ะกะปะธะฒะฐะฝะตั‚ะพ ะต ะฝะตัƒัะฟะตัˆะฝะพ: ะ’ัŠะทะฝะธะบะฝะฐ ะบะพะฝั„ะปะธะบั‚ ะฟะพ ะฒั€ะตะผะต ะฝะฐ ัะปะธะฒะฐะฝะตั‚ะพ. ะŸะพะดัะบะฐะทะบะฐ: ะžะฟะธั‚ะฐะนั‚ะต ั€ะฐะทะปะธั‡ะฝะฐ ัั‚ั€ะฐั‚ะตะณะธั +pulls.merge_conflict_summary = ะกัŠะพะฑั‰ะตะฝะธะต ะทะฐ ะณั€ะตัˆะบะฐ +pulls.rebase_conflict_summary = ะกัŠะพะฑั‰ะตะฝะธะต ะทะฐ ะณั€ะตัˆะบะฐ +pulls.has_merged = ะะตัƒัะฟะตัˆะฝะพ: ะ—ะฐัะฒะบะฐั‚ะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะต ัะปัั‚ะฐ, ะฝะต ะผะพะถะตั‚ะต ะดะฐ ัะปะตะตั‚ะต ะพั‚ะฝะพะฒะพ ะธะปะธ ะดะฐ ะฟั€ะพะผะตะฝะธั‚ะต ั†ะตะปะตะฒะธั ะบะปะพะฝ. pulls.push_rejected = ะ˜ะทั‚ะปะฐัะบะฒะฐะฝะตั‚ะพ ะต ะฝะตัƒัะฟะตัˆะฝะพ: ะ˜ะทั‚ะปะฐัะบะฒะฐะฝะตั‚ะพ ะต ะพั‚ั…ะฒัŠั€ะปะตะฝะพ. ะŸั€ะตะณะปะตะดะฐะนั‚ะต Git ะบัƒะบะธั‚ะต ะทะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต. -pulls.auto_merge_canceled_schedule = ะะฒั‚ะพะผะฐั‚ะธั‡ะฝะพั‚ะพ ัะปะธะฒะฐะฝะต ะต ะพั‚ะผะตะฝะตะฝะพ ะทะฐ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต. -pulls.allow_edits_from_maintainers_err = ะžะฑะฝะพะฒัะฒะฐะฝะตั‚ะพ ะต ะฝะตัƒัะฟะตัˆะฝะพ +pulls.push_rejected_no_message = ะ˜ะทั‚ะปะฐัะบะฒะฐะฝะตั‚ะพ ะต ะฝะตัƒัะฟะตัˆะฝะพ: ะ˜ะทั‚ะปะฐัะบะฒะฐะฝะตั‚ะพ ะต ะพั‚ั…ะฒัŠั€ะปะตะฝะพ, ะฝะพ ะฝัะผะฐ ะพั‚ะดะฐะปะตั‡ะตะฝะพ ััŠะพะฑั‰ะตะฝะธะต. ะŸั€ะตะณะปะตะดะฐะนั‚ะต Git ะบัƒะบะธั‚ะต ะทะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต +pulls.update_not_allowed = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ะพะฑะฝะพะฒัะฒะฐั‚ะต ะบะปะพะฝะฐ +pulls.outdated_with_base_branch = ะขะพะทะธ ะบะปะพะฝ ะต ะพัั‚ะฐั€ัะป ัะฟั€ัะผะพ ะพัะฝะพะฒะฝะธั ะบะปะพะฝ +pulls.cmd_instruction_merge_warning = ะŸั€ะตะดัƒะฟั€ะตะถะดะตะฝะธะต: ะะฐัั‚ั€ะพะนะบะฐั‚ะฐ โ€žะะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะพั‚ะบั€ะธะฒะฐะฝะต ะฝะฐ ั€ัŠั‡ะฝะพ ัะปะธะฒะฐะฝะตโ€œ ะฝะต ะต ะฒะบะปัŽั‡ะตะฝะฐ ะทะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต, ั‰ะต ั‚ั€ัะฑะฒะฐ ะดะฐ ะพั‚ะฑะตะปะตะถะธั‚ะต ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะบะฐั‚ะพ ั€ัŠั‡ะฝะพ ัะปัั‚ะฐ ัะปะตะด ั‚ะพะฒะฐ. +pulls.editable_explanation = ะขะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะฟะพะทะฒะพะปัะฒะฐ ั€ะตะดะฐะบั†ะธะธ ะพั‚ ะฟะพะดะดัŠั€ะถะฐั‰ะธั‚ะต. ะœะพะถะตั‚ะต ะดะฐ ะดะพะฟั€ะธะฝะตัะตั‚ะต ะดะธั€ะตะบั‚ะฝะพ ะบัŠะผ ะฝะตั. +pulls.auto_merge_button_when_succeed = (ะšะพะณะฐั‚ะพ ะฟั€ะพะฒะตั€ะบะธั‚ะต ัะฐ ัƒัะฟะตัˆะฝะธ) +pulls.auto_merge_when_succeed = ะะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ัะปะธะฒะฐะฝะต, ะบะพะณะฐั‚ะพ ะฒัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ +pulls.auto_merge_newly_scheduled = ะ—ะฐัะฒะบะฐั‚ะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะต ะฝะฐัั€ะพั‡ะตะฝะฐ ะทะฐ ัะปะธะฒะฐะฝะต, ะบะพะณะฐั‚ะพ ะฒัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ. +pulls.auto_merge_has_pending_schedule = %[1]s ะฝะฐัั€ะพั‡ะธ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะทะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ัะปะธะฒะฐะฝะต, ะบะพะณะฐั‚ะพ ะฒัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ %[2]s. pulls.auto_merge_cancel_schedule = ะžั‚ะผัะฝะฐ ะฝะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพั‚ะพ ัะปะธะฒะฐะฝะต pulls.auto_merge_not_scheduled = ะขะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะฝะต ะต ะฝะฐัั€ะพั‡ะตะฝะฐ ะทะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ัะปะธะฒะฐะฝะต. -pulls.outdated_with_base_branch = ะขะพะทะธ ะบะปะพะฝ ะต ะพัั‚ะฐั€ัะป ัะฟั€ัะผะพ ะพัะฝะพะฒะฝะธั ะบะปะพะฝ -pulls.update_not_allowed = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ะพะฑะฝะพะฒัะฒะฐั‚ะต ะบะปะพะฝะฐ -pulls.wrong_commit_id = ID ะฝะฐ ะฟะพะดะฐะฒะฐะฝะตั‚ะพ ั‚ั€ัะฑะฒะฐ ะดะฐ ะฑัŠะดะต ID ะฝะฐ ะฟะพะดะฐะฒะฐะฝะต ะฒ ั†ะตะปะตะฒะธั ะบะปะพะฝ -pulls.blocked_by_user = ะะต ะผะพะถะตั‚ะต ะดะฐ ััŠะทะดะฐะดะตั‚ะต ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะฒ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต, ะทะฐั‰ะพั‚ะพ ัั‚ะต ะฑะปะพะบะธั€ะฐะฝะธ ะพั‚ ะฟั€ะธั‚ะตะถะฐั‚ะตะปั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. -pulls.merge_conflict_summary = ะกัŠะพะฑั‰ะตะฝะธะต ะทะฐ ะณั€ะตัˆะบะฐ -pulls.editable_explanation = ะขะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะฟะพะทะฒะพะปัะฒะฐ ั€ะตะดะฐะบั†ะธะธ ะพั‚ ะฟะพะดะดัŠั€ะถะฐั‰ะธั‚ะต. ะœะพะถะตั‚ะต ะดะฐ ะดะพะฟั€ะธะฝะตัะตั‚ะต ะดะธั€ะตะบั‚ะฝะพ ะบัŠะผ ะฝะตั. -pulls.allow_edits_from_maintainers_desc = ะŸะพั‚ั€ะตะฑะธั‚ะตะปะธ ั ะฟั€ะฐะฒะพ ะฝะฐ ะทะฐะฟะธั ะฒ ะพัะฝะพะฒะฝะธั ะบะปะพะฝ ะผะพะณะฐั‚ ััŠั‰ะพ ะดะฐ ะธะทั‚ะปะฐัะบะฒะฐั‚ ะบัŠะผ ั‚ะพะทะธ ะบะปะพะฝ -pulls.merge_conflict = ะกะปะธะฒะฐะฝะตั‚ะพ ะต ะฝะตัƒัะฟะตัˆะฝะพ: ะ’ัŠะทะฝะธะบะฝะฐ ะบะพะฝั„ะปะธะบั‚ ะฟะพ ะฒั€ะตะผะต ะฝะฐ ัะปะธะฒะฐะฝะตั‚ะพ. ะŸะพะดัะบะฐะทะบะฐ: ะžะฟะธั‚ะฐะนั‚ะต ั€ะฐะทะปะธั‡ะฝะฐ ัั‚ั€ะฐั‚ะตะณะธั -pulls.has_merged = ะะตัƒัะฟะตัˆะฝะพ: ะ—ะฐัะฒะบะฐั‚ะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะต ัะปัั‚ะฐ, ะฝะต ะผะพะถะตั‚ะต ะดะฐ ัะปะตะตั‚ะต ะพั‚ะฝะพะฒะพ ะธะปะธ ะดะฐ ะฟั€ะพะผะตะฝะธั‚ะต ั†ะตะปะตะฒะธั ะบะปะพะฝ. -pulls.cmd_instruction_merge_warning = ะŸั€ะตะดัƒะฟั€ะตะถะดะตะฝะธะต: ะะฐัั‚ั€ะพะนะบะฐั‚ะฐ โ€žะะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะพั‚ะบั€ะธะฒะฐะฝะต ะฝะฐ ั€ัŠั‡ะฝะพ ัะปะธะฒะฐะฝะตโ€œ ะฝะต ะต ะฒะบะปัŽั‡ะตะฝะฐ ะทะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต, ั‰ะต ั‚ั€ัะฑะฒะฐ ะดะฐ ะพั‚ะฑะตะปะตะถะธั‚ะต ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะบะฐั‚ะพ ั€ัŠั‡ะฝะพ ัะปัั‚ะฐ ัะปะตะด ั‚ะพะฒะฐ. +pulls.auto_merge_canceled_schedule = ะะฒั‚ะพะผะฐั‚ะธั‡ะฝะพั‚ะพ ัะปะธะฒะฐะฝะต ะต ะพั‚ะผะตะฝะตะฝะพ ะทะฐ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต. +pulls.auto_merge_newly_scheduled_comment = `ะฝะฐัั€ะพั‡ะธ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะทะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ัะปะธะฒะฐะฝะต, ะบะพะณะฐั‚ะพ ะฒัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ %[1]s` +pulls.auto_merge_canceled_schedule_comment = `ะพั‚ะผะตะฝะธ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพั‚ะพ ัะปะธะฒะฐะฝะต ะฝะฐ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต, ะบะพะณะฐั‚ะพ ะฒัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ %[1]s` pulls.delete.title = ะ”ะฐ ัะต ะธะทั‚ั€ะธะต ะปะธ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต? -pulls.push_rejected_no_message = ะ˜ะทั‚ะปะฐัะบะฒะฐะฝะตั‚ะพ ะต ะฝะตัƒัะฟะตัˆะฝะพ: ะ˜ะทั‚ะปะฐัะบะฒะฐะฝะตั‚ะพ ะต ะพั‚ั…ะฒัŠั€ะปะตะฝะพ, ะฝะพ ะฝัะผะฐ ะพั‚ะดะฐะปะตั‡ะตะฝะพ ััŠะพะฑั‰ะตะฝะธะต. ะŸั€ะตะณะปะตะดะฐะนั‚ะต Git ะบัƒะบะธั‚ะต ะทะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต -pulls.auto_merge_newly_scheduled = ะ—ะฐัะฒะบะฐั‚ะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะต ะฝะฐัั€ะพั‡ะตะฝะฐ ะทะฐ ัะปะธะฒะฐะฝะต, ะบะพะณะฐั‚ะพ ะฒัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ. pulls.delete.text = ะะฐะธัั‚ะธะฝะฐ ะปะธ ะธัะบะฐั‚ะต ะดะฐ ะธะทั‚ั€ะธะตั‚ะต ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต? (ะขะพะฒะฐ ั‰ะต ะฟั€ะตะผะฐั…ะฝะต ั‚ั€ะฐะนะฝะพ ั†ัะปะพั‚ะพ ััŠะดัŠั€ะถะฐะฝะธะต. ะŸะพะผะธัะปะตั‚ะต ะดะฐะปะธ ะฒะผะตัั‚ะพ ั‚ะพะฒะฐ ะดะฐ ะฝะต ั ะทะฐั‚ะฒะพั€ะธั‚ะต, ะฐะบะพ ะฒัŠะทะฝะฐะผะตั€ัะฒะฐั‚ะต ะดะฐ ั ะทะฐะฟะฐะทะธั‚ะต ะฐั€ั…ะธะฒะธั€ะฐะฝะฐ) -pulls.auto_merge_has_pending_schedule = %[1]s ะฝะฐัั€ะพั‡ะธ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต ะทะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ัะปะธะฒะฐะฝะต, ะบะพะณะฐั‚ะพ ะฒัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ %[2]s. -pulls.auto_merge_when_succeed = ะะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ัะปะธะฒะฐะฝะต, ะบะพะณะฐั‚ะพ ะฒัะธั‡ะบะธ ะฟั€ะพะฒะตั€ะบะธ ัะฐ ัƒัะฟะตัˆะฝะธ -error.csv.invalid_field_count = ะะต ะผะพะถะต ะดะฐ ัะต ะฒะธะทัƒะฐะปะธะทะธั€ะฐ ั‚ะพะทะธ ั„ะฐะนะป, ะทะฐั‰ะพั‚ะพ ะธะผะฐ ะณั€ะตัˆะตะฝ ะฑั€ะพะน ะฟะพะปะตั‚ะฐ ะฝะฐ ั€ะตะด %d. -diff.bin = ะ”ะ’ะžะ˜ะงะ•ะ -release.add_tag_msg = ะ˜ะทะฟะพะปะทะฒะฐะฝะต ะฝะฐ ะทะฐะณะปะฐะฒะธะตั‚ะพ ะธ ััŠะดัŠั€ะถะฐะฝะธะตั‚ะพ ะฝะฐ ะธะทะดะฐะฝะธะตั‚ะพ ะบะฐั‚ะพ ััŠะพะฑั‰ะตะฝะธะต ะฝะฐ ะผะฐั€ะบะตั€ะฐ. -release.hide_archive_links_helper = ะกะบั€ะธะนั‚ะต ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะณะตะฝะตั€ะธั€ะฐะฝะธั‚ะต ะฐั€ั…ะธะฒะธ ั ะฟั€ะพะณั€ะฐะผะตะฝ ะบะพะด ะทะฐ ั‚ะพะฒะฐ ะธะทะดะฐะฝะธะต. ะะฐะฟั€ะธะผะตั€, ะฐะบะพ ะบะฐั‡ะฒะฐั‚ะต ัะฒะพะธ ัะพะฑัั‚ะฒะตะฝะธ. diff.data_not_available = ะกัŠะดัŠั€ะถะฐะฝะธะตั‚ะพ ะฝะฐ ั€ะฐะทะปะธะบะธั‚ะต ะฝะต ะต ะฝะฐะปะธั‡ะฝะพ -diff.has_escaped = ะขะพะทะธ ั€ะตะด ะธะผะฐ ัะบั€ะธั‚ะธ ะฃะฝะธะบะพะด ะทะฝะฐั†ะธ -branch.protected_deletion_failed = ะšะปะพะฝัŠั‚ โ€ž%sโ€œ ะต ะทะฐั‰ะธั‚ะตะฝ. ะะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะธะทั‚ั€ะธั‚. -branch.default_deletion_failed = ะšะปะพะฝัŠั‚ โ€ž%sโ€œ ะต ัั‚ะฐะฝะดะฐั€ั‚ะฝะธัั‚ ะบะปะพะฝ. ะะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะธะทั‚ั€ะธั‚. +diff.bin = ะ”ะ’ะžะ˜ะงะ•ะ +diff.file_suppressed_line_too_long = ะ ะฐะทะปะธะบะธั‚ะต ะฒัŠะฒ ั„ะฐะนะปะฐ ัะฐ ะฟะพั‚ะธัะฝะฐั‚ะธ, ะทะฐั‰ะพั‚ะพ ะตะดะธะฝ ะธะปะธ ะฟะพะฒะตั‡ะต ั€ะตะดะพะฒะต ัะฐ ั‚ะฒัŠั€ะดะต ะดัŠะปะณะธ +diff.too_many_files = ะัะบะพะธ ั„ะฐะนะปะพะฒะต ะฝะต ะฑัั…ะฐ ะฟะพะบะฐะทะฐะฝะธ, ะทะฐั‰ะพั‚ะพ ั‚ะฒัŠั€ะดะต ะผะฝะพะณะพ ั„ะฐะนะปะพะฒะต ะธะผะฐั‚ ะฟั€ะพะผะตะฝะธ ะฒ ั‚ะตะทะธ ั€ะฐะทะปะธะบะธ +diff.show_more = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ะพั‰ะต diff.generated = ะณะตะฝะตั€ะธั€ะฐะฝ diff.comment.add_line_comment = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะบะพะผะตะฝั‚ะฐั€ ะบัŠะผ ั€ะตะด diff.comment.add_review_comment = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะบะพะผะตะฝั‚ะฐั€ -diff.review.self_approve = ะะฒั‚ะพั€ะธั‚ะต ะฝะฐ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต ะฝะต ะผะพะณะฐั‚ ะดะฐ ะพะดะพะฑั€ัะฒะฐั‚ ัะพะฑัั‚ะฒะตะฝะธั‚ะต ัะธ ะทะฐัะฒะบะธ -release.tag_name_protected = ะ˜ะผะตั‚ะพ ะฝะฐ ะผะฐั€ะบะตั€ะฐ ะต ะทะฐั‰ะธั‚ะตะฝะพ. -branch.warning_rename_default_branch = ะŸั€ะตะธะผะตะฝัƒะฒะฐั‚ะต ัั‚ะฐะฝะดะฐั€ั‚ะฝะธั ะบะปะพะฝ. -find_file.no_matching = ะะต ะต ะฝะฐะผะตั€ะตะฝ ััŠะฒะฟะฐะดะฐั‰ ั„ะฐะนะป -issues.role.member_helper = ะขะพะทะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะป ะต ัƒั‡ะฐัั‚ะฝะธะบ ะฒ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ, ะฟั€ะธั‚ะตะถะฐะฒะฐั‰ะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต. -diff.image.overlay = ะะฐัะปะฐะณะฒะฐะฝะต -diff.image.swipe = ะŸะปัŠะทะณะฐะฝะต -branch.included = ะ’ะบะปัŽั‡ะตะฝ -diff.file_suppressed_line_too_long = ะ ะฐะทะปะธะบะธั‚ะต ะฒัŠะฒ ั„ะฐะนะปะฐ ัะฐ ะฟะพั‚ะธัะฝะฐั‚ะธ, ะทะฐั‰ะพั‚ะพ ะตะดะธะฝ ะธะปะธ ะฟะพะฒะตั‡ะต ั€ะตะดะพะฒะต ัะฐ ั‚ะฒัŠั€ะดะต ะดัŠะปะณะธ -error.csv.unexpected = ะะต ะผะพะถะต ะดะฐ ัะต ะฒะธะทัƒะฐะปะธะทะธั€ะฐ ั‚ะพะทะธ ั„ะฐะนะป, ะทะฐั‰ะพั‚ะพ ััŠะดัŠั€ะถะฐ ะฝะตะพั‡ะฐะบะฒะฐะฝ ะทะฝะฐะบ ะฝะฐ ั€ะตะด %d ะธ ะบะพะปะพะฝะฐ %d. -topic.count_prompt = ะะต ะผะพะถะตั‚ะต ะดะฐ ะธะทะฑะตั€ะตั‚ะต ะฟะพะฒะตั‡ะต ะพั‚ 25 ั‚ะตะผะธ -release.hide_archive_links = ะกะบั€ะธะฒะฐะฝะต ะฝะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะณะตะฝะตั€ะธั€ะฐะฝะธั‚ะต ะฐั€ั…ะธะฒะธ -diff.show_more = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ะพั‰ะต -diff.too_many_files = ะัะบะพะธ ั„ะฐะนะปะพะฒะต ะฝะต ะฑัั…ะฐ ะฟะพะบะฐะทะฐะฝะธ, ะทะฐั‰ะพั‚ะพ ั‚ะฒัŠั€ะดะต ะผะฝะพะณะพ ั„ะฐะนะปะพะฒะต ะธะผะฐั‚ ะฟั€ะพะผะตะฝะธ ะฒ ั‚ะตะทะธ ั€ะฐะทะปะธะบะธ diff.review.self_reject = ะะฒั‚ะพั€ะธั‚ะต ะฝะฐ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต ะฝะต ะผะพะณะฐั‚ ะดะฐ ะฟะพะธัะบะฒะฐั‚ ะฟั€ะพะผะตะฝะธ ะฒ ัะพะฑัั‚ะฒะตะฝะธั‚ะต ัะธ ะทะฐัะฒะบะธ -branch.included_desc = ะขะพะทะธ ะบะปะพะฝ ะต ั‡ะฐัั‚ ะพั‚ ัั‚ะฐะฝะดะฐั€ั‚ะฝะธั ะบะปะพะฝ +diff.review.self_approve = ะะฒั‚ะพั€ะธั‚ะต ะฝะฐ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต ะฝะต ะผะพะณะฐั‚ ะดะฐ ะพะดะพะฑั€ัะฒะฐั‚ ัะพะฑัั‚ะฒะตะฝะธั‚ะต ัะธ ะทะฐัะฒะบะธ diff.image.side_by_side = ะ•ะดะฝะพ ะดะพ ะดั€ัƒะณะพ -release.summary_card_alt = ะšะฐั€ั‚ะฐ ั ะพะฑะพะฑั‰ะตะฝะธะต ะฝะฐ ะธะทะดะฐะฝะธะต ััŠั ะทะฐะณะปะฐะฒะธะต โ€ž%sโ€œ ะฒ ั…ั€ะฐะฝะธะปะธั‰ะต %s +diff.image.swipe = ะŸะปัŠะทะณะฐะฝะต +diff.image.overlay = ะะฐัะปะฐะณะฒะฐะฝะต +diff.has_escaped = ะขะพะทะธ ั€ะตะด ะธะผะฐ ัะบั€ะธั‚ะธ ะฃะฝะธะบะพะด ะทะฝะฐั†ะธ +release.tag_name_protected = ะ˜ะผะตั‚ะพ ะฝะฐ ะผะฐั€ะบะตั€ะฐ ะต ะทะฐั‰ะธั‚ะตะฝะพ. +release.add_tag_msg = ะ˜ะทะฟะพะปะทะฒะฐะฝะต ะฝะฐ ะทะฐะณะปะฐะฒะธะตั‚ะพ ะธ ััŠะดัŠั€ะถะฐะฝะธะตั‚ะพ ะฝะฐ ะธะทะดะฐะฝะธะตั‚ะพ ะบะฐั‚ะพ ััŠะพะฑั‰ะตะฝะธะต ะฝะฐ ะผะฐั€ะบะตั€ะฐ. +release.hide_archive_links = ะกะบั€ะธะฒะฐะฝะต ะฝะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะณะตะฝะตั€ะธั€ะฐะฝะธั‚ะต ะฐั€ั…ะธะฒะธ +release.hide_archive_links_helper = ะกะบั€ะธะนั‚ะต ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะณะตะฝะตั€ะธั€ะฐะฝะธั‚ะต ะฐั€ั…ะธะฒะธ ั ะฟั€ะพะณั€ะฐะผะตะฝ ะบะพะด ะทะฐ ั‚ะพะฒะฐ ะธะทะดะฐะฝะธะต. ะะฐะฟั€ะธะผะตั€, ะฐะบะพ ะบะฐั‡ะฒะฐั‚ะต ัะฒะพะธ ัะพะฑัั‚ะฒะตะฝะธ. release.asset_external_url = ะ’ัŠะฝัˆะตะฝ URL ะฐะดั€ะตั +release.summary_card_alt = ะšะฐั€ั‚ะฐ ั ะพะฑะพะฑั‰ะตะฝะธะต ะฝะฐ ะธะทะดะฐะฝะธะต ััŠั ะทะฐะณะปะฐะฒะธะต โ€ž%sโ€œ ะฒ ั…ั€ะฐะฝะธะปะธั‰ะต %s +branch.protected_deletion_failed = ะšะปะพะฝัŠั‚ โ€ž%sโ€œ ะต ะทะฐั‰ะธั‚ะตะฝ. ะะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะธะทั‚ั€ะธั‚. +branch.default_deletion_failed = ะšะปะพะฝัŠั‚ โ€ž%sโ€œ ะต ัั‚ะฐะฝะดะฐั€ั‚ะฝะธัั‚ ะบะปะพะฝ. ะะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะธะทั‚ั€ะธั‚. +branch.included_desc = ะขะพะทะธ ะบะปะพะฝ ะต ั‡ะฐัั‚ ะพั‚ ัั‚ะฐะฝะดะฐั€ั‚ะฝะธั ะบะปะพะฝ +branch.included = ะ’ะบะปัŽั‡ะตะฝ +branch.warning_rename_default_branch = ะŸั€ะตะธะผะตะฝัƒะฒะฐั‚ะต ัั‚ะฐะฝะดะฐั€ั‚ะฝะธั ะบะปะพะฝ. +topic.count_prompt = ะะต ะผะพะถะตั‚ะต ะดะฐ ะธะทะฑะตั€ะตั‚ะต ะฟะพะฒะตั‡ะต ะพั‚ 25 ั‚ะตะผะธ +find_file.no_matching = ะะต ะต ะฝะฐะผะตั€ะตะฝ ััŠะฒะฟะฐะดะฐั‰ ั„ะฐะนะป error.csv.too_large = ะะต ะผะพะถะต ะดะฐ ัะต ะฒะธะทัƒะฐะปะธะทะธั€ะฐ ั‚ะพะทะธ ั„ะฐะนะป, ะทะฐั‰ะพั‚ะพ ะต ั‚ะฒัŠั€ะดะต ะณะพะปัะผ. +error.csv.unexpected = ะะต ะผะพะถะต ะดะฐ ัะต ะฒะธะทัƒะฐะปะธะทะธั€ะฐ ั‚ะพะทะธ ั„ะฐะนะป, ะทะฐั‰ะพั‚ะพ ััŠะดัŠั€ะถะฐ ะฝะตะพั‡ะฐะบะฒะฐะฝ ะทะฝะฐะบ ะฝะฐ ั€ะตะด %d ะธ ะบะพะปะพะฝะฐ %d. +error.csv.invalid_field_count = ะะต ะผะพะถะต ะดะฐ ัะต ะฒะธะทัƒะฐะปะธะทะธั€ะฐ ั‚ะพะทะธ ั„ะฐะนะป, ะทะฐั‰ะพั‚ะพ ะธะผะฐ ะณั€ะตัˆะตะฝ ะฑั€ะพะน ะฟะพะปะตั‚ะฐ ะฝะฐ ั€ะตะด %d. +error.broken_git_hook = Git ะบัƒะบะธั‚ะต ะฝะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต ะธะทะณะปะตะถะดะฐั‚ ะฟะพะฒั€ะตะดะตะฝะธ. ะœะพะปั, ะฟะพัะปะตะดะฒะฐะนั‚ะต ะดะพะบัƒะผะตะฝั‚ะฐั†ะธัั‚ะฐ, ะทะฐ ะดะฐ ะณะธ ะฟะพะฟั€ะฐะฒะธั‚ะต, ัะปะตะด ะบะพะตั‚ะพ ะธะทั‚ะปะฐัะบะฐะนั‚ะต ะฟะพะดะฐะฒะฐะฝะธั, ะทะฐ ะดะฐ ะพะฑะฝะพะฒะธั‚ะต ัั‚ะฐั‚ัƒัะฐ. [modal] confirm = ะŸะพั‚ะฒัŠั€ะถะดะฐะฒะฐะฝะต @@ -1825,7 +1880,7 @@ yes = ะ”ะฐ [editor] buttons.list.ordered.tooltip = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะฝะพะผะตั€ะธั€ะฐะฝ ัะฟะธััŠะบ -buttons.bold.tooltip = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ัƒะดะตะฑะตะปะตะฝ ั‚ะตะบัั‚ (Ctrl+B / โŒ˜B) +buttons.bold.tooltip = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ัƒะดะตะฑะตะปะตะฝ ั‚ะตะบัั‚ buttons.quote.tooltip = ะฆะธั‚ะธั€ะฐะฝ ั‚ะตะบัั‚ buttons.code.tooltip = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะบะพะด buttons.list.unordered.tooltip = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะฝะตะฝะพะผะตั€ะธั€ะฐะฝ ัะฟะธััŠะบ @@ -1834,7 +1889,7 @@ buttons.switch_to_legacy.tooltip = ะ˜ะทะฟะพะปะทะฒะฐะฝะต ะฝะฐ ัั‚ะฐั€ะธั ั€ะตะด buttons.list.task.tooltip = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ัะฟะธััŠะบ ััŠั ะทะฐะดะฐั‡ะธ buttons.enable_monospace_font = ะ’ะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ั€ะฐะฒะฝะพัˆะธั€ะพะบ ัˆั€ะธั„ั‚ buttons.mention.tooltip = ะกะฟะพะผะตะฝะฐะฒะฐะฝะต ะฝะฐ ะฟะพั‚ั€ะตะฑะธั‚ะตะป ะธะปะธ ะตะบะธะฟ -buttons.italic.tooltip = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะบัƒั€ัะธะฒ ั‚ะตะบัั‚ (Ctrl+I / โŒ˜I) +buttons.italic.tooltip = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะบัƒั€ัะธะฒ ั‚ะตะบัั‚ buttons.link.tooltip = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะฒั€ัŠะทะบะฐ buttons.disable_monospace_font = ะ˜ะทะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ั€ะฐะฒะฝะพัˆะธั€ะพะบะธั ัˆั€ะธั„ั‚ buttons.ref.tooltip = ะŸั€ะตะฟั€ะฐั‚ะบะฐ ะบัŠะผ ะทะฐะดะฐั‡ะฐ ะธะปะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต @@ -1906,8 +1961,10 @@ teams.none_access = ะ‘ะตะท ะดะพัั‚ัŠะฟ teams.members.none = ะัะผะฐ ัƒั‡ะฐัั‚ะฝะธั†ะธ ะฒ ั‚ะพะทะธ ะตะบะธะฟ. repo_updated = ะžะฑะฝะพะฒะตะฝะพ %s teams.delete_team_success = ะ•ะบะธะฟัŠั‚ ะต ะธะทั‚ั€ะธั‚. +teams.search_repo_placeholder = ะŸะพั‚ัŠั€ัะตั‚ะต ั…ั€ะฐะฝะธะปะธั‰ะตโ€ฆ teams.delete_team_title = ะ˜ะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ะตะบะธะฟะฐ teams.add_team_member = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ัƒั‡ะฐัั‚ะฝะธะบ ะฒ ะตะบะธะฟะฐ +teams.read_access_helper = ะงะปะตะฝะพะฒะตั‚ะต ะผะพะณะฐั‚ ะดะฐ ะฟั€ะตะณะปะตะถะดะฐั‚ ะธ ะบะปะพะฝะธั€ะฐั‚ ั…ั€ะฐะฝะธะปะธั‰ะฐั‚ะฐ ะฝะฐ ะตะบะธะฟะฐ. teams.invite.description = ะœะพะปั, ั‰ั€ะฐะบะฝะตั‚ะต ะฒัŠั€ั…ัƒ ะฑัƒั‚ะพะฝะฐ ะฟะพ-ะดะพะปัƒ, ะทะฐ ะดะฐ ัะต ะฟั€ะธััŠะตะดะธะฝะธั‚ะต ะบัŠะผ ะตะบะธะฟะฐ. teams.invite.title = ะŸะพะบะฐะฝะตะฝะธ ัั‚ะต ะดะฐ ัะต ะฟั€ะธััŠะตะดะธะฝะธั‚ะต ะบัŠะผ ะตะบะธะฟ %s ะฒ ะพั€ะณะฐะฝะธะทะฐั†ะธั %s. team_permission_desc = ะ ะฐะทั€ะตัˆะตะฝะธะต @@ -1922,36 +1979,37 @@ teams.no_desc = ะขะพะทะธ ะตะบะธะฟ ะฝัะผะฐ ะพะฟะธัะฐะฝะธะต settings.delete_org_desc = ะขะฐะทะธ ะพั€ะณะฐะฝะธะทะฐั†ะธั ั‰ะต ะฑัŠะดะต ะธะทั‚ั€ะธั‚ะฐ ะฟะตั€ะผะฐะฝะตะฝั‚ะฝะพ. ะŸั€ะพะดัŠะปะถะฐะฒะฐะฝะต? open_dashboard = ะžั‚ะฒะฐั€ัะฝะต ะฝะฐ ั‚ะฐะฑะปะพั‚ะพ settings.change_orgname_prompt = ะ‘ะตะปะตะถะบะฐ: ะŸั€ะพะผัะฝะฐั‚ะฐ ะฝะฐ ะธะผะตั‚ะพ ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ ั‰ะต ะฟั€ะพะผะตะฝะธ ะธ URL ะฐะดั€ะตัะฐ ะฝะฐ ะฒะฐัˆะฐั‚ะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธั ะธ ั‰ะต ะพัะฒะพะฑะพะดะธ ัั‚ะฐั€ะพั‚ะพ ะธะผะต. -teams.add_duplicate_users = ะŸะพั‚ั€ะตะฑะธั‚ะตะปัั‚ ะฒะตั‡ะต ะต ัƒั‡ะฐัั‚ะฝะธะบ ะฒ ะตะบะธะฟะฐ. + +team_access_desc = ะ”ะพัั‚ัŠะฟ ะดะพ ั…ั€ะฐะฝะธะปะธั‰ะต +team_unit_desc = ะ ะฐะทั€ะตัˆะฐะฒะฐะฝะต ะฝะฐ ะดะพัั‚ัŠะฟ ะดะพ ัะตะบั†ะธะธ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ team_unit_disabled = (ะ˜ะทะบะปัŽั‡ะตะฝะพ) form.name_reserved = ะ˜ะผะตั‚ะพ ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ โ€ž%sโ€œ ะต ั€ะตะทะตั€ะฒะธั€ะฐะฝะพ. -settings.update_avatar_success = ะŸั€ะพั„ะธะปะฝะฐั‚ะฐ ัะฝะธะผะบะฐ ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ ะต ะพะฑะฝะพะฒะตะฝะฐ. -teams.invite_team_member.list = ะงะฐะบะฐั‰ะธ ะฟะพะบะฐะฝะธ -teams.remove_all_repos_desc = ะขะพะฒะฐ ั‰ะต ะฟั€ะตะผะฐั…ะฝะต ะฒัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ ะพั‚ ะตะบะธะฟะฐ. -form.create_org_not_allowed = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ััŠะทะดะฐะฒะฐั‚ะต ะพั€ะณะฐะฝะธะทะฐั†ะธั. form.name_pattern_not_allowed = ะจะฐะฑะปะพะฝัŠั‚ โ€ž%sโ€œ ะฝะต ะต ั€ะฐะทั€ะตัˆะตะฝ ะฒ ะธะผะต ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธั. -members.invite_now = ะŸะพะบะฐะฝะฒะฐะฝะต ัะตะณะฐ -teams.specific_repositories = ะšะพะฝะบั€ะตั‚ะฝะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ -teams.repos.none = ะัะผะฐ ั…ั€ะฐะฝะธะปะธั‰ะฐ, ะดะพ ะบะพะธั‚ะพ ั‚ะพะทะธ ะตะบะธะฟ ะดะฐ ะธะผะฐ ะดะพัั‚ัŠะฟ. -teams.add_all_repos_title = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะฒัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ -settings.hooks_desc = ะ”ะพะฑะฐะฒะตั‚ะต ัƒะตะฑ-ะบัƒะบะธ, ะบะพะธั‚ะพ ั‰ะต ัะต ะทะฐะดะตะนัั‚ะฒะฐั‚ ะทะฐ ะฒัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ ะฒ ั‚ะฐะทะธ ะพั€ะณะฐะฝะธะทะฐั†ะธั. -teams.add_all_repos_desc = ะขะพะฒะฐ ั‰ะต ะดะพะฑะฐะฒะธ ะฒัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ ะบัŠะผ ะตะบะธะฟะฐ. -members.invite_desc = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะฝะพะฒ ัƒั‡ะฐัั‚ะฝะธะบ ะบัŠะผ %s: -members.private = ะกะบั€ะธั‚ -settings.change_orgname_redirect_prompt.with_cooldown.few = ะกั‚ะฐั€ะพั‚ะพ ะธะผะต ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ ั‰ะต ะฑัŠะดะต ะดะพัั‚ัŠะฟะฝะพ ะทะฐ ะฒัะธั‡ะบะธ ัะปะตะด ะฟะตั€ะธะพะด ะฝะฐ ะธะทั‡ะฐะบะฒะฐะฝะต ะพั‚ %[1]d ะดะฝะธ. ะ’ัะต ะพั‰ะต ะผะพะถะตั‚ะต ะดะฐ ัะธ ะฒัŠั€ะฝะตั‚ะต ัั‚ะฐั€ะพั‚ะพ ะธะผะต ะฟะพ ะฒั€ะตะผะต ะฝะฐ ะฟะตั€ะธะพะดะฐ ะฝะฐ ะธะทั‡ะฐะบะฒะฐะฝะต. -team_access_desc = ะ”ะพัั‚ัŠะฟ ะดะพ ั…ั€ะฐะฝะธะปะธั‰ะต -teams.specific_repositories_helper = ะฃั‡ะฐัั‚ะฝะธั†ะธั‚ะต ั‰ะต ะธะผะฐั‚ ะดะพัั‚ัŠะฟ ัะฐะผะพ ะดะพ ั…ั€ะฐะฝะธะปะธั‰ะฐ, ะธะทั€ะธั‡ะฝะพ ะดะพะฑะฐะฒะตะฝะธ ะบัŠะผ ะตะบะธะฟะฐ. ะ˜ะทะฑะธั€ะฐะฝะตั‚ะพ ะฝะฐ ั‚ะพะฒะฐ ะฝัะผะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะดะฐ ะฟั€ะตะผะฐั…ะฝะต ั…ั€ะฐะฝะธะปะธั‰ะฐ, ะฒะตั‡ะต ะดะพะฑะฐะฒะตะฝะธ ั ะ’ัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ. -teams.delete_team_desc = ะ˜ะทั‚ั€ะธะฒะฐะฝะตั‚ะพ ะฝะฐ ะตะบะธะฟ ะพั‚ะฝะตะผะฐ ะดะพัั‚ัŠะฟะฐ ะดะพ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะพั‚ ะฝะตะณะพะฒะธั‚ะต ัƒั‡ะฐัั‚ะฝะธั†ะธ. ะŸั€ะพะดัŠะปะถะฐะฒะฐะฝะต? -members.membership_visibility = ะ’ะธะดะธะผะพัั‚ ะฝะฐ ัƒั‡ะฐัั‚ะฝะธั‡ะตัั‚ะฒะพั‚ะพ: -members.public = ะ’ะธะดะธะผ -teams.all_repositories_helper = ะ•ะบะธะฟัŠั‚ ะธะผะฐ ะดะพัั‚ัŠะฟ ะดะพ ะฒัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ. ะ˜ะทะฑะธั€ะฐะฝะตั‚ะพ ะฝะฐ ั‚ะพะฒะฐ ั‰ะต ะดะพะฑะฐะฒะธ ะฒัะธั‡ะบะธ ััŠั‰ะตัั‚ะฒัƒะฒะฐั‰ะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ ะบัŠะผ ะตะบะธะฟะฐ. -team_unit_desc = ะ ะฐะทั€ะตัˆะฐะฒะฐะฝะต ะฝะฐ ะดะพัั‚ัŠะฟ ะดะพ ัะตะบั†ะธะธ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ +form.create_org_not_allowed = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะดะฐ ััŠะทะดะฐะฒะฐั‚ะต ะพั€ะณะฐะฝะธะทะฐั†ะธั. settings.update_setting_success = ะะฐัั‚ั€ะพะนะบะธั‚ะต ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ ัะฐ ะพะฑะฝะพะฒะตะฝะธ. settings.change_orgname_redirect_prompt = ะกั‚ะฐั€ะพั‚ะพ ะธะผะต ั‰ะต ัะต ะฟั€ะตะฝะฐัะพั‡ะฒะฐ, ะดะพะบะฐั‚ะพ ะฝะต ะฑัŠะดะต ะฒะทะตั‚ะพ. -teams.invite_team_member = ะŸะพะบะฐะฝะฒะฐะฝะต ะฒ %s -teams.admin_access = ะะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€ัะบะธ ะดะพัั‚ัŠะฟ settings.change_orgname_redirect_prompt.with_cooldown.one = ะกั‚ะฐั€ะพั‚ะพ ะธะผะต ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ ั‰ะต ะฑัŠะดะต ะดะพัั‚ัŠะฟะฝะพ ะทะฐ ะฒัะธั‡ะบะธ ัะปะตะด ะฟะตั€ะธะพะด ะฝะฐ ะธะทั‡ะฐะบะฒะฐะฝะต ะพั‚ %[1]d ะดะตะฝ. ะ’ัะต ะพั‰ะต ะผะพะถะตั‚ะต ะดะฐ ัะธ ะฒัŠั€ะฝะตั‚ะต ัั‚ะฐั€ะพั‚ะพ ะธะผะต ะฟะพ ะฒั€ะตะผะต ะฝะฐ ะฟะตั€ะธะพะดะฐ ะฝะฐ ะธะทั‡ะฐะบะฒะฐะฝะต. +settings.change_orgname_redirect_prompt.with_cooldown.few = ะกั‚ะฐั€ะพั‚ะพ ะธะผะต ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ ั‰ะต ะฑัŠะดะต ะดะพัั‚ัŠะฟะฝะพ ะทะฐ ะฒัะธั‡ะบะธ ัะปะตะด ะฟะตั€ะธะพะด ะฝะฐ ะธะทั‡ะฐะบะฒะฐะฝะต ะพั‚ %[1]d ะดะฝะธ. ะ’ัะต ะพั‰ะต ะผะพะถะตั‚ะต ะดะฐ ัะธ ะฒัŠั€ะฝะตั‚ะต ัั‚ะฐั€ะพั‚ะพ ะธะผะต ะฟะพ ะฒั€ะตะผะต ะฝะฐ ะฟะตั€ะธะพะดะฐ ะฝะฐ ะธะทั‡ะฐะบะฒะฐะฝะต. +settings.update_avatar_success = ะŸั€ะพั„ะธะปะฝะฐั‚ะฐ ัะฝะธะผะบะฐ ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ ะต ะพะฑะฝะพะฒะตะฝะฐ. +settings.hooks_desc = ะ”ะพะฑะฐะฒะตั‚ะต ัƒะตะฑ-ะบัƒะบะธ, ะบะพะธั‚ะพ ั‰ะต ัะต ะทะฐะดะตะนัั‚ะฒะฐั‚ ะทะฐ ะฒัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ ะฒ ั‚ะฐะทะธ ะพั€ะณะฐะฝะธะทะฐั†ะธั. +members.membership_visibility = ะ’ะธะดะธะผะพัั‚ ะฝะฐ ัƒั‡ะฐัั‚ะฝะธั‡ะตัั‚ะฒะพั‚ะพ: +members.public = ะ’ะธะดะธะผ +members.private = ะกะบั€ะธั‚ +members.invite_desc = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะฝะพะฒ ัƒั‡ะฐัั‚ะฝะธะบ ะบัŠะผ %s: +members.invite_now = ะŸะพะบะฐะฝะฒะฐะฝะต ัะตะณะฐ +teams.admin_access = ะะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€ัะบะธ ะดะพัั‚ัŠะฟ +teams.invite_team_member = ะŸะพะบะฐะฝะฒะฐะฝะต ะฒ %s +teams.invite_team_member.list = ะงะฐะบะฐั‰ะธ ะฟะพะบะฐะฝะธ +teams.delete_team_desc = ะ˜ะทั‚ั€ะธะฒะฐะฝะตั‚ะพ ะฝะฐ ะตะบะธะฟ ะพั‚ะฝะตะผะฐ ะดะพัั‚ัŠะฟะฐ ะดะพ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะพั‚ ะฝะตะณะพะฒะธั‚ะต ัƒั‡ะฐัั‚ะฝะธั†ะธ. ะŸั€ะพะดัŠะปะถะฐะฒะฐะฝะต? +teams.remove_all_repos_desc = ะขะพะฒะฐ ั‰ะต ะฟั€ะตะผะฐั…ะฝะต ะฒัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ ะพั‚ ะตะบะธะฟะฐ. +teams.add_all_repos_title = ะ”ะพะฑะฐะฒัะฝะต ะฝะฐ ะฒัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ +teams.add_all_repos_desc = ะขะพะฒะฐ ั‰ะต ะดะพะฑะฐะฒะธ ะฒัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ ะบัŠะผ ะตะบะธะฟะฐ. teams.add_nonexistent_repo = ะฅั€ะฐะฝะธะปะธั‰ะตั‚ะพ, ะบะพะตั‚ะพ ัะต ะพะฟะธั‚ะฒะฐั‚ะต ะดะฐ ะดะพะฑะฐะฒะธั‚ะต, ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ, ะผะพะปั, ะฟัŠั€ะฒะพ ะณะพ ััŠะทะดะฐะนั‚ะต. +teams.add_duplicate_users = ะŸะพั‚ั€ะตะฑะธั‚ะตะปัั‚ ะฒะตั‡ะต ะต ัƒั‡ะฐัั‚ะฝะธะบ ะฒ ะตะบะธะฟะฐ. +teams.repos.none = ะัะผะฐ ั…ั€ะฐะฝะธะปะธั‰ะฐ, ะดะพ ะบะพะธั‚ะพ ั‚ะพะทะธ ะตะบะธะฟ ะดะฐ ะธะผะฐ ะดะพัั‚ัŠะฟ. +teams.specific_repositories = ะšะพะฝะบั€ะตั‚ะฝะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ +teams.specific_repositories_helper = ะฃั‡ะฐัั‚ะฝะธั†ะธั‚ะต ั‰ะต ะธะผะฐั‚ ะดะพัั‚ัŠะฟ ัะฐะผะพ ะดะพ ั…ั€ะฐะฝะธะปะธั‰ะฐ, ะธะทั€ะธั‡ะฝะพ ะดะพะฑะฐะฒะตะฝะธ ะบัŠะผ ะตะบะธะฟะฐ. ะ˜ะทะฑะธั€ะฐะฝะตั‚ะพ ะฝะฐ ั‚ะพะฒะฐ ะฝัะผะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะดะฐ ะฟั€ะตะผะฐั…ะฝะต ั…ั€ะฐะฝะธะปะธั‰ะฐ, ะฒะตั‡ะต ะดะพะฑะฐะฒะตะฝะธ ั ะ’ัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ. +teams.all_repositories_helper = ะ•ะบะธะฟัŠั‚ ะธะผะฐ ะดะพัั‚ัŠะฟ ะดะพ ะฒัะธั‡ะบะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ. ะ˜ะทะฑะธั€ะฐะฝะตั‚ะพ ะฝะฐ ั‚ะพะฒะฐ ั‰ะต ะดะพะฑะฐะฒะธ ะฒัะธั‡ะบะธ ััŠั‰ะตัั‚ะฒัƒะฒะฐั‰ะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ ะบัŠะผ ะตะบะธะฟะฐ. teams.invite.by = ะŸะพะบะฐะฝะตะฝ ะพั‚ %s [install] @@ -2021,6 +2079,7 @@ issue.action.review = @%[1]s ะบะพะผะตะฝั‚ะธั€ะฐ ะฒ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ issue.action.reopen = @%[1]s ะพั‚ะฒะพั€ะธ ะฝะฐะฝะพะฒะพ #%[2]d. issue.action.approve = @%[1]s ะพะดะพะฑั€ะธ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต. issue.action.reject = @%[1]s ะฟะพะธัะบะฐ ะฟั€ะพะผะตะฝะธ ะฒ ั‚ะฐะทะธ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต. +register_notify.title = %[1]s, ะดะพะฑั€ะต ะดะพัˆะปะธ ะฒ %[2]s link_not_working_do_paste = ะะบะพ ะฒั€ัŠะทะบะฐั‚ะฐ ะฝะต ั€ะฐะฑะพั‚ะธ, ะพะฟะธั‚ะฐะนั‚ะต ะดะฐ ั ะบะพะฟะธั€ะฐั‚ะต ะธ ะฟะพัั‚ะฐะฒะธั‚ะต ะฒ URL ะปะตะฝั‚ะฐั‚ะฐ ะฝะฐ ะฒะฐัˆะธั ะฑั€ะฐัƒะทัŠั€. activate_account = ะœะพะปั, ะฐะบั‚ะธะฒะธั€ะฐะนั‚ะต ัะฒะพั ะฐะบะฐัƒะฝั‚ admin.new_user.subject = ะะพะฒ ะฟะพั‚ั€ะตะฑะธั‚ะตะป %s ั‚ะพะบัƒ-ั‰ะพ ัะต ั€ะตะณะธัั‚ั€ะธั€ะฐ @@ -2080,6 +2139,7 @@ block_user = ะ‘ะปะพะบะธั€ะฐะฝะต ะฝะฐ ะฟะพั‚ั€ะตะฑะธั‚ะตะปั change_avatar = ะŸั€ะพะผะตะฝะตั‚ะต ะฟั€ะพั„ะธะปะฝะฐั‚ะฐ ัะธ ัะฝะธะผะบะฐโ€ฆ email_visibility.limited = ะ’ะฐัˆะธัั‚ ะฐะดั€ะตั ะทะฐ ะตะป. ะฟะพั‰ะฐ ะต ะฒะธะดะธะผ ะทะฐ ะฒัะธั‡ะบะธ ัƒะดะพัั‚ะพะฒะตั€ะตะฝะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะปะธ disabled_public_activity = ะขะพะทะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะป ะต ะธะทะบะปัŽั‡ะธะป ะฟัƒะฑะปะธั‡ะฝะฐั‚ะฐ ะฒะธะดะธะผะพัั‚ ะฝะฐ ะดะตะนะฝะพัั‚ั‚ะฐ. +email_visibility.private = ะ’ะฐัˆะธัั‚ ะฐะดั€ะตั ะฝะฐ ะตะป. ะฟะพั‰ะฐ ะต ะฒะธะดะธะผ ัะฐะผะพ ะทะฐ ะฒะฐั ะธ ะฐะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€ะธั‚ะต show_on_map = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ั‚ะพะฒะฐ ะผััั‚ะพ ะฝะฐ ะบะฐั€ั‚ะฐั‚ะฐ followers_one = %d ะฟะพัะปะตะดะพะฒะฐั‚ะตะป following_one = %d ัะปะตะดะฒะฐะฝ @@ -2104,6 +2164,7 @@ block_user.detail_1 = ะฉะต ัะฟั€ะตั‚ะต ะดะฐ ัะต ัะปะตะดะฒะฐั‚ะต ะตะดะธะฝ ะดั€ [home] filter = ะ”ั€ัƒะณะธ ั„ะธะปั‚ั€ะธ show_archived = ะั€ั…ะธะฒะธั€ะฐะฝะธ +search_repos = ะะฐะผะธั€ะฐะฝะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตโ€ฆ my_orgs = ะžั€ะณะฐะฝะธะทะฐั†ะธะธ uname_holder = ะŸะพั‚ั€ะตะฑะธั‚ะตะปัะบะพ ะธะผะต ะธะปะธ ะตะป. ะฟะพั‰ะฐ my_repos = ะฅั€ะฐะฝะธะปะธั‰ะฐ @@ -2113,9 +2174,13 @@ issues.in_your_repos = ะ’ัŠะฒ ะฒะฐัˆะธั‚ะต ั…ั€ะฐะฝะธะปะธั‰ะฐ show_both_private_public = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ะธ ะฟัƒะฑะปะธั‡ะฝะธ ะธ ั‡ะฐัั‚ะฝะธ show_only_private = ะŸะพะบะฐะทะฒะฐะฝะต ัะฐะผะพ ะฝะฐ ั‡ะฐัั‚ะฝะธ show_private = ะงะฐัั‚ะฝะธ +password_holder = ะŸะฐั€ะพะปะฐ +show_more_repos = ะŸะพะบะฐะทะฒะฐะฝะต ะฝะฐ ะฟะพะฒะตั‡ะต ั…ั€ะฐะฝะธะปะธั‰ะฐโ€ฆ show_only_unarchived = ะŸะพะบะฐะทะฒะฐะฝะต ัะฐะผะพ ะฝะฐ ะฝะตะฐั€ั…ะธะฒะธั€ะฐะฝะธ +my_mirrors = ะœะพะธั‚ะต ะพะณะปะตะดะฐะปะฐ show_only_archived = ะŸะพะบะฐะทะฒะฐะฝะต ัะฐะผะพ ะฝะฐ ะฐั€ั…ะธะฒะธั€ะฐะฝะธ view_home = ะŸั€ะตะณะปะตะด ะฝะฐ %s +collaborative_repos = ะกัŠะฒะผะตัั‚ะฝะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ switch_dashboard_context = ะŸั€ะตะฒะบะปัŽั‡ะฒะฐะฝะต ะฝะฐ ะบะพะฝั‚ะตะบัั‚ะฐ ะฝะฐ ั‚ะฐะฑะปะพั‚ะพ show_only_public = ะŸะพะบะฐะทะฒะฐะฝะต ัะฐะผะพ ะฝะฐ ะฟัƒะฑะปะธั‡ะฝะธ filter_by_team_repositories = ะคะธะปั‚ั€ะธั€ะฐะฝะต ะฟะพ ั…ั€ะฐะฝะธะปะธั‰ะฐ ะฝะฐ ะตะบะธะฟะฐ @@ -2128,6 +2193,8 @@ dashboard = ะขะฐะฑะปะพ repositories = ะฅั€ะฐะฝะธะปะธั‰ะฐ users.name = ะŸะพั‚ั€ะตะฑะธั‚ะตะปัะบะพ ะธะผะต organizations = ะžั€ะณะฐะฝะธะทะฐั†ะธะธ +repos.forks = ะ ะฐะทะบะปะพะฝะตะฝะธั +repos.stars = ะ—ะฒะตะทะดะธ config.mailer_name = ะ˜ะผะต repos.name = ะ˜ะผะต orgs.name = ะ˜ะผะต @@ -2141,6 +2208,7 @@ notices.type_1 = ะฅั€ะฐะฝะธะปะธั‰ะต config.domain = ะ”ะพะผะตะนะฝ ะฝะฐ ััŠั€ะฒัŠั€ะฐ users.max_repo_creation = ะœะฐะบัะธะผะฐะปะตะฝ ะฑั€ะพะน ั…ั€ะฐะฝะธะปะธั‰ะฐ defaulthooks = ะฃะตะฑ-ะบัƒะบะธ ะฟะพ ะฟะพะดั€ะฐะทะฑะธั€ะฐะฝะต +auths.sspi_default_language = ะŸะพั‚ั€ะตะฑะธั‚ะตะปัะบะธ ะตะทะธะบ ะฟะพ ะฟะพะดั€ะฐะทะฑะธั€ะฐะฝะต hooks = ะฃะตะฑ-ะบัƒะบะธ systemhooks = ะกะธัั‚ะตะผะฝะธ ัƒะตะฑ-ะบัƒะบะธ orgs.new_orga = ะะพะฒะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธั @@ -2209,12 +2277,14 @@ Email = ะะดั€ะตั ะทะฐ ะตะป. ะฟะพั‰ะฐ Password = ะŸะฐั€ะพะปะฐ RepoName = ะ˜ะผะต ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ username_been_taken = ะŸะพั‚ั€ะตะฑะธั‚ะตะปัะบะพั‚ะพ ะธะผะต ะฒะตั‡ะต ะต ะทะฐะตั‚ะพ. +SSPIDefaultLanguage = ะ•ะทะธะบ ะฟะพ ะฟะพะดั€ะฐะทะฑะธั€ะฐะฝะต password_not_match = ะŸะฐั€ะพะปะธั‚ะต ะฝะต ััŠะฒะฟะฐะดะฐั‚. captcha_incorrect = CAPTCHA ะบะพะดัŠั‚ ะต ะฝะตะฟั€ะฐะฒะธะปะตะฝ. username_change_not_local_user = ะŸะพั‚ั€ะตะฑะธั‚ะตะปะธ, ะบะพะธั‚ะพ ะฝะต ัะฐ ะปะพะบะฐะปะฝะธ ะฝะต ะผะพะณะฐั‚ ะดะฐ ะฟั€ะพะผะตะฝัั‚ ะฟะพั‚ั€ะตะฑะธั‚ะตะปัะบะพั‚ะพ ัะธ ะธะผะต. username_password_incorrect = ะะตะฟั€ะฐะฒะธะปะฝะพ ะฟะพั‚ั€ะตะฑะธั‚ะตะปัะบะพ ะธะผะต ะธะปะธ ะฟะฐั€ะพะปะฐ. user_not_exist = ะŸะพั‚ั€ะตะฑะธั‚ะตะปัั‚ ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ. lang_select_error = ะ˜ะทะฑะตั€ะตั‚ะต ะตะทะธะบ ะพั‚ ัะฟะธััŠะบะฐ. +HttpsUrl = HTTPS URL require_error = ` ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะฟั€ะฐะทะฝะพ.` Retype = ะŸะพั‚ะฒัŠั€ะดะตั‚ะต ะฟะฐั€ะพะปะฐั‚ะฐ url_error = `โ€ž%sโ€œ ะฝะต ะต ะฒะฐะปะธะดะตะฝ URL.` @@ -2223,6 +2293,7 @@ team_not_exist = ะ•ะบะธะฟัŠั‚ ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ. TeamName = ะ˜ะผะต ะฝะฐ ะตะบะธะฟะฐ email_error = ` ะฝะต ะต ะฒะฐะปะธะดะตะฝ ะฐะดั€ะตั ะทะฐ ะตะป. ะฟะพั‰ะฐ.` email_invalid = ะะดั€ะตััŠั‚ ะทะฐ ะตะป. ะฟะพั‰ะฐ ะต ะฝะตะฒะฐะปะธะดะตะฝ. +SSHTitle = ะ˜ะผะต ะฝะฐ SSH ะบะปัŽั‡ repo_name_been_taken = ะ˜ะผะตั‚ะพ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ ะฒะตั‡ะต ะต ะธะทะฟะพะปะทะฒะฐะฝะพ. team_name_been_taken = ะ˜ะผะตั‚ะพ ะฝะฐ ะตะบะธะฟะฐ ะฒะตั‡ะต ะต ะทะฐะตั‚ะพ. org_name_been_taken = ะ˜ะผะตั‚ะพ ะฝะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธัั‚ะฐ ะฒะตั‡ะต ะต ะทะฐะตั‚ะพ. @@ -2272,17 +2343,18 @@ TreeName = ะŸัŠั‚ ะดะพ ั„ะฐะนะปะฐ AdminEmail = ะะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€ัะบะธ ะฐะดั€ะตั ะทะฐ ะตะป. ะฟะพั‰ะฐ email_domain_is_not_allowed = ะ”ะพะผะตะนะฝัŠั‚ ะฝะฐ ะฐะดั€ะตัะฐ ะทะฐ ะตะป. ะฟะพั‰ะฐ ะฝะฐ ะฟะพั‚ั€ะตะฑะธั‚ะตะปั %s ะต ะฒ ะบะพะฝั„ะปะธะบั‚ ั EMAIL_DOMAIN_ALLOWLIST ะธะปะธ EMAIL_DOMAIN_BLOCKLIST. ะฃะฒะตั€ะตั‚ะต ัะต, ั‡ะต ัั‚ะต ะฒัŠะฒะตะปะธ ะฟั€ะฐะฒะธะปะฝะพ ะฐะดั€ะตัะฐ ะทะฐ ะตะป. ะฟะพั‰ะฐ. email_been_used = ะะดั€ะตััŠั‚ ะทะฐ ะตะป. ะฟะพั‰ะฐ ะฒะตั‡ะต ัะต ะธะทะฟะพะปะทะฒะฐ. -unable_verify_ssh_key = ะะต ะผะพะถะต ะดะฐ ัะต ะฟะพั‚ะฒัŠั€ะดะธ SSH ะบะปัŽั‡ัŠั‚, ะฟั€ะพะฒะตั€ะตั‚ะต ะณะพ ะพั‚ะฝะพะฒะพ ะทะฐ ะณั€ะตัˆะบะธ. -enterred_invalid_owner_name = ะ˜ะผะตั‚ะพ ะฝะฐ ะฝะพะฒะธั ะฟั€ะธั‚ะตะถะฐั‚ะตะป ะฝะต ะต ะฒะฐะปะธะดะฝะพ. + NewBranchName = ะ˜ะผะต ะฝะฐ ะฝะพะฒะธั ะบะปะพะฝ -invalid_ssh_key = ะะต ะผะพะถะต ะดะฐ ัะต ะฟะพั‚ะฒัŠั€ะดะธ ะฒะฐัˆะธัั‚ SSH ะบะปัŽั‡: %s -required_prefix = ะ’ัŠะฒะตะดะตะฝะธัั‚ ั‚ะตะบัั‚ ั‚ั€ัะฑะฒะฐ ะดะฐ ะทะฐะฟะพั‡ะฒะฐ ั โ€ž%sโ€œ +git_ref_name_error = ` ั‚ั€ัะฑะฒะฐ ะดะฐ ะต ะฟั€ะฐะฒะธะปะฝะพ ั„ะพั€ะผะฐั‚ะธั€ะฐะฝะพ ะธะผะต ะฝะฐ Git ะฟั€ะตะฟั€ะฐั‚ะบะฐ.` regex_pattern_error = ` ัˆะฐะฑะปะพะฝัŠั‚ ะฝะฐ ั€ะตะณัƒะปัั€ะฝะธั ะธะทั€ะฐะท ะต ะฝะตะฒะฐะปะธะดะตะฝ: %s.` repository_files_already_exist = ะ’ะตั‡ะต ััŠั‰ะตัั‚ะฒัƒะฒะฐั‚ ั„ะฐะนะปะพะฒะต ะทะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต. ะกะฒัŠั€ะถะตั‚ะต ัะต ััŠั ัะธัั‚ะตะผะฝะธั ะฐะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€. repository_files_already_exist.delete = ะ’ะตั‡ะต ััŠั‰ะตัั‚ะฒัƒะฒะฐั‚ ั„ะฐะนะปะพะฒะต ะทะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต. ะขั€ัะฑะฒะฐ ะดะฐ ะณะธ ะธะทั‚ั€ะธะตั‚ะต. -invalid_gpg_key = ะะต ะผะพะถะต ะดะฐ ัะต ะฟะพั‚ะฒัŠั€ะดะธ ะฒะฐัˆะธัั‚ GPG ะบะปัŽั‡: %s -git_ref_name_error = ` ั‚ั€ัะฑะฒะฐ ะดะฐ ะต ะฟั€ะฐะฒะธะปะฝะพ ั„ะพั€ะผะฐั‚ะธั€ะฐะฝะพ ะธะผะต ะฝะฐ Git ะฟั€ะตะฟั€ะฐั‚ะบะฐ.` +enterred_invalid_owner_name = ะ˜ะผะตั‚ะพ ะฝะฐ ะฝะพะฒะธั ะฟั€ะธั‚ะตะถะฐั‚ะตะป ะฝะต ะต ะฒะฐะปะธะดะฝะพ. last_org_owner = ะะต ะผะพะถะตั‚ะต ะดะฐ ะฟั€ะตะผะฐั…ะฝะตั‚ะต ะฟะพัะปะตะดะฝะธั ะฟะพั‚ั€ะตะฑะธั‚ะตะป ะพั‚ ะตะบะธะฟะฐ ะฝะฐ โ€žะฟั€ะธั‚ะตะถะฐั‚ะตะปะธั‚ะตโ€œ. ะขั€ัะฑะฒะฐ ะดะฐ ะธะผะฐ ะฟะพะฝะต ะตะดะธะฝ ะฟั€ะธั‚ะตะถะฐั‚ะตะป ะทะฐ ะพั€ะณะฐะฝะธะทะฐั†ะธั. +invalid_ssh_key = ะะต ะผะพะถะต ะดะฐ ัะต ะฟะพั‚ะฒัŠั€ะดะธ ะฒะฐัˆะธัั‚ SSH ะบะปัŽั‡: %s +invalid_gpg_key = ะะต ะผะพะถะต ะดะฐ ัะต ะฟะพั‚ะฒัŠั€ะดะธ ะฒะฐัˆะธัั‚ GPG ะบะปัŽั‡: %s +unable_verify_ssh_key = ะะต ะผะพะถะต ะดะฐ ัะต ะฟะพั‚ะฒัŠั€ะดะธ SSH ะบะปัŽั‡ัŠั‚, ะฟั€ะพะฒะตั€ะตั‚ะต ะณะพ ะพั‚ะฝะพะฒะพ ะทะฐ ะณั€ะตัˆะบะธ. +required_prefix = ะ’ัŠะฒะตะดะตะฝะธัั‚ ั‚ะตะบัั‚ ั‚ั€ัะฑะฒะฐ ะดะฐ ะทะฐะฟะพั‡ะฒะฐ ั โ€ž%sโ€œ [action] close_issue = `ะทะฐั‚ะฒะพั€ะธ ะทะฐะดะฐั‡ะฐ %[3]s#%[2]s` @@ -2302,7 +2374,7 @@ merge_pull_request = `ัะปั ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต %[ auto_merge_pull_request = `ัะปั ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะทะฐัะฒะบะฐ ะทะฐ ัะปะธะฒะฐะฝะต %[3]s#%[2]s` watched_repo = ะทะฐะฟะพั‡ะฝะฐ ะดะฐ ะฝะฐะฑะปัŽะดะฐะฒะฐ %[2]s delete_tag = ะธะทั‚ั€ะธ ะผะฐั€ะบะตั€ะฐ %[2]s ะพั‚ %[3]s -delete_branch = ะธะทั‚ั€ะธ ะบะปะพะฝะฐ %[2]s ะพั‚ %[3]s +delete_branch = ะธะทั‚ั€ะธ ะบะปะพะฝะฐ %[2]s ะพั‚ %[3]s create_branch = ััŠะทะดะฐะดะต ะบะปะพะฝ %[3]s ะฝะฐ %[4]s publish_release = `ะฟัƒะฑะปะธะบัƒะฒะฐ ะธะทะดะฐะฝะธะต %[4]s ะฝะฐ %[3]s` push_tag = ะธะทั‚ะปะฐัะบะฐ ะผะฐั€ะบะตั€ %[3]s ะบัŠะผ %[4]s @@ -2311,23 +2383,28 @@ reject_pull_request = `ะฟั€ะตะดะปะพะถะธ ะฟั€ะพะผะตะฝะธ ะทะฐ %[3] compare_branch = ะกั€ะฐะฒะฝัะฒะฐะฝะต compare_commits_general = ะกั€ะฐะฒะฝัะฒะฐะฝะต ะฝะฐ ะฟะพะดะฐะฒะฐะฝะธั compare_commits = ะกั€ะฐะฒะฝะตั‚ะต %d ะฟะพะดะฐะฒะฐะฝะธั + transfer_repo = ะฟั€ะตั…ะฒัŠั€ะปะธ ั…ั€ะฐะฝะธะปะธั‰ะต %s ะบัŠะผ %s mirror_sync_push = ัะธะฝั…ั€ะพะฝะธะทะธั€ะฐ ะฟะพะดะฐะฒะฐะฝะธั ะบัŠะผ %[3]s ะฝะฐ %[4]s ะพั‚ ะพะณะปะตะดะฐะปะพ mirror_sync_create = ัะธะฝั…ั€ะพะฝะธะทะธั€ะฐ ะฝะพะฒะฐ ะฟั€ะตะฟั€ะฐั‚ะบะฐ %[3]s ะบัŠะผ %[4]s ะพั‚ ะพะณะปะตะดะฐะปะพ -review_dismissed = `ะพั‚ั…ะฒัŠั€ะปะธ ั€ะตั†ะตะฝะทะธั ะพั‚ %[4]s ะทะฐ %[3]s#%[2]s` mirror_sync_delete = ัะธะฝั…ั€ะพะฝะธะทะธั€ะฐ ะธ ะธะทั‚ั€ะธ ะฟั€ะตะฟั€ะฐั‚ะบะฐ %[2]s ะฝะฐ %[3]s ะพั‚ ะพะณะปะตะดะฐะปะพ +review_dismissed = `ะพั‚ั…ะฒัŠั€ะปะธ ั€ะตั†ะตะฝะทะธั ะพั‚ %[4]s ะทะฐ %[3]s#%[2]s` [auth] +tab_openid = OpenID openid_connect_submit = ะกะฒัŠั€ะทะฒะฐะฝะต sign_up_successful = ะะบะฐัƒะฝั‚ัŠั‚ ะต ััŠะทะดะฐะดะตะฝ ัƒัะฟะตัˆะฝะพ. ะ”ะพะฑั€ะต ะดะพัˆะปะธ! login_userpass = ะ’ะปะธะทะฐะฝะต forgot_password = ะ—ะฐะฑั€ะฐะฒะตะฝะฐ ะฟะฐั€ะพะปะฐ? +sign_up_now = ะัƒะถะดะฐะตั‚ะต ัะต ะพั‚ ะฐะบะฐัƒะฝั‚? ะ ะตะณะธัั‚ั€ะธั€ะฐะนั‚ะต ัะต ัะตะณะฐ. forgot_password_title = ะ—ะฐะฑั€ะฐะฒะตะฝะฐ ะฟะฐั€ะพะปะฐ openid_register_title = ะกัŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะฝะพะฒ ะฐะบะฐัƒะฝั‚ account_activated = ะะบะฐัƒะฝั‚ัŠั‚ ะต ะฐะบั‚ะธะฒะธั€ะฐะฝ +social_register_helper_msg = ะ’ะตั‡ะต ะธะผะฐั‚ะต ะฐะบะฐัƒะฝั‚? ะกะฒัŠั€ะถะตั‚ะต ะณะพ ัะตะณะฐ! verify = ะŸะพั‚ะฒัŠั€ะถะดะฐะฒะฐะฝะต create_new_account = ะ ะตะณะธัั‚ั€ะธั€ะฐะฝะต ะฝะฐ ะฐะบะฐัƒะฝั‚ active_your_account = ะะบั‚ะธะฒะธั€ะฐะนั‚ะต ะฐะบะฐัƒะฝั‚ะฐ ัะธ +register_helper_msg = ะ’ะตั‡ะต ะธะผะฐั‚ะต ะฐะบะฐัƒะฝั‚? ะ’ะปะตะทั‚ะต ัะตะณะฐ! reset_password = ะ’ัŠะทัั‚ะฐะฝะพะฒัะฒะฐะฝะต ะฝะฐ ะฐะบะฐัƒะฝั‚ะฐ disable_register_prompt = ะ ะตะณะธัั‚ั€ะธั€ะฐะฝะตั‚ะพ ะต ะธะทะบะปัŽั‡ะตะฝะพ. ะœะพะปั, ัะฒัŠั€ะถะตั‚ะต ัะต ั ะฒะฐัˆะธั ะฐะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€ ะฝะฐ ัะฐะนั‚ะฐ. remember_me = ะ—ะฐะฟะพะผะฝะธ ะผะต @@ -2336,6 +2413,8 @@ disable_register_mail = ะŸะพั‚ะฒัŠั€ะถะดะตะฝะธะตั‚ะพ ะฟะพ ะตะป. ะฟะพั‰ะฐ ะทะฐ ั€ manual_activation_only = ะกะฒัŠั€ะถะตั‚ะต ัะต ั ะฒะฐัˆะธั ะฐะดะผะธะฝะธัั‚ั€ะฐั‚ะพั€ ะฝะฐ ัะฐะนั‚ะฐ, ะทะฐ ะดะฐ ะทะฐะฒัŠั€ัˆะธั‚ะต ะฐะบั‚ะธะฒะธั€ะฐะฝะตั‚ะพ. must_change_password = ะžะฑะฝะพะฒะตั‚ะต ะฟะฐั€ะพะปะฐั‚ะฐ ัะธ password_too_short = ะ”ัŠะปะถะธะฝะฐั‚ะฐ ะฝะฐ ะฟะฐั€ะพะปะฐั‚ะฐ ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะฟะพ-ะผะฐะปะบะฐ ะพั‚ %d ะทะฝะฐะบะฐ. +tab_signin = ะ’ะปะธะทะฐะฝะต +tab_signup = ะ ะตะณะธัั‚ั€ะธั€ะฐะฝะต password_pwned = ะŸะฐั€ะพะปะฐั‚ะฐ, ะบะพัั‚ะพ ัั‚ะต ะธะทะฑั€ะฐะปะธ, ะต ะฒ ัะฟะธััŠะบ ั ะพั‚ะบั€ะฐะดะฝะฐั‚ะธ ะฟะฐั€ะพะปะธ, ั€ะฐะทะบั€ะธั‚ะธ ะฟั€ะตะดะธ ั‚ะพะฒะฐ ะฟั€ะธ ะฟัƒะฑะปะธั‡ะฝะธ ะฟั€ะพะฑะธะฒะธ ะฝะฐ ะดะฐะฝะฝะธ. ะœะพะปั, ะพะฟะธั‚ะฐะนั‚ะต ะพั‚ะฝะพะฒะพ ั ั€ะฐะทะปะธั‡ะฝะฐ ะฟะฐั€ะพะปะฐ. confirmation_mail_sent_prompt = ะะพะฒะพ ะตะป. ะฟะธัะผะพ ะทะฐ ะฟะพั‚ะฒัŠั€ะถะดะตะฝะธะต ะต ะธะทะฟั€ะฐั‚ะตะฝะพ ะดะพ %s. ะ—ะฐ ะดะฐ ะทะฐะฒัŠั€ัˆะธั‚ะต ะฟั€ะพั†ะตัะฐ ะฝะฐ ั€ะตะณะธัั‚ั€ะฐั†ะธั, ะผะพะปั, ะฟั€ะพะฒะตั€ะตั‚ะต ะฒั…ะพะดัั‰ะฐั‚ะฐ ัะธ ะบัƒั‚ะธั ะธ ะฟะพัะปะตะดะฒะฐะนั‚ะต ะฟั€ะตะดะพัั‚ะฐะฒะตะฝะฐั‚ะฐ ะฒั€ัŠะทะบะฐ ะฒ ั€ะฐะผะบะธั‚ะต ะฝะฐ ัะปะตะดะฒะฐั‰ะธั‚ะต %s. ะะบะพ ะฐะดั€ะตััŠั‚ ะทะฐ ะตะป. ะฟะพั‰ะฐ ะต ะฝะตะฟั€ะฐะฒะธะปะตะฝ, ะผะพะถะตั‚ะต ะดะฐ ะฒะปะตะทะตั‚ะต ะธ ะดะฐ ะฟะพะธัะบะฐั‚ะต ะดั€ัƒะณะพ ะตะป. ะฟะธัะผะพ ะทะฐ ะฟะพั‚ะฒัŠั€ะถะดะตะฝะธะต ะดะฐ ะฑัŠะดะต ะธะทะฟั€ะฐั‚ะตะฝะพ ะฝะฐ ั€ะฐะทะปะธั‡ะตะฝ ะฐะดั€ะตั. hint_login = ะ’ะตั‡ะต ะธะผะฐั‚ะต ะฐะบะฐัƒะฝั‚? ะ’ะปะตะทั‚ะต! @@ -2403,12 +2482,17 @@ mark_all_as_read = ะžั‚ะฑะตะปัะทะฒะฐะฝะต ะฝะฐ ะฒัะธั‡ะบะธ ะบะฐั‚ะพ ะฟั€ะพั‡ะต pin = ะ—ะฐะบะฐั‡ะฒะฐะฝะต ะฝะฐ ะธะทะฒะตัั‚ะธะตั‚ะพ [explore] +code_search_results = ะ ะตะทัƒะปั‚ะฐั‚ะธ ะพั‚ ั‚ัŠั€ัะตะฝะตั‚ะพ ะฝะฐ "%s" go_to = ะžั‚ะธะฒะฐะฝะต ะบัŠะผ repos = ะฅั€ะฐะฝะธะปะธั‰ะฐ users = ะŸะพั‚ั€ะตะฑะธั‚ะตะปะธ +search = ะขัŠั€ัะตะฝะต code = ะšะพะด organizations = ะžั€ะณะฐะฝะธะทะฐั†ะธะธ code_last_indexed_at = ะŸะพัะปะตะดะฝะพ ะธะฝะดะตะบัะธั€ะฐะฝ %s +repo_no_results = ะัะผะฐ ะฝะฐะผะตั€ะตะฝะธ ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‰ะธ ั…ั€ะฐะฝะธะปะธั‰ะฐ. +user_no_results = ะัะผะฐ ะฝะฐะผะตั€ะตะฝะธ ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‰ะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะปะธ. +org_no_results = ะัะผะฐ ะฝะฐะผะตั€ะตะฝะธ ััŠะพั‚ะฒะตั‚ัั‚ะฒะฐั‰ะธ ะพั€ะณะฐะฝะธะทะฐั†ะธะธ. stars_one = %d ะทะฒะตะทะดะฐ stars_few = %d ะทะฒะตะทะดะธ forks_one = %d ั€ะฐะทะบะปะพะฝะตะฝะธะต @@ -2438,14 +2522,15 @@ variables.management = ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะฟั€ะพะผะตะฝะปะธะฒะธ variables.not_found = ะŸั€ะพะผะตะฝะปะธะฒะฐั‚ะฐ ะฝะต ะต ะพั‚ะบั€ะธั‚ะฐ. variables.id_not_exist = ะŸั€ะพะผะตะฝะปะธะฒะฐ ั ะธะดะตะฝั‚ะธั„ะธะบะฐั‚ะพั€ %d ะฝะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ. runners.owner_type = ะขะธะฟ -status.cancelled = ะžั‚ะผะตะฝะตะฝะพ + +unit.desc = ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะธะฝั‚ะตะณั€ะธั€ะฐะฝะธ CI/CD pipelines ั Forgejo Actions. +status.unknown = ะะตะธะทะฒะตัั‚ะฝะพ +status.waiting = ะ˜ะทั‡ะฐะบะฒะฐ ัะต status.running = ะ˜ะทะฟัŠะปะฝัะฒะฐ ัะต status.success = ะฃัะฟะตัˆะฝะพ -status.waiting = ะ˜ะทั‡ะฐะบะฒะฐ ัะต -status.unknown = ะะตะธะทะฒะตัั‚ะฝะพ status.failure = ะะตัƒัะฟะตัˆะฝะพ +status.cancelled = ะžั‚ะผะตะฝะตะฝะพ status.skipped = ะŸั€ะพะฟัƒัะฝะฐั‚ะพ -unit.desc = ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะธะฝั‚ะตะณั€ะธั€ะฐะฝะธ CI/CD pipelines ั Forgejo Actions. [heatmap] less = ะŸะพ-ะผะฐะปะบะพ @@ -2528,32 +2613,31 @@ eib = ะ•ะธะ‘ [translation_meta] test = ะพะบะตะน +[repo.permissions] +code.read = ะงะตั‚ะตะฝะต: ะ”ะพัั‚ัŠะฟ ะธ ะบะปะพะฝะธั€ะฐะฝะต ะฝะฐ ะบะพะดะฐ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. +code.write = ะŸะธัะฐะฝะต: ะ˜ะทั‚ะปะฐัะบะฒะฐะฝะต ะบัŠะผ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ, ััŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะบะปะพะฝะพะฒะต ะธ ะผะฐั€ะบะตั€ะธ. +issues.read = ะงะตั‚ะตะฝะต: ะงะตั‚ะตะฝะต ะธ ััŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะทะฐะดะฐั‡ะธ ะธ ะบะพะผะตะฝั‚ะฐั€ะธ. +issues.write = ะŸะธัะฐะฝะต: ะ—ะฐั‚ะฒะฐั€ัะฝะต ะฝะฐ ะทะฐะดะฐั‡ะธ ะธ ัƒะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะผะตั‚ะฐะดะฐะฝะฝะธ ะบะฐั‚ะพ ะตั‚ะธะบะตั‚ะธ, ะตั‚ะฐะฟะธ, ะธะทะฟัŠะปะฝะธั‚ะตะปะธ, ะบั€ะฐะนะฝะธ ัั€ะพะบะพะฒะต ะธ ะทะฐะฒะธัะธะผะพัั‚ะธ. +pulls.read = ะงะตั‚ะตะฝะต: ะงะตั‚ะตะฝะต ะธ ััŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต. +pulls.write = ะŸะธัะฐะฝะต: ะ—ะฐั‚ะฒะฐั€ัะฝะต ะฝะฐ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต ะธ ัƒะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะผะตั‚ะฐะดะฐะฝะฝะธ ะบะฐั‚ะพ ะตั‚ะธะบะตั‚ะธ, ะตั‚ะฐะฟะธ, ะธะทะฟัŠะปะฝะธั‚ะตะปะธ, ะบั€ะฐะนะฝะธ ัั€ะพะบะพะฒะต ะธ ะทะฐะฒะธัะธะผะพัั‚ะธ. +releases.read = ะงะตั‚ะตะฝะต: ะŸั€ะตะณะปะตะด ะธ ะธะทั‚ะตะณะปัะฝะต ะฝะฐ ะธะทะดะฐะฝะธั. +wiki.read = ะงะตั‚ะตะฝะต: ะงะตั‚ะตะฝะต ะฝะฐ ะธะฝั‚ะตะณั€ะธั€ะฐะฝะพั‚ะพ ัƒะธะบะธ ะธ ะฝะตะณะพะฒะฐั‚ะฐ ะธัั‚ะพั€ะธั. +wiki.write = ะŸะธัะฐะฝะต: ะกัŠะทะดะฐะฒะฐะฝะต, ะพะฑะฝะพะฒัะฒะฐะฝะต ะธ ะธะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ัั‚ั€ะฐะฝะธั†ะธ ะฒ ะธะฝั‚ะตะณั€ะธั€ะฐะฝะพั‚ะพ ัƒะธะบะธ. +projects.read = ะงะตั‚ะตะฝะต: ะ”ะพัั‚ัŠะฟ ะดะพ ะฟั€ะพะตะบั‚ะฝะธั‚ะต ั‚ะฐะฑะปะฐ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. +projects.write = ะŸะธัะฐะฝะต: ะกัŠะทะดะฐะฒะฐะฝะต ะธ ั€ะตะดะฐะบั‚ะธั€ะฐะฝะต ะฝะฐ ะฟั€ะพะตะบั‚ะธ ะธ ะบะพะปะพะฝะธ. [gpg] default_key = ะŸะพะดะฟะธัะฐะฝะพ ั ะบะปัŽั‡ ะฟะพ ะฟะพะดั€ะฐะทะฑะธั€ะฐะฝะต +error.extract_sign = ะะตัƒัะฟะตัˆะฝะพ ะธะทะฒะปะธั‡ะฐะฝะต ะฝะฐ ะฟะพะดะฟะธั +error.generate_hash = ะะตัƒัะฟะตัˆะฝะพ ะณะตะฝะตั€ะธั€ะฐะฝะต ะฝะฐ ั…ะตัˆ ะฝะฐ ะฟะพะดะฐะฒะฐะฝะตั‚ะพ +error.no_committer_account = ะัะผะฐ ะฐะบะฐัƒะฝั‚, ัะฒัŠั€ะทะฐะฝ ั ะฐะดั€ะตัะฐ ะทะฐ ะตะป. ะฟะพั‰ะฐ ะฝะฐ ะฟะพะดะฐะฒะฐั‰ะธั error.no_gpg_keys_found = ะะต ะต ะฝะฐะผะตั€ะตะฝ ะธะทะฒะตัั‚ะตะฝ ะบะปัŽั‡ ะทะฐ ั‚ะพะทะธ ะฟะพะดะฟะธั ะฒ ะฑะฐะทะฐั‚ะฐ ะดะฐะฝะฝะธ error.not_signed_commit = ะะต ะต ะฟะพะดะฟะธัะฐะฝะพ ะฟะพะดะฐะฒะฐะฝะต -error.generate_hash = ะะตัƒัะฟะตัˆะฝะพ ะณะตะฝะตั€ะธั€ะฐะฝะต ะฝะฐ ั…ะตัˆ ะฝะฐ ะฟะพะดะฐะฒะฐะฝะตั‚ะพ -error.extract_sign = ะะตัƒัะฟะตัˆะฝะพ ะธะทะฒะปะธั‡ะฐะฝะต ะฝะฐ ะฟะพะดะฟะธั -error.probable_bad_signature = ะ’ะะ˜ะœะะะ˜ะ•! ะ’ัŠะฟั€ะตะบะธ ั‡ะต ะธะผะฐ ะบะปัŽั‡ ั ั‚ะพะฒะฐ ID ะฒ ะฑะฐะทะฐั‚ะฐ ะดะฐะฝะฝะธ, ั‚ะพะน ะฝะต ะฟะพั‚ะฒัŠั€ะถะดะฐะฒะฐ ั‚ะพะฒะฐ ะฟะพะดะฐะฒะฐะฝะต! ะขะพะฒะฐ ะฟะพะดะฐะฒะฐะฝะต ะต ะŸะžะ”ะžะ—ะ ะ˜ะขะ•ะ›ะะž. error.failed_retrieval_gpg_keys = ะะตัƒัะฟะตัˆะฝะพ ะธะทะฒะปะธั‡ะฐะฝะต ะฝะฐ ะบะปัŽั‡, ัะฒัŠั€ะทะฐะฝ ั ะฐะบะฐัƒะฝั‚ะฐ ะฝะฐ ะฟะพะดะฐะฒะฐั‰ะธั +error.probable_bad_signature = ะ’ะะ˜ะœะะะ˜ะ•! ะ’ัŠะฟั€ะตะบะธ ั‡ะต ะธะผะฐ ะบะปัŽั‡ ั ั‚ะพะฒะฐ ID ะฒ ะฑะฐะทะฐั‚ะฐ ะดะฐะฝะฝะธ, ั‚ะพะน ะฝะต ะฟะพั‚ะฒัŠั€ะถะดะฐะฒะฐ ั‚ะพะฒะฐ ะฟะพะดะฐะฒะฐะฝะต! ะขะพะฒะฐ ะฟะพะดะฐะฒะฐะฝะต ะต ะŸะžะ”ะžะ—ะ ะ˜ะขะ•ะ›ะะž. error.probable_bad_default_signature = ะ’ะะ˜ะœะะะ˜ะ•! ะ’ัŠะฟั€ะตะบะธ ั‡ะต ะบะปัŽั‡ัŠั‚ ะฟะพ ะฟะพะดั€ะฐะทะฑะธั€ะฐะฝะต ะธะผะฐ ั‚ะพะฒะฐ ID, ั‚ะพะน ะฝะต ะฟะพั‚ะฒัŠั€ะถะดะฐะฒะฐ ั‚ะพะฒะฐ ะฟะพะดะฐะฒะฐะฝะต! ะขะพะฒะฐ ะฟะพะดะฐะฒะฐะฝะต ะต ะŸะžะ”ะžะ—ะ ะ˜ะขะ•ะ›ะะž. -error.no_committer_account = ะัะผะฐ ะฐะบะฐัƒะฝั‚, ัะฒัŠั€ะทะฐะฝ ั ะฐะดั€ะตัะฐ ะทะฐ ะตะป. ะฟะพั‰ะฐ ะฝะฐ ะฟะพะดะฐะฒะฐั‰ะธั - -[repo.permissions] -projects.read = ะงะตั‚ะตะฝะต: ะ”ะพัั‚ัŠะฟ ะดะพ ะฟั€ะพะตะบั‚ะฝะธั‚ะต ั‚ะฐะฑะปะฐ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. -wiki.write = ะŸะธัะฐะฝะต: ะกัŠะทะดะฐะฒะฐะฝะต, ะพะฑะฝะพะฒัะฒะฐะฝะต ะธ ะธะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ัั‚ั€ะฐะฝะธั†ะธ ะฒ ะธะฝั‚ะตะณั€ะธั€ะฐะฝะพั‚ะพ ัƒะธะบะธ. -issues.read = ะงะตั‚ะตะฝะต: ะงะตั‚ะตะฝะต ะธ ััŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะทะฐะดะฐั‡ะธ ะธ ะบะพะผะตะฝั‚ะฐั€ะธ. -pulls.read = ะงะตั‚ะตะฝะต: ะงะตั‚ะตะฝะต ะธ ััŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต. -pulls.write = ะŸะธัะฐะฝะต: ะ—ะฐั‚ะฒะฐั€ัะฝะต ะฝะฐ ะทะฐัะฒะบะธ ะทะฐ ัะปะธะฒะฐะฝะต ะธ ัƒะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะผะตั‚ะฐะดะฐะฝะฝะธ ะบะฐั‚ะพ ะตั‚ะธะบะตั‚ะธ, ะตั‚ะฐะฟะธ, ะธะทะฟัŠะปะฝะธั‚ะตะปะธ, ะบั€ะฐะนะฝะธ ัั€ะพะบะพะฒะต ะธ ะทะฐะฒะธัะธะผะพัั‚ะธ. -projects.write = ะŸะธัะฐะฝะต: ะกัŠะทะดะฐะฒะฐะฝะต ะธ ั€ะตะดะฐะบั‚ะธั€ะฐะฝะต ะฝะฐ ะฟั€ะพะตะบั‚ะธ ะธ ะบะพะปะพะฝะธ. -releases.read = ะงะตั‚ะตะฝะต: ะŸั€ะตะณะปะตะด ะธ ะธะทั‚ะตะณะปัะฝะต ะฝะฐ ะธะทะดะฐะฝะธั. -wiki.read = ะงะตั‚ะตะฝะต: ะงะตั‚ะตะฝะต ะฝะฐ ะธะฝั‚ะตะณั€ะธั€ะฐะฝะพั‚ะพ ัƒะธะบะธ ะธ ะฝะตะณะพะฒะฐั‚ะฐ ะธัั‚ะพั€ะธั. -code.read = ะงะตั‚ะตะฝะต: ะ”ะพัั‚ัŠะฟ ะธ ะบะปะพะฝะธั€ะฐะฝะต ะฝะฐ ะบะพะดะฐ ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. -code.write = ะŸะธัะฐะฝะต: ะ˜ะทั‚ะปะฐัะบะฒะฐะฝะต ะบัŠะผ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ, ััŠะทะดะฐะฒะฐะฝะต ะฝะฐ ะบะปะพะฝะพะฒะต ะธ ะผะฐั€ะบะตั€ะธ. -issues.write = ะŸะธัะฐะฝะต: ะ—ะฐั‚ะฒะฐั€ัะฝะต ะฝะฐ ะทะฐะดะฐั‡ะธ ะธ ัƒะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะผะตั‚ะฐะดะฐะฝะฝะธ ะบะฐั‚ะพ ะตั‚ะธะบะตั‚ะธ, ะตั‚ะฐะฟะธ, ะธะทะฟัŠะปะฝะธั‚ะตะปะธ, ะบั€ะฐะนะฝะธ ัั€ะพะบะพะฒะต ะธ ะทะฐะฒะธัะธะผะพัั‚ะธ. [units] -error.no_unit_allowed_repo = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะทะฐ ะดะพัั‚ัŠะฟ ะดะพ ะฝะธะบะพั ัะตะบั†ะธั ะฝะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต. unit = ะ•ะปะตะผะตะฝั‚ -error.unit_not_allowed = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะทะฐ ะดะพัั‚ัŠะฟ ะดะพ ั‚ะฐะทะธ ัะตะบั†ะธั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. \ No newline at end of file +error.no_unit_allowed_repo = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะทะฐ ะดะพัั‚ัŠะฟ ะดะพ ะฝะธะบะพั ัะตะบั†ะธั ะฝะฐ ั‚ะพะฒะฐ ั…ั€ะฐะฝะธะปะธั‰ะต. +error.unit_not_allowed = ะัะผะฐั‚ะต ั€ะฐะทั€ะตัˆะตะฝะธะต ะทะฐ ะดะพัั‚ัŠะฟ ะดะพ ั‚ะฐะทะธ ัะตะบั†ะธั ะฝะฐ ั…ั€ะฐะฝะธะปะธั‰ะตั‚ะพ. diff --git a/options/locale/locale_ca.ini b/options/locale/locale_ca.ini index 6a7e074618..ea2af3b645 100644 --- a/options/locale/locale_ca.ini +++ b/options/locale/locale_ca.ini @@ -39,7 +39,7 @@ twofa_scratch = Codi de rascar de doble-factor passcode = Codi de pas webauthn_insert_key = Inseriu la vostra clau de seguretat webauthn_sign_in = Premeu el botรณ a la vostra clau de seguretat. Si no en tรฉ, torneu-la a inserir. -webauthn_press_button = Si us plau, premeu el botรณ a la vostra clau de seguretatโ€ฆ +webauthn_press_button = Siusplau, premeu el botรณ a la vostra clau de seguretatโ€ฆ webauthn_use_twofa = Utilitza un codi de doble factor des del teu mรฒbil webauthn_error = No s'ha pogut llegir la clau de seguretat. webauthn_unsupported_browser = El teu navegador no suprta WebAuthn. @@ -48,11 +48,15 @@ webauthn_error_insecure = WebAuthn nomรฉs suporta connexions segures. Per provar webauthn_error_unable_to_process = El servidor no ha pogut processar la vostra peticiรณ. webauthn_error_duplicated = La clau de seguretat no รฉs permesa per aquesta peticiรณ. Si us plau, assegureu-vos que la clau encara no ha estat registrada. webauthn_error_empty = S'ha d'anomenar aquesta clau. +webauthn_reload = Recarrega repository = Repositori organization = Organitzaciรณ mirror = Mirall +new_repo = Nou repositori +new_migrate = Nova migraciรณ new_mirror = Nou mirall new_fork = Nou fork d'un repositori +new_org = Nova organitzaciรณ new_project = Nou projecte new_project_column = Nova columna admin_panel = Administraciรณ del lloc @@ -144,6 +148,7 @@ new_migrate.link = Nova migraciรณ new_org.link = Nova organitzaciรณ [search] +milestone_kind = Cerca fites... fuzzy = Difusa search = Cerca... type_tooltip = Tipus de cerca @@ -151,6 +156,7 @@ fuzzy_tooltip = Inclou resultats que s'assemblen al terme de la cerca repo_kind = Cerca reposโ€ฆ user_kind = Cerca usuarisโ€ฆ code_search_unavailable = La cerca de codi no estร  disponible actualment. Si us plau concteu amb l'administrador del lloc. +code_search_by_git_grep = Els resultats actuals de la cerca de codi sรณn proporcionats per "git grep". Podrรญen haver-hi millors resultats si l'administrador del lloc habilita l'indexador de codi. package_kind = Cerca paquetsโ€ฆ project_kind = Cerca projectesโ€ฆ branch_kind = Cerca branquesโ€ฆ @@ -188,6 +194,8 @@ occurred = Hi ha hagut un error report_message = Si creus que aixรฒ es un bug de Forgejo, si us plau cerca problemes a Codeberg i obre'n un de nou si cal. not_found = L'objectiu no s'ha pogut trobar. server_internal = Error intern del servidor +missing_csrf = Peticiรณ Dolenta: falta el testimoni CSRF +invalid_csrf = Peticiรณ Dolenta: testimoni CSRF invร lid network_error = Error de xarxa [install] @@ -436,6 +444,7 @@ link_modal.paste_reminder = Pista: Amb un enllaรง en el teu porta-retalls, pots [home] my_orgs = Organitzacions +show_more_repos = Mostra mรฉs repositorisโ€ฆ show_both_archived_unarchived = Mostrant ambdรณs arxivats i no-arxivats show_only_public = Mostrant nomรฉs publics issues.in_your_repos = En els teus repositoris @@ -445,8 +454,10 @@ show_both_private_public = Mostrant amdรณs publics i privats show_only_private = Mostrant nomรฉs privats filter_by_team_repositories = Filtra per respostirois d'equip feed_of = Canal de "%s" +collaborative_repos = Respositoris coล€laboratius show_archived = Arxivat view_home = Veure %s +password_holder = Contrasenya switch_dashboard_context = Commuta el contexte del tauler my_repos = Repositoris show_only_archived = Mostrant nomรฉs arxivats @@ -472,290 +483,4 @@ admin.new_user.user_info = Informaciรณ d'usuari admin.new_user.subject = Nou usuari %s s'acaba d'enregistrar activate_email.text = Si us plau, cliqueu el segรผent enllaรง per verificar la vostra adreรงa de correu electrรฒnic en %s activate_email = Verifica la teva adreรงa de correu electrรฒnic -activate_account.text_2 = Si us plau, cliqueu l'enllaรง segรผent per activar el vostre compte en %s: -issue.action.merge = @%[1]s ha fusionat #%[2]d a %[3]s. -release.download.targz = Codi font (TAR.GZ) -repo.transfer.body = Per acceptar-ho o rebutjar-ho, aneu a %s o simplement ignoreu-ho. -team_invite.text_1 = %[1]s us convida a unir-vos a l'equip %[2]s de l'organitzaciรณ %[3]s. -team_invite.text_2 = Si us plau, feu clic al segรผent enllaรง per unir-vos a l'equip: -issue.action.close = @%[1]s ha tancat #%[2]d. -team_invite.text_3 = Nota: aquesta invitaciรณ estava destinada a %[1]s. Si no estร veu esperant-la, podeu ignorar aquest correu electrรฒnic. -team_invite.subject = %[1]s us convida a unir-vos a l'organitzaciรณ %[2]s -release.title = Tรญtol: %s -release.downloads = Baixades: -release.download.zip = Codi font (ZIP) -repo.transfer.subject_to_you = %s us vol transferir el repositori "%s" -repo.collaborator.added.subject = %s us ha afegit a %s com a colยทlaborador -repo.collaborator.added.text = Us han afegit com a colยทlaborador al repositori: -issue_assigned.issue = @%[1]s us ha assignat l'incidรจncia %[2]s del repositori %[3]s. -issue.x_mentioned_you = @%s us ha mencionat: -issue.action.new = @%[1]s ha creat #%[2]d. -repo.transfer.subject_to = %s vol transferir el repositori "%s" a %s - -[modal] -yes = Sรญ -no = No -cancel = Cancelยทlar -confirm = Confirmar - -[form] -FullName = Nom complet -Description = Descripciรณ -Pronouns = Pronoms -UserName = Nom d'usuari -username_change_not_local_user = No es permet canviar el nom d'usuari als usuaris no locals. -repo_name_been_taken = El nom del repositori ja estร  en รบs. -repository_files_already_exist.adopt = Aquest repositori ja tรฉ fitxers i nomรฉs pot ser Adoptat. -Password = ๏ปฟContrasenya -Retype = Confirma la contrasenya -captcha_incorrect = El codi CAPTCHA รฉs incorrecte. -email_error = ` no รฉs una adreรงa de correu electrรฒnic vร lida.` -unable_verify_ssh_key = No es pot verificar la clau SSH, reviseu si contรฉ errors. -auth_failed = Ha fallat l'autenticaciรณ: %v -still_own_packages = El vostre compte tรฉ un o mรฉs paquets, elimineu-los abans. -org_still_own_repo = Aquesta organitzaciรณ encara tรฉ un o mรฉs repositoris, elimineu-los o transferiu-los abans. -admin_cannot_delete_self = No us podeu eliminar si sou administradors. Si us plau, elimineu els vostres privilegis d'administrador abans. -repository_files_already_exist = Aquest repositori ja tรฉ fitxers. Contacteu l'administrador del sistema. -password_uppercase_one = Com a mรญnim un carร cter en majรบscules -team_not_exist = L'equip no existeix. -team_name_been_taken = El nom de l'equip ja estร  en รบs. -last_org_owner = No podeu eliminar l'รบltim usuari de l'equip "propietaris". Una organitzaciรณ ha de tenir un propietari com a mรญnim. -duplicate_invite_to_team = L'usuari ja ha estat convidat com a membre de l'equip. -Biography = Biografia -RepoName = Nom del repositori -TeamName = Nom de l' equip -To = Nom de la branca -NewBranchName = Nom de la nova branca -Content = Contingut -url_error = `"%s" no รฉs una URL vร lida.` -unknown_error = Error desconegut: -password_not_match = Les contrasenyes no coincideixen. -lang_select_error = Seleccioneu un idioma de la llista. -username_been_taken = El nom d'usuari ja estร  en รบs. -repository_files_already_exist.adopt_or_delete = Aquest repositori ja tรฉ fitxers. Adopteu-los o elimineu-los. -org_name_been_taken = El nom de l'organitzaciรณ ja estร  en รบs. -email_been_used = L'adreรงa de correu electrรฒnic ja estร  en รบs. -email_invalid = L'adreรงa de correu electrรฒnic no es vร lida. -password_complexity = La contrasenya no supera els requisits de complexitat: -password_digit_one = Com a mรญnim un dรญgit -password_special_one = Com a mรญnim un carร cter especial (puntuaciรณ, claudร tors, cometes, etc.) -enterred_invalid_repo_name = El nom del repositori que heu introduรฏt รฉs incorrecte. -enterred_invalid_owner_name = El nom del nou propietari no รฉs vร lid. -enterred_invalid_password = La contrasenya que heu introduรฏt no รฉs correcta. -user_not_exist = L'usuari no existeix. -cannot_add_org_to_team = No es pot afegir una organitzaciรณ com a membre d'un equip. -invalid_ssh_key = No es pot verificar la vostra clau SSH: %s -invalid_gpg_key = No es pot verificar la vostra clau GPG: %s -still_has_org = El vostre compte รฉs membre d'una o mรฉs organitzacions, abandoneu-les abans. -still_own_repo = El vostre compte tรฉ un o mรฉs repositoris, elimineu-los o transferiu-los abans. -target_branch_not_exist = La branca de destรญ no existeix. -AuthName = Nom d'autoritzaciรณ -enterred_invalid_org_name = El nom d'organitzaciรณ que heu introduรฏt รฉs incorrecte. -repository_files_already_exist.delete = Aquest repositori ja tรฉ fitxers. Els heu d'eliminar. -organization_leave_success = Heu deixat l'organitzaciรณ %s amb รจxit. -openid_been_used = L'adreรงa OpenID "%s" ja estร  en รบs. -username_password_incorrect = Nom d'usuari o contrasenya incorrecte. -password_lowercase_one = Com a mรญnim un carร cter en minรบscules -must_use_public_key = La clau que heu proporcionat รฉs una clau privada. Si us plau, no pugueu la vostra clau privada enlloc. Feu servir la vostra clau pรบblica. -org_still_own_packages = Aquesta organitzaciรณ encara tรฉ un o mรฉs paquets, elimineu-los abans. - -[settings] -pronouns = Pronoms -change_username_prompt = Nota: canviar el vostre nom d'usuari tambรฉ canvia l'URL del vostre compte. -comment_type_group_time_tracking = Seguiment del temps -comment_type_group_deadline = Data lรญmit -keep_activity_private = Oculta l'activitat de la pร gina de perfil -repos = Repositoris -applications = Aplicacions -location_placeholder = Compartiu la vostra ubicaciรณ aproximada amb altres -security = Seguretat -profile = Perfil -account = Compte -appearance = Aparenรงa -blocked_users = Usuaris bloquejats -cancel = Cancelยทlar -language = Idioma -comment_type_group_reference = Referรจncia -comment_type_group_dependency = Dependรจncia -saved_successfully = La vostra configuraciรณ s'ha desat amb รจxit. -ssh_gpg_keys = Claus SSH / GPG -public_profile = Perfil pรบblic -ui = Tema -hints = Consells -hidden_comment_types.issue_ref_tooltip = Comentaris on l'usuari canvia la branca/etiqueta associada amb aquesta incidรจncia -hidden_comment_types = Tipus de comentaris ocults -orgs = Organitzacions -organization = Organitzacions -full_name = Nom complet -website = Pร gina web -location = Ubicaciรณ -pronouns_unspecified = Sense especificar -update_theme = Canviar el tema -update_language_not_found = L'idioma "%s" no estร  disponible. -update_language_success = S'ha actualitzat l'idioma. -update_profile_success = El vostre perfil s'ha actualitzat. -change_username_redirect_prompt = El nom d'usuari antic redirigirร  fins que algรบ altre el reclami. -additional_repo_units_hint = Suggereix habilitar unitats de repositori addicionals -update_hints = Actualitza els suggeriments -update_hints_success = S'han actualitzat els suggeriments. -comment_type_group_label = Etiqueta -comment_type_group_title = Tรญtol -comment_type_group_branch = Branca -comment_type_group_issue_ref = Referรจncia d'incidรจncia -hidden_comment_types_description = Els tipus de comentaris marcats aquรญ no es mostraran a les pร gines de les incidรจncies. Marcar "Etiqueta", per exemple, eliminarร  tots els comentaris del tipus "