diff --git a/.drone.yml b/.drone.yml index 4ba081e809..99da2b368a 100644 --- a/.drone.yml +++ b/.drone.yml @@ -13,12 +13,25 @@ trigger: - tag - pull_request +volumes: + - name: deps + temp: {} + steps: - name: deps-frontend - pull: always image: node:16 + pull: always commands: - - make node_modules + - make deps-frontend + + - name: deps-backend + image: golang:1.18 + pull: always + commands: + - make deps-backend + volumes: + - name: deps + path: /go - name: lint-frontend image: node:16 @@ -27,36 +40,46 @@ steps: depends_on: [deps-frontend] - name: lint-backend - pull: always image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env + pull: always commands: - make lint-backend environment: - GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not + GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not GOSUMDB: sum.golang.org TAGS: bindata sqlite sqlite_unlock_notify + depends_on: [deps-backend] + volumes: + - name: deps + path: /go - name: lint-backend-windows - pull: always image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env commands: - - make golangci-lint vet + - make golangci-lint-windows vet environment: - GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not + GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not GOSUMDB: sum.golang.org TAGS: bindata sqlite sqlite_unlock_notify GOOS: windows GOARCH: amd64 + depends_on: [deps-backend] + volumes: + - name: deps + path: /go - name: lint-backend-gogit - pull: always image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env commands: - make lint-backend environment: - GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not + GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not GOSUMDB: sum.golang.org TAGS: bindata gogit sqlite sqlite_unlock_notify + depends_on: [deps-backend] + volumes: + - name: deps + path: /go - name: checks-frontend image: node:16 @@ -65,11 +88,13 @@ steps: depends_on: [deps-frontend] - name: checks-backend - pull: always - image: golang:1.17 + image: golang:1.18 commands: - make checks-backend - depends_on: [lint-backend] + depends_on: [deps-backend] + volumes: + - name: deps + path: /go - name: test-frontend image: node:16 @@ -84,50 +109,62 @@ steps: depends_on: [test-frontend] - name: build-backend-no-gcc - pull: always image: golang:1.16 # this step is kept as the lowest version of golang that we support + pull: always environment: GO111MODULE: on - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io commands: - go build -o gitea_no_gcc # test if build succeeds without the sqlite tag - depends_on: [checks-backend] + depends_on: [deps-backend, checks-backend] + volumes: + - name: deps + path: /go - name: build-backend-arm64 - image: golang:1.17 + image: golang:1.18 environment: GO111MODULE: on - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io GOOS: linux GOARCH: arm64 TAGS: bindata gogit commands: - make backend # test cross compile - rm ./gitea # clean - depends_on: [checks-backend] + depends_on: [deps-backend, checks-backend] + volumes: + - name: deps + path: /go - name: build-backend-windows - image: golang:1.17 + image: golang:1.18 environment: GO111MODULE: on - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io GOOS: windows GOARCH: amd64 TAGS: bindata gogit commands: - go build -o gitea_windows - depends_on: [checks-backend] + depends_on: [deps-backend, checks-backend] + volumes: + - name: deps + path: /go - name: build-backend-386 - image: golang:1.17 + image: golang:1.18 environment: GO111MODULE: on - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io GOOS: linux GOARCH: 386 commands: - go build -o gitea_linux_386 # test if compatible with 32 bit - depends_on: [checks-backend] + depends_on: [deps-backend, checks-backend] + volumes: + - name: deps + path: /go --- kind: pipeline @@ -147,21 +184,28 @@ trigger: - tag - pull_request +volumes: + - name: deps + temp: {} + services: - name: mysql image: mysql:5.7 + pull: always environment: MYSQL_ALLOW_EMPTY_PASSWORD: yes MYSQL_DATABASE: test - name: mysql8 image: mysql:8 + pull: always environment: MYSQL_ALLOW_EMPTY_PASSWORD: yes MYSQL_DATABASE: testgitea - name: mssql image: mcr.microsoft.com/mssql/server:latest + pull: always environment: ACCEPT_EULA: Y MSSQL_PID: Standard @@ -169,14 +213,17 @@ services: - name: ldap image: gitea/test-openldap:latest + pull: always - name: elasticsearch + image: elasticsearch:7.5.0 + pull: always environment: discovery.type: single-node - image: elasticsearch:7.5.0 - name: minio image: minio/minio:RELEASE.2021-03-12T00-00-47Z + pull: always commands: - minio server /data environment: @@ -186,37 +233,50 @@ services: steps: - name: fetch-tags image: docker:git + pull: always commands: + - git config --global --add safe.directory /drone/src - git fetch --tags --force when: event: exclude: - pull_request - - name: tag-pre-condition + - name: deps-backend + image: golang:1.18 pull: always + commands: + - make deps-backend + volumes: + - name: deps + path: /go + + - name: tag-pre-condition image: drone/git + pull: always commands: - git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA} - name: prepare-test-env image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env + pull: always commands: - ./build/test-env-prepare.sh - name: build - pull: always image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env user: gitea commands: - ./build/test-env-check.sh - make backend environment: - GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not + GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not GOSUMDB: sum.golang.org TAGS: bindata sqlite sqlite_unlock_notify - depends_on: - - prepare-test-env + depends_on: [deps-backend, prepare-test-env] + volumes: + - name: deps + path: /go - name: unit-test image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env @@ -224,24 +284,31 @@ steps: commands: - make unit-test-coverage test-check environment: - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io TAGS: bindata sqlite sqlite_unlock_notify RACE_ENABLED: true GITHUB_READ_TOKEN: from_secret: github_read_token + depends_on: [deps-backend, prepare-test-env] + volumes: + - name: deps + path: /go - name: unit-test-gogit - pull: always image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env user: gitea commands: - make unit-test-coverage test-check environment: - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io TAGS: bindata gogit sqlite sqlite_unlock_notify RACE_ENABLED: true GITHUB_READ_TOKEN: from_secret: github_read_token + depends_on: [deps-backend, prepare-test-env] + volumes: + - name: deps + path: /go - name: test-mysql image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env @@ -249,14 +316,16 @@ steps: commands: - make test-mysql-migration integration-test-coverage environment: - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io TAGS: bindata RACE_ENABLED: true TEST_LDAP: 1 USE_REPO_TEST_DIR: 1 TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200" - depends_on: - - build + depends_on: [build] + volumes: + - name: deps + path: /go - name: test-mysql8 image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env @@ -264,13 +333,15 @@ steps: commands: - timeout -s ABRT 40m make test-mysql8-migration test-mysql8 environment: - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io TAGS: bindata RACE_ENABLED: true TEST_LDAP: 1 USE_REPO_TEST_DIR: 1 - depends_on: - - build + depends_on: [build] + volumes: + - name: deps + path: /go - name: test-mssql image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env @@ -278,24 +349,24 @@ steps: commands: - make test-mssql-migration test-mssql environment: - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io TAGS: bindata RACE_ENABLED: true TEST_LDAP: 1 USE_REPO_TEST_DIR: 1 - depends_on: - - build + depends_on: [build] + volumes: + - name: deps + path: /go - name: generate-coverage - image: golang:1.17 + image: golang:1.18 commands: - make coverage environment: - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io TAGS: bindata - depends_on: - - unit-test - - test-mysql + depends_on: [unit-test, test-mysql] when: branch: - main @@ -304,15 +375,14 @@ steps: - pull_request - name: coverage-codecov + image: woodpeckerci/plugin-codecov:next-alpine pull: always - image: plugins/codecov settings: files: - coverage.all token: from_secret: codecov_token - depends_on: - - generate-coverage + depends_on: [generate-coverage] when: branch: - main @@ -337,6 +407,10 @@ trigger: - tag - pull_request +volumes: + - name: deps + temp: {} + services: - name: pgsql pull: default @@ -352,31 +426,44 @@ services: steps: - name: fetch-tags image: docker:git + pull: always commands: + - git config --global --add safe.directory /drone/src - git fetch --tags --force when: event: exclude: - pull_request + - name: deps-backend + image: golang:1.18 + pull: always + commands: + - make deps-backend + volumes: + - name: deps + path: /go + - name: prepare-test-env image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env + pull: always commands: - ./build/test-env-prepare.sh - name: build - pull: always image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env user: gitea commands: - ./build/test-env-check.sh - make backend environment: - GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not + GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not GOSUMDB: sum.golang.org TAGS: bindata gogit sqlite sqlite_unlock_notify - depends_on: - - prepare-test-env + depends_on: [deps-backend, prepare-test-env] + volumes: + - name: deps + path: /go - name: test-sqlite image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env @@ -384,13 +471,15 @@ steps: commands: - timeout -s ABRT 40m make test-sqlite-migration test-sqlite environment: - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io TAGS: bindata gogit sqlite sqlite_unlock_notify RACE_ENABLED: true TEST_TAGS: gogit sqlite sqlite_unlock_notify USE_REPO_TEST_DIR: 1 - depends_on: - - build + depends_on: [build] + volumes: + - name: deps + path: /go - name: test-pgsql image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env @@ -398,14 +487,16 @@ steps: commands: - timeout -s ABRT 40m make test-pgsql-migration test-pgsql environment: - GOPROXY: https://goproxy.cn + GOPROXY: https://goproxy.io TAGS: bindata gogit RACE_ENABLED: true TEST_TAGS: gogit TEST_LDAP: 1 USE_REPO_TEST_DIR: 1 - depends_on: - - build + depends_on: [build] + volumes: + - name: deps + path: /go --- kind: pipeline @@ -425,8 +516,8 @@ trigger: steps: - name: download - pull: always image: jonasfranz/crowdin + pull: always settings: download: true export_dir: options/locale/ @@ -437,14 +528,14 @@ steps: from_secret: crowdin_key - name: update - pull: default image: alpine:3.13 + pull: always commands: - ./build/update-locales.sh - name: push - pull: always image: appleboy/drone-git-push + pull: always settings: author_email: "teabot@gitea.io" author_name: GiteaBot @@ -457,8 +548,8 @@ steps: from_secret: git_push_ssh_key - name: upload_translations - pull: always image: jonasfranz/crowdin + pull: always settings: files: locale_en-US.ini: options/locale/locale_en-US.ini @@ -487,13 +578,14 @@ trigger: steps: - name: download - image: golang:1.17 + image: golang:1.18 + pull: always commands: - timeout -s ABRT 40m make generate-license generate-gitignore - name: push - pull: always image: appleboy/drone-git-push + pull: always settings: author_email: "teabot@gitea.io" author_name: GiteaBot @@ -529,26 +621,50 @@ depends_on: - testing-amd64 - testing-arm64 +volumes: + - name: deps + temp: {} + steps: - name: fetch-tags image: docker:git + pull: always commands: + - git config --global --add safe.directory /drone/src - git fetch --tags --force - - name: static + - name: deps-frontend + image: node:16 + pull: always + commands: + - make deps-frontend + + - name: deps-backend + image: golang:1.18 + pull: always + commands: + - make deps-backend + volumes: + - name: deps + path: /go + + - name: static + image: techknowlogick/xgo:go-1.18.x pull: always - image: techknowlogick/xgo:go-1.17.x commands: - curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - export PATH=$PATH:$GOPATH/bin - make release environment: - GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not + GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not TAGS: bindata sqlite sqlite_unlock_notify + volumes: + - name: deps + path: /go - name: gpg-sign - pull: always image: plugins/gpgsign:1 + pull: always settings: detach_sign: true excludes: @@ -562,12 +678,12 @@ steps: from_secret: gpgsign_passphrase - name: release-branch - pull: always image: woodpeckerci/plugin-s3:latest + pull: always settings: acl: public-read bucket: gitea-artifacts - endpoint: https://storage.gitea.io + endpoint: https://ams3.digitaloceanspaces.com path_style: true source: "dist/release/*" strip_prefix: dist/release/ @@ -588,7 +704,7 @@ steps: settings: acl: public-read bucket: gitea-artifacts - endpoint: https://storage.gitea.io + endpoint: https://ams3.digitaloceanspaces.com path_style: true source: "dist/release/*" strip_prefix: dist/release/ @@ -624,27 +740,51 @@ depends_on: - testing-arm64 - testing-amd64 +volumes: + - name: deps + temp: {} + steps: - name: fetch-tags - pull: default image: docker:git + pull: always commands: + - git config --global --add safe.directory /drone/src - git fetch --tags --force - - name: static + - name: deps-frontend + image: node:16 + pull: always + commands: + - make deps-frontend + + - name: deps-backend + image: golang:1.18 + pull: always + commands: + - make deps-backend + volumes: + - name: deps + path: /go + + - name: static + image: techknowlogick/xgo:go-1.18.x pull: always - image: techknowlogick/xgo:go-1.17.x commands: - curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - export PATH=$PATH:$GOPATH/bin - make release environment: - GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not + GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not TAGS: bindata sqlite sqlite_unlock_notify + depends_on: [fetch-tags] + volumes: + - name: deps + path: /go - name: gpg-sign - pull: always image: plugins/gpgsign:1 + pull: always settings: detach_sign: true excludes: @@ -656,14 +796,15 @@ steps: from_secret: gpgsign_key GPGSIGN_PASSPHRASE: from_secret: gpgsign_passphrase + depends_on: [static] - name: release-tag - pull: always image: woodpeckerci/plugin-s3:latest + pull: always settings: acl: public-read bucket: gitea-artifacts - endpoint: https://storage.gitea.io + endpoint: https://ams3.digitaloceanspaces.com path_style: true source: "dist/release/*" strip_prefix: dist/release/ @@ -673,16 +814,19 @@ steps: from_secret: aws_access_key_id AWS_SECRET_ACCESS_KEY: from_secret: aws_secret_access_key + depends_on: [gpg-sign] - name: github + image: plugins/github-release:latest pull: always - image: plugins/github-release:1 settings: files: - "dist/release/*" + file_exists: overwrite environment: GITHUB_TOKEN: from_secret: github_token + depends_on: [gpg-sign] --- kind: pipeline @@ -704,16 +848,16 @@ trigger: steps: - name: build-docs - pull: always image: plugins/hugo:latest + pull: always commands: - apk add --no-cache make bash curl - cd docs - make trans-copy clean build - name: publish-docs - pull: always image: techknowlogick/drone-netlify:latest + pull: always settings: path: docs/public/ site_id: d2260bae-7861-4c02-8646-8f6440b12672 @@ -749,18 +893,23 @@ trigger: steps: - name: fetch-tags image: docker:git + pull: always commands: + - git config --global --add safe.directory /drone/src - git fetch --tags --force - name: publish - pull: always image: techknowlogick/drone-docker:latest + pull: always settings: - auto_tag: true + auto_tag: false auto_tag_suffix: linux-amd64 + tags: + - ${DRONE_TAG##v}-linux-amd64 + - ${DRONE_TAG:1:4}-linux-amd64 repo: gitea/gitea build_args: - - GOPROXY=https://goproxy.cn + - GOPROXY=https://goproxy.io password: from_secret: docker_password username: @@ -774,11 +923,14 @@ steps: image: techknowlogick/drone-docker:latest settings: dockerfile: Dockerfile.rootless - auto_tag: true + auto_tag: false auto_tag_suffix: linux-amd64-rootless + tags: + - ${DRONE_TAG##v}-linux-amd64-rootless + - ${DRONE_TAG:1:4}-linux-amd64-rootless repo: gitea/gitea build_args: - - GOPROXY=https://goproxy.cn + - GOPROXY=https://goproxy.io password: from_secret: docker_password username: @@ -811,18 +963,20 @@ trigger: steps: - name: fetch-tags image: docker:git + pull: always commands: + - git config --global --add safe.directory /drone/src - git fetch --tags --force - name: publish - pull: always image: techknowlogick/drone-docker:latest + pull: always settings: auto_tag: false tags: dev-linux-amd64 repo: gitea/gitea build_args: - - GOPROXY=https://goproxy.cn + - GOPROXY=https://goproxy.io password: from_secret: docker_password username: @@ -840,7 +994,70 @@ steps: tags: dev-linux-amd64-rootless repo: gitea/gitea build_args: - - GOPROXY=https://goproxy.cn + - GOPROXY=https://goproxy.io + password: + from_secret: docker_password + username: + from_secret: docker_username + when: + event: + exclude: + - pull_request + +--- +kind: pipeline +name: docker-linux-amd64-release-branch + +platform: + os: linux + arch: amd64 + +depends_on: + - testing-amd64 + - testing-arm64 + +trigger: + ref: + - "refs/heads/release/v*" + event: + exclude: + - cron + +steps: + - name: fetch-tags + image: docker:git + pull: always + commands: + - git config --global --add safe.directory /drone/src + - git fetch --tags --force + + - name: publish + image: techknowlogick/drone-docker:latest + pull: always + settings: + auto_tag: false + tags: ${DRONE_BRANCH##release/v}-dev-linux-amd64 + repo: gitea/gitea + build_args: + - GOPROXY=https://goproxy.io + password: + from_secret: docker_password + username: + from_secret: docker_username + when: + event: + exclude: + - pull_request + + - name: publish-rootless + image: techknowlogick/drone-docker:latest + settings: + dockerfile: Dockerfile.rootless + auto_tag: false + tags: ${DRONE_BRANCH##release/v}-dev-linux-amd64-rootless + repo: gitea/gitea + build_args: + - GOPROXY=https://goproxy.io password: from_secret: docker_password username: @@ -868,14 +1085,14 @@ trigger: steps: - name: dryrun - pull: always image: techknowlogick/drone-docker:latest + pull: always settings: dry_run: true repo: gitea/gitea tags: linux-arm64 build_args: - - GOPROXY=https://goproxy.cn + - GOPROXY=https://goproxy.io environment: PLUGIN_MIRROR: from_secret: plugin_mirror @@ -906,18 +1123,23 @@ trigger: steps: - name: fetch-tags image: docker:git + pull: always commands: + - git config --global --add safe.directory /drone/src - git fetch --tags --force - name: publish - pull: always image: techknowlogick/drone-docker:latest + pull: always settings: - auto_tag: true + auto_tag: false auto_tag_suffix: linux-arm64 + tags: + - ${DRONE_TAG##v}-linux-arm64 + - ${DRONE_TAG:1:4}-linux-arm64 repo: gitea/gitea build_args: - - GOPROXY=https://goproxy.cn + - GOPROXY=https://goproxy.io password: from_secret: docker_password username: @@ -931,11 +1153,14 @@ steps: image: techknowlogick/drone-docker:latest settings: dockerfile: Dockerfile.rootless - auto_tag: true + auto_tag: false auto_tag_suffix: linux-arm64-rootless + tags: + - ${DRONE_TAG##v}-linux-arm64-rootless + - ${DRONE_TAG:1:4}-linux-arm64-rootless repo: gitea/gitea build_args: - - GOPROXY=https://goproxy.cn + - GOPROXY=https://goproxy.io password: from_secret: docker_password username: @@ -968,18 +1193,20 @@ trigger: steps: - name: fetch-tags image: docker:git + pull: always commands: + - git config --global --add safe.directory /drone/src - git fetch --tags --force - name: publish - pull: always image: techknowlogick/drone-docker:latest + pull: always settings: auto_tag: false tags: dev-linux-arm64 repo: gitea/gitea build_args: - - GOPROXY=https://goproxy.cn + - GOPROXY=https://goproxy.io password: from_secret: docker_password username: @@ -997,7 +1224,7 @@ steps: tags: dev-linux-arm64-rootless repo: gitea/gitea build_args: - - GOPROXY=https://goproxy.cn + - GOPROXY=https://goproxy.io password: from_secret: docker_password username: @@ -1006,6 +1233,70 @@ steps: event: exclude: - pull_request + +--- +kind: pipeline +name: docker-linux-arm64-release-branch + +platform: + os: linux + arch: arm64 + +depends_on: + - testing-amd64 + - testing-arm64 + +trigger: + ref: + - "refs/heads/release/v*" + event: + exclude: + - cron + +steps: + - name: fetch-tags + image: docker:git + pull: always + commands: + - git config --global --add safe.directory /drone/src + - git fetch --tags --force + + - name: publish + image: techknowlogick/drone-docker:latest + pull: always + settings: + auto_tag: false + tags: ${DRONE_BRANCH##release/v}-dev-linux-arm64 + repo: gitea/gitea + build_args: + - GOPROXY=https://goproxy.io + password: + from_secret: docker_password + username: + from_secret: docker_username + when: + event: + exclude: + - pull_request + + - name: publish-rootless + image: techknowlogick/drone-docker:latest + settings: + dockerfile: Dockerfile.rootless + auto_tag: false + tags: ${DRONE_BRANCH##release/v}-dev-linux-arm64-rootless + repo: gitea/gitea + build_args: + - GOPROXY=https://goproxy.io + password: + from_secret: docker_password + username: + from_secret: docker_username + when: + event: + exclude: + - pull_request + --- kind: pipeline type: docker @@ -1017,10 +1308,10 @@ platform: steps: - name: manifest-rootless - pull: always image: plugins/manifest + pull: always settings: - auto_tag: true + auto_tag: false ignore_missing: true spec: docker/manifest.rootless.tmpl password: @@ -1031,7 +1322,7 @@ steps: - name: manifest image: plugins/manifest settings: - auto_tag: true + auto_tag: false ignore_missing: true spec: docker/manifest.tmpl password: @@ -1063,6 +1354,7 @@ steps: - name: manifest-rootless pull: always image: plugins/manifest + pull: always settings: auto_tag: false ignore_missing: true @@ -1086,6 +1378,7 @@ steps: trigger: ref: - refs/heads/main + - "refs/heads/release/v*" event: exclude: - cron @@ -1093,6 +1386,8 @@ trigger: depends_on: - docker-linux-amd64-release - docker-linux-arm64-release + - docker-linux-amd64-release-branch + - docker-linux-arm64-release-branch --- kind: pipeline @@ -1126,14 +1421,16 @@ depends_on: - docker-linux-arm64-release - docker-linux-amd64-release-version - docker-linux-arm64-release-version + - docker-linux-amd64-release-branch + - docker-linux-arm64-release-branch - docker-manifest - docker-manifest-version - docs steps: - name: discord - pull: always image: appleboy/drone-discord:1.2.4 + pull: always settings: message: "{{#success build.status}} āœ… Build #{{build.number}} of `{{repo.name}}` succeeded.\n\nšŸ“ Commit by {{commit.author}} on `{{commit.branch}}`:\n``` {{commit.message}} ```\n\n🌐 {{ build.link }} {{else}} āŒ Build #{{build.number}} of `{{repo.name}}` failed.\n\nšŸ“ Commit by {{commit.author}} on `{{commit.branch}}`:\n``` {{commit.message}} ```\n\n🌐 {{ build.link }} {{/success}}\n" webhook_id: diff --git a/.gitignore b/.gitignore index 98975fab49..eab92b49ad 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,8 @@ _testmain.go coverage.all cpu.out +/modules/migration/bindata.go +/modules/migration/bindata.go.hash /modules/options/bindata.go /modules/options/bindata.go.hash /modules/public/bindata.go diff --git a/.golangci.yml b/.golangci.yml index 235bb76715..626334b52e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -13,7 +13,7 @@ linters: #- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time. - gofmt - misspell - - gocritic + #- gocritic # TODO: disabled until fixed with go 1.18 - bidichk - ineffassign - revive @@ -22,7 +22,11 @@ linters: fast: false run: - timeout: 3m + timeout: 10m + skip-dirs: + - node_modules + - public + - web_src linters-settings: gocritic: @@ -57,6 +61,9 @@ linters-settings: - name: errorf - name: duplicated-imports - name: modifies-value-receiver + gofumpt: + extra-rules: true + lang-version: 1.18 issues: exclude-rules: @@ -144,3 +151,11 @@ issues: - path: models/user/openid.go linters: - golint + - linters: staticcheck + text: "strings.Title is deprecated: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead." + - linters: staticcheck + text: "util.FindClosure is deprecated: This function can not handle newlines. Many elements can be existed over multiple lines(e.g. link labels). Use text.Reader.FindClosure." + - linters: staticcheck + text: "gossh.SigAlgoRSASHA2256 is deprecated: use KeyAlgoRSASHA256." + - linters: staticcheck + text: "gossh.SigAlgoRSASHA2512 is deprecated: use KeyAlgoRSASHA512." diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c3c67dd7b..bfd7efdcd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,275 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). -## [1.16.0-rc1](https://github.com/go-gitea/gitea/releases/tag/v1.16.0-rc1) - 2022-01-19 +## [1.16.9](https://github.com/go-gitea/gitea/releases/tag/v1.16.9) - 2022-07-12 + +* SECURITY + * Add write check for creating Commit status (#20332) (#20334) + * Check for permission when fetching user controlled issues (#20133) (#20196) +* BUGFIXES + * Hide notify mail setting ui if not enabled (#20138) (#20337) + * Add write check for creating Commit status (#20332) (#20334) + * Only show Followers that current user can access (#20220) (#20253) + * Release page show all tags in compare dropdown (#20070) (#20071) + * Fix permission check for delete tag (#19985) (#20001) + * Only log non ErrNotExist errors in git.GetNote (#19884) (#19905) + * Use exact search instead of fuzzy search for branch filter dropdown (#19885) (#19893) + * Set Setpgid on child git processes (#19865) (#19881) + * Import git from alpine 3.16 repository as 2.30.4 is needed for `safe.directory = '*'` to work but alpine 3.13 has 2.30.3 (#19876) + * Ensure responses are context.ResponseWriters (#19843) (#19859) + * Fix incorrect usage of `Count` function (#19850) + * Fix raw endpoint PDF file headers (#19825) (#19826) + * Make WIP prefixes case insensitive, e.g. allow `Draft` as a WIP prefix (#19780) (#19811) + * Don't return 500 on NotificationUnreadCount (#19802) + * Prevent NPE when cache service is disabled (#19703) (#19783) + * Detect truncated utf-8 characters at the end of content as still representing utf-8 (#19773) (#19774) + * Fix doctor pq: syntax error at or near "." quote user table name (#19765) (#19770) + * Fix bug with assigneees (#19757) + +## [1.16.8](https://github.com/go-gitea/gitea/releases/tag/v1.16.8) - 2022-05-16 + +* ENHANCEMENTS + * Add doctor check/fix for bogus action rows (#19656) (#19669) + * Make .cs highlighting legible on dark themes. (#19604) (#19605) +* BUGFIXES + * Fix oauth setting list bug (#19681) + * Delete user related oauth stuff on user deletion too (#19677) (#19680) + * Fix new release from tags list UI (#19670) (#19673) + * Prevent NPE when checking repo units if the user is nil (#19625) (#19630) + * GetFeeds must always discard actions with dangling repo_id (#19598) (#19629) + * Call MultipartForm.RemoveAll when request finishes (#19606) (#19607) + * Avoid MoreThanOne error when creating a branch whose name conflicts with other ref names (#19557) (#19591) + * Fix sending empty notifications (#19589) (#19590) + * Ignore DNS error when doing migration allow/block check (#19566) (#19567) + * Fix issue overview for teams (#19652) (#19653) + +## [1.16.7](https://github.com/go-gitea/gitea/releases/tag/v1.16.7) - 2022-05-02 + +* SECURITY + * Escape git fetch remote (#19487) (#19490) +* BUGFIXES + * Don't overwrite err with nil (#19572) (#19574) + * On Migrations, only write commit-graph if wiki clone was successful (#19563) (#19568) + * Respect DefaultUserIsRestricted system default when creating new user (#19310) (#19560) + * Don't error when branch's commit doesn't exist (#19547) (#19548) + * Support `hostname:port` to pass host matcher's check (#19543) (#19544) + * Prevent intermittent race in attribute reader close (#19537) (#19539) + * Fix 64-bit atomic operations on 32-bit machines (#19531) (#19532) + * Prevent dangling archiver goroutine (#19516) (#19526) + * Fix migrate release from github (#19510) (#19523) + * When view _Siderbar or _Footer, just display once (#19501) (#19522) + * Fix blame page select range error and some typos (#19503) + * Fix name of doctor fix "authorized-keys" in hints (#19464) (#19484) + * User specific repoID or xorm builder conditions for issue search (#19475) (#19476) + * Prevent dangling cat-file calls (goroutine alternative) (#19454) (#19466) + * RepoAssignment ensure to close before overwrite (#19449) (#19460) + * Set correct PR status on 3way on conflict checking (#19457) (#19458) + * Mark TemplateLoading error as "UnprocessableEntity" (#19445) (#19446) + +## [1.16.6](https://github.com/go-gitea/gitea/releases/tag/v1.16.6) - 2022-04-20 + +* ENHANCEMENTS + * Only request write when necessary (#18657) (#19422) + * Disable service worker by default (#18914) (#19342) +* BUGFIXES + * When dumping trim the standard suffices instead of a random suffix (#19440) (#19447) + * Fix DELETE request for non-existent public key (#19443) (#19444) + * Don't panic on ErrEmailInvalid (#19441) (#19442) + * Add uploadpack.allowAnySHA1InWant to allow --filter=blob:none with older git clients (#19430) (#19438) + * Warn on SSH connection for incorrect configuration (#19317) (#19437) + * Search Issues via API, dont show 500 if filter result in empty list (#19244) (#19436) + * When updating mirror repo intervals by API reschedule next update too (#19429) (#19433) + * Fix nil error when some pages are rendered outside request context (#19427) (#19428) + * Fix double blob-hunk on diff page (#19404) (#19405) + * Don't allow merging PR's which are being conflict checked (#19357) (#19358) + * Fix middleware function's placements (#19377) (#19378) + * Fix invalid CSRF token bug, make sure CSRF tokens can be up-to-date (#19338) + * Restore user autoregistration with email addresses (#19261) (#19312) + * Move checks for pulls before merge into own function (#19271) (#19277) + * Granular webhook events in editHook (#19251) (#19257) + * Only send webhook events to active system webhooks and only deliver to active hooks (#19234) (#19248) + * Use full output of git show-ref --tags to get tags for PushUpdateAddTag (#19235) (#19236) + * Touch mirrors on even on fail to update (#19217) (#19233) + * Hide sensitive content on admin panel progress monitor (#19218 & #19226) (#19231) + * Fix clone url JS error for the empty repo page (#19209) + * Bump goldmark to v1.4.11 (#19201) (#19203) +* TESTING + * Prevent intermittent failures in RepoIndexerTest (#19225 #19229) (#19228) +* BUILD + * Revert the minimal golang version requirement from 1.17 to 1.16 and add a warning in Makefile (#19319) +* MISC + * Performance improvement for add team user when org has more than 1000 repositories (#19227) (#19289) + * Check go and nodejs version by go.mod and package.json (#19197) (#19254) + +## [1.16.5](https://github.com/go-gitea/gitea/releases/tag/v1.16.5) - 2022-03-23 + +* BREAKING + * Bump to build with go1.18 (#19120 et al) (#19127) +* SECURITY + * Prevent redirect to Host (2) (#19175) (#19186) + * Try to prevent autolinking of displaynames by email readers (#19169) (#19183) + * Clean paths when looking in Storage (#19124) (#19179) + * Do not send notification emails to inactive users (#19131) (#19139) + * Do not send activation email if manual confirm is set (#19119) (#19122) +* ENHANCEMENTS + * Use the new/choose link for New Issue on project page (#19172) (#19176) +* BUGFIXES + * Fix showing issues in your repositories (#18916) (#19191) + * Fix compare link in active feeds for new branch (#19149) (#19185) + * Redirect .wiki/* ui link to /wiki (#18831) (#19184) + * Ensure deploy keys with write access can push (#19010) (#19182) + * Ensure that setting.LocalURL always has a trailing slash (#19171) (#19177) + * Cleanup protected branches when deleting users & teams (#19158) (#19174) + * Use IterateBufferSize whilst querying repositories during adoption check (#19140) (#19160) + * Fix NPE /repos/issues/search when not signed in (#19154) (#19155) + * Use custom favicon when viewing static files if it exists (#19130) (#19152) + * Fix the editor height in review box (#19003) (#19147) + * Ensure isSSH is set whenever DISABLE_HTTP_GIT is set (#19028) (#19146) + * Fix wrong scopes caused by empty scope input (#19029) (#19145) + * Make migrations SKIP_TLS_VERIFY apply to git too (#19132) (#19141) + * Handle email address not exist (#19089) (#19121) +* MISC + * Update json-iterator to allow compilation with go1.18 (#18644) (#19100) + * Update golang.org/x/crypto (#19097) (#19098) + +## [1.16.4](https://github.com/go-gitea/gitea/releases/tag/v1.16.4) - 2022-03-14 + +* SECURITY + * Restrict email address validation (#17688) (#19085) + * Fix lfs bug (#19072) (#19080) +* ENHANCEMENTS + * Improve SyncMirrors logging (#19045) (#19050) +* BUGFIXES + * Refactor mirror code & fix `StartToMirror` (#18904) (#19075) + * Update the webauthn_credential_id_sequence in Postgres (#19048) (#19060) + * Prevent 500 when there is an error during new auth source post (#19041) (#19059) + * If rendering has failed due to a net.OpError stop rendering (attempt 2) (#19049) (#19056) + * Fix flag validation (#19046) (#19051) + * Add pam account authorization check (#19040) (#19047) + * Ignore missing comment for user notifications (#18954) (#19043) + * Set `rel="nofollow noindex"` on new issue links (#19023) (#19042) + * Upgrading binding package (#19034) (#19035) + * Don't show context cancelled errors in attribute reader (#19006) (#19027) + * Fix update hint bug (#18996) (#19002) +* MISC + * Fix potential assignee query for repo (#18994) (#18999) + +## [1.16.3](https://github.com/go-gitea/gitea/releases/tag/v1.16.3) - 2022-03-02 + +* SECURITY + * Git backend ignore replace objects (#18979) (#18980) +* ENHANCEMENTS + * Adjust error for already locked db and prevent level db lock on malformed connstr (#18923) (#18938) +* BUGFIXES + * Set max text height to prevent overflow (#18862) (#18977) + * Fix newAttachmentPaths deletion for DeleteRepository() (#18973) (#18974) + * Accounts with WebAuthn only (no TOTP) now exist ... fix code to handle that case (#18897) (#18964) + * Send 404 on `/{org}.gpg` (#18959) (#18962) + * Fix admin user list pagination (#18957) (#18960) + * Fix lfs management setting (#18947) (#18946) + * Fix login with email panic when email is not exist (#18942) + * Update go-org to v1.6.1 (#18932) (#18933) + * Fix `` html in translation (#18929) (#18931) + * Fix page and missing return on unadopted repos API (#18848) (#18927) + * Allow adminstrator teams members to see other teams (#18918) (#18919) + * Don't treat BOM escape sequence as hidden character. (#18909) (#18910) + * Correctly link URLs to users/repos with dashes, dots or underscores (… (#18908) + * Fix redirect when using lowercase repo name (#18775) (#18902) + * Fix migration v210 (#18893) (#18892) + * Fix team management UI (#18887) (18886) + * BeforeSourcePath should point to base commit (#18880) (#18799) +* TRANSLATION + * Backport locales from master (#18944) +* MISC + * Don't update email for organisation (#18905) (#18906) + +## [1.16.2](https://github.com/go-gitea/gitea/releases/tag/v1.16.2) - 2022-02-24 + +* ENHANCEMENTS + * Show fullname on issue edits and gpg/ssh signing info (#18828) + * Immediately Hammer if second kill is sent (#18823) (#18826) + * Allow mermaid render error to wrap (#18791) +* BUGFIXES + * Fix ldap user sync missed email in email_address table (#18786) (#18876) + * Update assignees check to include any writing team and change org sidebar (#18680) (#18873) + * Don't report signal: killed errors in serviceRPC (#18850) (#18865) + * Fix bug where certain LDAP settings were reverted (#18859) + * Update go-org to 1.6.0 (#18824) (#18839) + * Fix login with email for ldap users (#18800) (#18836) + * Fix bug for get user by email (#18834) + * Fix panic in EscapeReader (#18820) (#18821) + * Fix ldap loginname (#18789) (#18804) + * Remove redundant call to UpdateRepoStats during migration (#18591) (#18794) + * In disk_channel queues synchronously push to disk on shutdown (#18415) (#18788) + * Fix template bug of LFS lock (#18784) (#18787) + * Attempt to fix the webauthn migration again - part 3 (#18770) (#18771) + * Send mail to issue/pr assignee/reviewer also when OnMention is set (#18707) (#18765) + * Fix a broken link in commits_list_small.tmpl (#18763) (#18764) + * Increase the size of the webauthn_credential credential_id field (#18739) (#18756) + * Prevent dangling GetAttribute calls (#18754) (#18755) + * Fix isempty detection of git repository (#18746) (#18750) + * Fix source code line highlighting on external tracker (#18729) (#18740) + * Prevent double encoding of branch names in delete branch (#18714) (#18738) + * Always set PullRequestWorkInProgressPrefixes in PrepareViewPullInfo (#18713) (#18737) + * Fix forked repositories missed tags (#18719) (#18735) + * Fix release typo (#18728) (#18731) + * Separate the details links of commit-statuses in headers (#18661) (#18730) + * Update object repo with the migrated repository (#18684) (#18726) + * Fix bug for version update hint (#18701) (#18705) + * Fix issue with docker-rootless shimming script (#18690) (#18699) + * Let `MinUnitAccessMode` return correct perm (#18675) (#18689) + * Prevent security failure due to bad APP_ID (#18678) (#18682) + * Restart zero worker if there is still work to do (#18658) (#18672) + * If rendering has failed due to a net.OpError stop rendering (#18642) (#18645) +* TESTING + * Ensure git tag tests and others create test repos in tmpdir (#18447) (#18767) +* BUILD + * Reduce CI go module downloads, add make targets (#18708, #18475, #18443) (#18741) +* MISC + * Put buttons back in org dashboard (#18817) (#18825) + * Various Mermaid improvements (#18776) (#18780) + * C preprocessor colors improvement (#18671) (#18696) + * Fix the missing i18n key for update checker (#18646) (#18665) + +## [1.16.1](https://github.com/go-gitea/gitea/releases/tag/v1.16.1) - 2022-02-06 + +* SECURITY + * Update JS dependencies, fix lint (#18389) (#18540) +* ENHANCEMENTS + * Add dropdown icon to label set template dropdown (#18564) (#18571) +* BUGFIXES + * Comments on migrated issues/prs must link to the comment ID (#18630) (#18637) + * Stop logging an error when notes are not found (#18626) (#18635) + * Ensure that blob-excerpt links work for wiki (#18587) (#18624) + * Only attempt to flush queue if the underlying worker pool is not finished (#18593) (#18620) + * Ensure commit-statuses box is sized correctly in headers (#18538) (#18606) + * Prevent merge messages from being sorted to the top of email chains (#18566) (#18588) + * Prevent panic on prohibited user login with oauth2 (#18562) (#18563) + * Collaborator trust model should trust collaborators (#18539) (#18557) + * Detect conflicts with 3way merge (#18536) (#18537) + * In docker rootless use $GITEA_APP_INI if provided (#18524) (#18535) + * Add `GetUserTeams` (#18499) (#18531) + * Fix review excerpt (#18502) (#18530) + * Fix for AvatarURL database type (#18487) (#18529) + * Use `ImagedProvider` for gplus oauth2 provider (#18504) (#18505) + * Fix OAuth Source Edit Page (#18495) (#18503) + * Use "read" value for General Access (#18496) (#18500) + * Prevent NPE on partial match of compare URL and allow short SHA1 compare URLs (#18472) (#18473) +* BUILD + * Make docker gitea/gitea:v1.16-dev etc refer to the latest build on that branch (#18551) (#18569) +* DOCS + * Update 1.16.0 changelog to set #17846 as breaking (#18533) (#18534) + +## [1.16.0](https://github.com/go-gitea/gitea/releases/tag/v1.16.0) - 2022-01-30 * BREAKING * Remove golang vendored directory (#18277) * Paginate releases page & set default page size to 10 (#16857) + * Use shadowing script for docker (#17846) * Only allow webhook to send requests to allowed hosts (#17482) * SECURITY + * Disable content sniffing on `PlainTextBytes` (#18359) (#18365) + * Only view milestones from current repo (#18414) (#18417) * Sanitize user-input on file name (#17666) * Use `hostmatcher` to replace `matchlist` to improve blocking of bad hosts in Webhooks (#17605) * FEATURES @@ -228,6 +490,16 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). * Add left padding for chunk header of split diff view (#13397) * Allow U2F 2FA without TOTP (#11573) * BUGFIXES + * GitLab reviews may not have the updated_at field set (#18450) (#18461) + * Fix detection of no commits when the default branch is not master (#18422) (#18423) + * Fix broken oauth2 authentication source edit page (#18412) (#18419) + * Place inline diff comment dialogs on split diff in 4th and 8th columns (#18403) (#18404) + * Fix restore without topic failure (#18387) (#18400) + * Fix commit's time (#18375) (#18392) + * Fix partial cloning a repo (#18373) (#18377) + * Stop trimming preceding and suffixing spaces from editor filenames (#18334) + * Prevent showing webauthn error for every time visiting `/user/settings/security` (#18386) + * Fix mime-type detection for HTTP server (#18370) (#18371) * Stop trimming preceding and suffixing spaces from editor filenames (#18334) * Restore propagation of ErrDependenciesLeft (#18325) * Fix PR comments UI (#18323) @@ -295,10 +567,22 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). * BUILD * Add lockfile-check (#18285) * Don't store assets modified time into generated files (#18193) - * Use shadowing script for docker (#17846) * MISC * Update JS dependencies (#17611) +## [1.15.11](https://github.com/go-gitea/gitea/releases/tag/v1.15.11) - 2022-01-29 + +* SECURITY + * Only view milestones from current repo (#18414) (#18418) +* BUGFIXES + * Fix broken when no commits and default branch is not master (#18422) (#18424) + * Fix commit's time (#18375) (#18409) + * Fix restore without topic failure (#18387) (#18401) + * Fix mermaid import in 1.15 (it uses ESModule now) (#18382) + * Update to go/text 0.3.7 (#18336) +* MISC + * Upgrade EasyMDE to 2.16.1 (#18278) (#18279) + ## [1.15.10](https://github.com/go-gitea/gitea/releases/tag/v1.15.10) - 2022-01-14 * BUGFIXES diff --git a/Dockerfile b/Dockerfile index e9767402c7..8a899b9a72 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,5 @@ - -################################### -#Build stage - temporarily using techknowlogick image until we upgrade to latest official alpine/go image -FROM techknowlogick/go:1.17-alpine3.13 AS build-env +#Build stage +FROM golang:1.18-alpine3.15 AS build-env ARG GOPROXY ENV GOPROXY ${GOPROXY:-direct} @@ -35,7 +33,6 @@ RUN apk --no-cache add \ ca-certificates \ curl \ gettext \ - git \ linux-pam \ openssh \ s6 \ @@ -43,6 +40,8 @@ RUN apk --no-cache add \ su-exec \ gnupg +RUN apk add git --repository=http://dl-cdn.alpinelinux.org/alpine/v3.16/main + RUN addgroup \ -S -g 1000 \ git && \ diff --git a/Dockerfile.rootless b/Dockerfile.rootless index 5b22b26bc2..5bcf51647c 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,7 +1,5 @@ - -################################### -#Build stage - temporarily using techknowlogick image until we upgrade to latest official alpine/go image -FROM techknowlogick/go:1.17-alpine3.13 AS build-env +#Build stage +FROM golang:1.18-alpine3.15 AS build-env ARG GOPROXY ENV GOPROXY ${GOPROXY:-direct} @@ -34,10 +32,11 @@ RUN apk --no-cache add \ bash \ ca-certificates \ gettext \ - git \ curl \ gnupg +RUN apk add git --repository=http://dl-cdn.alpinelinux.org/alpine/v3.16/main + RUN addgroup \ -S -g 1000 \ git && \ diff --git a/Makefile b/Makefile index 342366492c..a15caf7a8f 100644 --- a/Makefile +++ b/Makefile @@ -24,10 +24,17 @@ SHASUM ?= shasum -a 256 HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" ) COMMA := , -XGO_VERSION := go-1.17.x -MIN_GO_VERSION := 001016000 -MIN_NODE_VERSION := 012017000 -MIN_GOLANGCI_LINT_VERSION := 001043000 +XGO_VERSION := go-1.18.x + +AIR_PACKAGE ?= github.com/cosmtrek/air@v1.29.0 +EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.4.0 +ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.0 +GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.0 +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.2 +GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10 +MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4 +SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.29.0 +XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest DOCKER_IMAGE ?= gitea/gitea DOCKER_TAG ?= latest @@ -125,8 +132,6 @@ ifeq ($(filter $(TAGS_SPLIT),bindata),bindata) GO_SOURCES += $(BINDATA_DEST) endif -#To update swagger use: GO111MODULE=on go get -u github.com/go-swagger/go-swagger/cmd/swagger -SWAGGER := $(GO) run github.com/go-swagger/go-swagger/cmd/swagger SWAGGER_SPEC := templates/swagger/v1_json.tmpl SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|g SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|"basePath": "/api/v1"|g @@ -166,6 +171,9 @@ help: @echo " - watch-backend watch backend files and continuously rebuild" @echo " - clean delete backend and integration files" @echo " - clean-all delete backend, frontend and integration files" + @echo " - deps install dependencies" + @echo " - deps-frontend install frontend dependencies" + @echo " - deps-backend install backend dependencies" @echo " - lint lint everything" @echo " - lint-frontend lint frontend files" @echo " - lint-backend lint backend files" @@ -193,10 +201,15 @@ help: .PHONY: go-check go-check: - $(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');)) + $(eval MIN_GO_VERSION_STR := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2)) + $(eval MIN_GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' '))) + $(eval GO_VERSION_STR := $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+')) + $(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(GO_VERSION_STR)' | tr '.' ' '))) @if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \ - echo "Gitea requires Go 1.16 or greater to build. You can get it at https://golang.org/dl/"; \ + echo "Gitea requires Go $(MIN_GO_VERSION_STR) or greater to build, but $(GO_VERSION) was found. You can get an updated version at https://go.dev/dl/"; \ exit 1; \ + else \ + echo "WARNING: Please ensure Go $(GO_VERSION_STR) is still maintained to avoid possible security problems. You can check it at https://go.dev/dl/"; \ fi .PHONY: git-check @@ -208,11 +221,12 @@ git-check: .PHONY: node-check node-check: + $(eval MIN_NODE_VERSION_STR := $(shell grep -Eo '"node":.*[0-9.]+"' package.json | sed -n 's/.*[^0-9.]\([0-9.]*\)"/\1/p')) + $(eval MIN_NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_NODE_VERSION_STR)' | tr '.' ' '))) $(eval NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v | cut -c2- | tr '.' ' ');)) - $(eval MIN_NODE_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_NODE_VERSION) | grep -o ...))) $(eval NPM_MISSING := $(shell hash npm > /dev/null 2>&1 || echo 1)) @if [ "$(NODE_VERSION)" -lt "$(MIN_NODE_VERSION)" -o "$(NPM_MISSING)" = "1" ]; then \ - echo "Gitea requires Node.js $(MIN_NODE_VER_FMT) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \ + echo "Gitea requires Node.js $(MIN_NODE_VERSION_STR) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \ exit 1; \ fi @@ -231,8 +245,8 @@ clean: .PHONY: fmt fmt: - @echo "Running gitea-fmt(with gofmt)..." - @$(GO) run build/code-batch-process.go gitea-fmt -s -w '{file-list}' + @echo "Running gitea-fmt (with gofumpt)..." + @MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}' .PHONY: vet vet: @@ -251,7 +265,7 @@ endif .PHONY: generate-swagger generate-swagger: - $(SWAGGER) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)' + $(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)' $(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)' $(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)' @@ -267,21 +281,18 @@ swagger-check: generate-swagger .PHONY: swagger-validate swagger-validate: $(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)' - $(SWAGGER) validate './$(SWAGGER_SPEC)' + $(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)' $(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)' .PHONY: errcheck errcheck: - @hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) install github.com/kisielk/errcheck@8ddee489636a8311a376fc92e27a6a13c6658344; \ - fi @echo "Running errcheck..." - @errcheck $(GO_PACKAGES) + $(GO) run $(ERRCHECK_PACKAGE) $(GO_PACKAGES) .PHONY: fmt-check fmt-check: # get all go files and run gitea-fmt (with gofmt) on them - @diff=$$($(GO) run build/code-batch-process.go gitea-fmt -s -d '{file-list}'); \ + @diff=$$(MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -l '{file-list}'); \ if [ -n "$$diff" ]; then \ echo "Please run 'make fmt' and commit the result:"; \ echo "$${diff}"; \ @@ -320,10 +331,7 @@ watch-frontend: node-check node_modules .PHONY: watch-backend watch-backend: go-check - @hash air > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) install github.com/cosmtrek/air@bedc18201271882c2be66d216d0e1a275b526ec4; \ - fi - air -c .air.toml + $(GO) run $(AIR_PACKAGE) -c .air.toml .PHONY: test test: test-frontend test-backend @@ -396,6 +404,11 @@ test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./migrations.sqlite.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./migrations.individual.sqlite.test +.PHONY: test-sqlite-migration\#% +test-sqlite-migration\#%: migrations.sqlite.test migrations.individual.sqlite.test generate-ini-sqlite + GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./migrations.individual.sqlite.test -test.run $(subst .,/,$*) + + generate-ini-mysql: sed -e 's|{{TEST_MYSQL_HOST}}|${TEST_MYSQL_HOST}|g' \ -e 's|{{TEST_MYSQL_DBNAME}}|${TEST_MYSQL_DBNAME}|g' \ @@ -591,12 +604,9 @@ $(DIST_DIRS): .PHONY: release-windows release-windows: | $(DIST_DIRS) - @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) install src.techknowlogick.com/xgo@latest; \ - fi - CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . ifeq (,$(findstring gogit,$(TAGS))) - CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit . + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit . endif ifeq ($(CI),drone) cp /build/* $(DIST)/binaries @@ -604,20 +614,14 @@ endif .PHONY: release-linux release-linux: | $(DIST_DIRS) - @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) install src.techknowlogick.com/xgo@latest; \ - fi - CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) . ifeq ($(CI),drone) cp /build/* $(DIST)/binaries endif .PHONY: release-darwin release-darwin: | $(DIST_DIRS) - @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) install src.techknowlogick.com/xgo@latest; \ - fi - CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) . ifeq ($(CI),drone) cp /build/* $(DIST)/binaries endif @@ -632,10 +636,7 @@ release-check: | $(DIST_DIRS) .PHONY: release-compress release-compress: | $(DIST_DIRS) - @hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) install github.com/ulikunitz/xz/cmd/gxz@v0.5.10; \ - fi - cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done; + cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && $(GO) run $(GXZ_PAGAGE) -k -9 $${file}; done; .PHONY: release-sources release-sources: | $(DIST_DIRS) @@ -656,6 +657,25 @@ docs: fi cd docs; make trans-copy clean build-offline; +.PHONY: deps +deps: deps-frontend deps-backend + +.PHONY: deps-frontend +deps-frontend: node_modules + +.PHONY: deps-backend +deps-backend: + $(GO) mod download + $(GO) install $(AIR_PACKAGE) + $(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) + $(GO) install $(ERRCHECK_PACKAGE) + $(GO) install $(GOFUMPT_PACKAGE) + $(GO) install $(GOLANGCI_LINT_PACKAGE) + $(GO) install $(GXZ_PAGAGE) + $(GO) install $(MISSPELL_PACKAGE) + $(GO) install $(SWAGGER_PACKAGE) + $(GO) install $(XGO_PACKAGE) + node_modules: package-lock.json npm install --no-save @touch node_modules @@ -748,22 +768,19 @@ pr\#%: clean-all $(GO) run contrib/pr/checkout.go $* .PHONY: golangci-lint -golangci-lint: golangci-lint-check - golangci-lint run --timeout 10m +golangci-lint: + $(GO) run $(GOLANGCI_LINT_PACKAGE) run -.PHONY: golangci-lint-check -golangci-lint-check: - $(eval GOLANGCI_LINT_VERSION := $(shell printf "%03d%03d%03d" $(shell golangci-lint --version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');)) - $(eval MIN_GOLANGCI_LINT_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_GOLANGCI_LINT_VERSION) | grep -o ...))) - @hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - echo "Downloading golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \ - export BINARY="golangci-lint"; \ - curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \ - elif [ "$(GOLANGCI_LINT_VERSION)" -lt "$(MIN_GOLANGCI_LINT_VERSION)" ]; then \ - echo "Downloading newer version of golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \ - export BINARY="golangci-lint"; \ - curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \ - fi +# workaround step for the lint-backend-windows CI task because 'go run' can not +# have distinct GOOS/GOARCH for its build and run steps +.PHONY: golangci-lint-windows +golangci-lint-windows: + @GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE) + golangci-lint run + +.PHONY: editorconfig-checker +editorconfig-checker: + $(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .PHONY: docker docker: diff --git a/README.md b/README.md index bbe27fab4d..84c0524ed4 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ or if SQLite support is required: The `build` target is split into two sub-targets: -- `make backend` which requires [Go 1.16](https://golang.org/dl/) or greater. +- `make backend` which requires [Go 1.17](https://go.dev/dl/) or greater. - `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and Internet connectivity to download npm dependencies. When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js and Internet connectivity. diff --git a/build/code-batch-process.go b/build/code-batch-process.go index 1fd236abd5..54ff41c6d5 100644 --- a/build/code-batch-process.go +++ b/build/code-batch-process.go @@ -40,7 +40,7 @@ func passThroughCmd(cmd string, args []string) error { } c := exec.Cmd{ Path: foundCmd, - Args: args, + Args: append([]string{cmd}, args...), Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, @@ -270,9 +270,10 @@ func main() { if containsString(subArgs, "-w") { cmdErrors = append(cmdErrors, giteaFormatGoImports(files)) } - cmdErrors = append(cmdErrors, passThroughCmd("gofmt", substArgs)) + cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-l"), containsString(subArgs, "-w"))) + cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", "1.17"}, substArgs...))) case "misspell": - cmdErrors = append(cmdErrors, passThroughCmd("misspell", substArgs)) + cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("MISSPELL_PACKAGE")}, substArgs...))) default: log.Fatalf("unknown cmd: %s %v", subCmd, subArgs) } diff --git a/cmd/admin.go b/cmd/admin.go index 3c7f7c8a7c..1e524fe095 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -25,6 +25,7 @@ import ( repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/util" auth_service "code.gitea.io/gitea/services/auth" "code.gitea.io/gitea/services/auth/source/oauth2" "code.gitea.io/gitea/services/auth/source/smtp" @@ -113,6 +114,10 @@ var ( Name: "access-token", Usage: "Generate access token for the user", }, + cli.BoolFlag{ + Name: "restricted", + Usage: "Make a restricted user account", + }, }, } @@ -537,17 +542,26 @@ func runCreateUser(c *cli.Context) error { changePassword = c.Bool("must-change-password") } + restricted := util.OptionalBoolNone + + if c.IsSet("restricted") { + restricted = util.OptionalBoolOf(c.Bool("restricted")) + } + u := &user_model.User{ Name: username, Email: c.String("email"), Passwd: password, - IsActive: true, IsAdmin: c.Bool("admin"), MustChangePassword: changePassword, - Theme: setting.UI.DefaultTheme, } - if err := user_model.CreateUser(u); err != nil { + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsActive: util.OptionalBoolTrue, + IsRestricted: restricted, + } + + if err := user_model.CreateUser(u, overwriteDefault); err != nil { return fmt.Errorf("CreateUser: %v", err) } diff --git a/cmd/cmd.go b/cmd/cmd.go index fd713b9aff..3846a86900 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -31,7 +31,7 @@ func argsSet(c *cli.Context, args ...string) error { return errors.New(a + " is not set") } - if util.IsEmptyString(a) { + if util.IsEmptyString(c.String(a)) { return errors.New(a + " is required") } } diff --git a/cmd/dump.go b/cmd/dump.go index d6a5230060..604cbb6866 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -86,7 +86,7 @@ func (o outputType) String() string { } var outputTypeEnum = &outputType{ - Enum: []string{"zip", "rar", "tar", "sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"}, + Enum: []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"}, Default: "zip", } @@ -160,7 +160,12 @@ func runDump(ctx *cli.Context) error { fatal("Deleting default logger failed. Can not write to stdout: %v", err) } } else { - fileName = strings.TrimSuffix(fileName, path.Ext(fileName)) + for _, suffix := range outputTypeEnum.Enum { + if strings.HasSuffix(fileName, "."+suffix) { + fileName = strings.TrimSuffix(fileName, "."+suffix) + break + } + } fileName += "." + outType } setting.LoadFromExisting() diff --git a/cmd/hook.go b/cmd/hook.go index 9bbe4f33ab..c12fa7e360 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -185,7 +185,7 @@ Gitea or set your environment appropriately.`, "") reponame := os.Getenv(models.EnvRepoName) userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64) prID, _ := strconv.ParseInt(os.Getenv(models.EnvPRID), 10, 64) - isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey)) + deployKeyID, _ := strconv.ParseInt(os.Getenv(models.EnvDeployKeyID), 10, 64) hookOptions := private.HookOptions{ UserID: userID, @@ -194,7 +194,7 @@ Gitea or set your environment appropriately.`, "") GitQuarantinePath: os.Getenv(private.GitQuarantinePath), GitPushOptions: pushOptions(), PullRequestID: prID, - IsDeployKey: isDeployKey, + DeployKeyID: deployKeyID, } scanner := bufio.NewScanner(os.Stdin) diff --git a/cmd/serv.go b/cmd/serv.go index ab60358b53..63befa88b4 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/pprof" "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/lfs" @@ -243,11 +244,11 @@ func runServ(c *cli.Context) error { os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10)) os.Setenv(models.EnvRepoID, strconv.FormatInt(results.RepoID, 10)) os.Setenv(models.EnvPRID, fmt.Sprintf("%d", 0)) - os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey)) + os.Setenv(models.EnvDeployKeyID, fmt.Sprintf("%d", results.DeployKeyID)) os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID)) os.Setenv(models.EnvAppURL, setting.AppURL) - //LFS token authentication + // LFS token authentication if verb == lfsAuthenticateVerb { url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName)) @@ -297,6 +298,16 @@ func runServ(c *cli.Context) error { gitcmd = exec.CommandContext(ctx, verb, repoPath) } + // Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when + // `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection. + if _, err := os.Stat(setting.RepoRootPath); err != nil { + if os.IsNotExist(err) { + return fail("Incorrect configuration.", + "Directory `[repository]` `ROOT` was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.") + } + } + + process.SetSysProcAttribute(gitcmd) gitcmd.Dir = setting.RepoRootPath gitcmd.Stdout = os.Stdout gitcmd.Stdin = os.Stdin diff --git a/contrib/fhs-compliant-script/gitea b/contrib/fhs-compliant-script/gitea index ae1ae3cf14..ea033b0f2d 100755 --- a/contrib/fhs-compliant-script/gitea +++ b/contrib/fhs-compliant-script/gitea @@ -33,10 +33,8 @@ for i in "$@"; do done if [ -z "$APP_INI_SET" ]; then - CONF_ARG="-c \"$APP_INI\"" + CONF_ARG=("-c" "${GITEA_APP_INI:-$APP_INI}") fi # Provide FHS compliant defaults -GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" exec -a "$0" "$GITEA" $CONF_ARG "$@" - - +GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" exec -a "$0" "$GITEA" "${CONF_ARG[@]}" "$@" diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 586c924c4a..b33e156646 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -880,7 +880,7 @@ PATH = ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; List of prefixes used in Pull Request title to mark them as Work In Progress +;; List of prefixes used in Pull Request title to mark them as Work In Progress (matched in a case-insensitive manner) ;WORK_IN_PROGRESS_PREFIXES = WIP:,[WIP] ;; ;; List of keywords used in Pull Request comments to automatically close a related issue @@ -1075,7 +1075,7 @@ PATH = ;SEARCH_REPO_DESCRIPTION = true ;; ;; Whether to enable a Service Worker to cache frontend assets -;USE_SERVICE_WORKER = true +;USE_SERVICE_WORKER = false ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docker/manifest.rootless.tmpl b/docker/manifest.rootless.tmpl index 1d14041ff2..2c6623b2d7 100644 --- a/docker/manifest.rootless.tmpl +++ b/docker/manifest.rootless.tmpl @@ -1,19 +1,18 @@ -image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}dev{{/if}}-rootless +image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-rootless {{#if build.tags}} tags: {{#each build.tags}} - {{this}}-rootless {{/each}} - - "latest-rootless" {{/if}} manifests: - - image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}dev{{/if}}-linux-amd64-rootless + image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-amd64-rootless platform: architecture: amd64 os: linux - - image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}dev{{/if}}-linux-arm64-rootless + image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-arm64-rootless platform: architecture: arm64 os: linux diff --git a/docker/manifest.tmpl b/docker/manifest.tmpl index 43a57f7f27..8ca3d5be1d 100644 --- a/docker/manifest.tmpl +++ b/docker/manifest.tmpl @@ -1,20 +1,19 @@ -image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}dev{{/if}} +image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}} {{#if build.tags}} tags: {{#each build.tags}} - {{this}} {{/each}} - - "latest" {{/if}} manifests: - - image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{else}}dev-{{/if}}linux-amd64 + image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-amd64 platform: architecture: amd64 os: linux - - image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{else}}dev-{{/if}}linux-arm64 + image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-arm64 platform: architecture: arm64 os: linux - variant: v8 \ No newline at end of file + variant: v8 diff --git a/docker/rootless/usr/local/bin/gitea b/docker/rootless/usr/local/bin/gitea index 5fdadfb3fe..9a9a569b12 100644 --- a/docker/rootless/usr/local/bin/gitea +++ b/docker/rootless/usr/local/bin/gitea @@ -32,11 +32,9 @@ for i in "$@"; do done if [ -z "$APP_INI_SET" ]; then - CONF_ARG="-c \"$APP_INI\"" + CONF_ARG=("-c" "${GITEA_APP_INI:-$APP_INI}") fi # Provide docker defaults -GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" exec -a "$0" "$GITEA" $CONF_ARG "$@" - - +GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" exec -a "$0" "$GITEA" "${CONF_ARG[@]}" "$@" diff --git a/docs/config.yaml b/docs/config.yaml index 6f3bacc643..e77f98bd21 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -18,9 +18,9 @@ params: description: Git with a cup of tea author: The Gitea Authors website: https://docs.gitea.io - version: 1.15.10 + version: 1.16.4 minGoVersion: 1.16 - goVersion: 1.17 + goVersion: 1.18 minNodeVersion: 12.17 outputs: diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 6cbc9b91f9..94dd432304 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -87,7 +87,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. ### Repository - Pull Request (`repository.pull-request`) - `WORK_IN_PROGRESS_PREFIXES`: **WIP:,\[WIP\]**: List of prefixes used in Pull Request - title to mark them as Work In Progress + title to mark them as Work In Progress. These are matched in a case-insensitive manner. - `CLOSE_KEYWORDS`: **close**, **closes**, **closed**, **fix**, **fixes**, **fixed**, **resolve**, **resolves**, **resolved**: List of keywords used in Pull Request comments to automatically close a related issue - `REOPEN_KEYWORDS`: **reopen**, **reopens**, **reopened**: List of keywords used in Pull Request comments to automatically reopen @@ -189,7 +189,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a add it to this config. - `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used. - `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page. -- `USE_SERVICE_WORKER`: **true**: Whether to enable a Service Worker to cache frontend assets. +- `USE_SERVICE_WORKER`: **false**: Whether to enable a Service Worker to cache frontend assets. ### UI - Admin (`ui.admin`) diff --git a/docs/content/doc/developers/guidelines-backend.md b/docs/content/doc/developers/guidelines-backend.md index d249465453..1248d41432 100644 --- a/docs/content/doc/developers/guidelines-backend.md +++ b/docs/content/doc/developers/guidelines-backend.md @@ -42,7 +42,7 @@ To maintain understandable code and avoid circular dependencies it is important - `modules/setting`: Store all system configurations read from ini files and has been referenced by everywhere. But they should be used as function parameters when possible. - `modules/git`: Package to interactive with `Git` command line or Gogit package. - `public`: Compiled frontend files (javascript, images, css, etc.) -- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers. +- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) must not depend on routers. - `routers/api` Contains routers for `/api/v1` aims to handle RESTful API requests. - `routers/install` Could only respond when system is in INSTALL mode (INSTALL_LOCK=false). - `routers/private` will only be invoked by internal sub commands, especially `serv` and `hooks`. @@ -106,10 +106,20 @@ i.e. `servcies/user`, `models/repository`. Since there are some packages which use the same package name, it is possible that you find packages like `modules/user`, `models/user`, and `services/user`. When these packages are imported in one Go file, it's difficult to know which package we are using and if it's a variable name or an import name. So, we always recommend to use import aliases. To differ from package variables which are commonly in camelCase, just use **snake_case** for import aliases. i.e. `import user_service "code.gitea.io/gitea/services/user"` +### Important Gotchas + +- Never write `x.Update(exemplar)` without an explicit `WHERE` clause: + - This will cause all rows in the table to be updated with the non-zero values of the exemplar - including IDs. + - You should usually write `x.ID(id).Update(exemplar)`. +- If during a migration you are inserting into a table using `x.Insert(exemplar)` where the ID is preset: + - You will need to ``SET IDENTITY_INSERT `table` ON`` for the MSSQL variant (the migration will fail otherwise) + - However, you will also need to update the id sequence for postgres - the migration will silently pass here but later insertions will fail: + ``SELECT setval('table_name_id_seq', COALESCE((SELECT MAX(id)+1 FROM `table_name`), 1), false)`` + ### Future Tasks Currently, we are creating some refactors to do the following things: - Correct that codes which doesn't follow the rules. - There are too many files in `models`, so we are moving some of them into a sub package `models/xxx`. -- Some `modules` sub packages should be moved to `services` because they depends on `models`. \ No newline at end of file +- Some `modules` sub packages should be moved to `services` because they depend on `models`. diff --git a/docs/content/doc/developers/hacking-on-gitea.en-us.md b/docs/content/doc/developers/hacking-on-gitea.en-us.md index 5481a2f1fe..be04e6efc4 100644 --- a/docs/content/doc/developers/hacking-on-gitea.en-us.md +++ b/docs/content/doc/developers/hacking-on-gitea.en-us.md @@ -185,8 +185,6 @@ Before committing, make sure the linters pass: make lint-frontend ``` -Note: When working on frontend code, set `USE_SERVICE_WORKER` to `false` in `app.ini` to prevent undesirable caching of frontend assets. - ### Building and adding SVGs SVG icons are built using the `make svg` target which compiles the icon sources defined in `build/generate-svg.js` into the output directory `public/img/svg`. Custom icons can be added in the `web_src/svg` directory. diff --git a/docs/content/doc/installation/with-docker-rootless.en-us.md b/docs/content/doc/installation/with-docker-rootless.en-us.md index f28d506231..a49d3bb15b 100644 --- a/docs/content/doc/installation/with-docker-rootless.en-us.md +++ b/docs/content/doc/installation/with-docker-rootless.en-us.md @@ -32,7 +32,7 @@ image as a service. Since there is no database available, one can be initialized Create a directory for `data` and `config` then paste the following content into a file named `docker-compose.yml`. Note that the volume should be owned by the user/group with the UID/GID specified in the config file. By default Gitea in docker will use uid:1000 gid:1000. If needed you can set ownership on those folders with the command: `sudo chown 1000:1000 config/ data/` If you don't give the volume correct permissions, the container may not start. -For a stable release you could use `:latest-rootless`, `:1-rootless` or specify a certain release like `:{{< version >}}-rootless`, but if you'd like to use the latest development version then `:dev-rootless` would be an appropriate tag. +For a stable release you could use `:latest-rootless`, `:1-rootless` or specify a certain release like `:{{< version >}}-rootless`, but if you'd like to use the latest development version then `:dev-rootless` would be an appropriate tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-dev-rootless` tag, where x is the minor version of Gitea. (e.g. `:1.16-dev-rootless`) ```yaml version: "2" diff --git a/docs/content/doc/installation/with-docker.en-us.md b/docs/content/doc/installation/with-docker.en-us.md index 43a262c593..de738cc0f8 100644 --- a/docs/content/doc/installation/with-docker.en-us.md +++ b/docs/content/doc/installation/with-docker.en-us.md @@ -34,7 +34,7 @@ image as a service. Since there is no database available, one can be initialized Create a directory like `gitea` and paste the following content into a file named `docker-compose.yml`. Note that the volume should be owned by the user/group with the UID/GID specified in the config file. If you don't give the volume correct permissions, the container may not start. -For a stable release you can use `:latest`, `:1` or specify a certain release like `:{{< version >}}`, but if you'd like to use the latest development version of Gitea then you could use the `:dev` tag. +For a stable release you can use `:latest`, `:1` or specify a certain release like `:{{< version >}}`, but if you'd like to use the latest development version of Gitea then you could use the `:dev` tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-dev` tag, where x is the minor version of Gitea. (e.g. `:1.16-dev`) ```yaml version: "3" diff --git a/docs/content/doc/installation/with-docker.fr-fr.md b/docs/content/doc/installation/with-docker.fr-fr.md index 0011ba2ff4..176abf7a12 100644 --- a/docs/content/doc/installation/with-docker.fr-fr.md +++ b/docs/content/doc/installation/with-docker.fr-fr.md @@ -43,7 +43,7 @@ Vous devriez avoir une instance fonctionnelle de Gitea. Pour accĆØder Ć  l'inter ## Named Volumes -Ce guide aboutira Ć  une installation avec les donnĆ©es Gita et PostgreSQL stockĆ©es dans des volumes nommĆ©s. Cela permet une sauvegarde, une restauration et des mises Ć  niveau en toute simplicitĆ©. +Ce guide aboutira Ć  une installation avec les donnĆ©es Gitea et PostgreSQL stockĆ©es dans des volumes nommĆ©s. Cela permet une sauvegarde, une restauration et des mises Ć  niveau en toute simplicitĆ©. ### The Database diff --git a/go.mod b/go.mod index ce3be970bd..ad6770c62b 100644 --- a/go.mod +++ b/go.mod @@ -3,41 +3,30 @@ module code.gitea.io/gitea go 1.16 require ( - cloud.google.com/go v0.78.0 // indirect code.gitea.io/gitea-vet v0.2.1 code.gitea.io/sdk/gitea v0.15.1 - gitea.com/go-chi/binding v0.0.0-20211013065440-d16dc407c2be + gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb gitea.com/go-chi/cache v0.0.0-20211013020926-78790b11abf1 gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5 gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8 gitea.com/lunny/levelqueue v0.4.1 github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 - github.com/Microsoft/go-winio v0.5.0 // indirect github.com/NYTimes/gziphandler v1.1.1 - github.com/ProtonMail/go-crypto v0.0.0-20210705153151-cc34b1f6908b // indirect - github.com/PuerkitoBio/goquery v1.7.0 - github.com/alecthomas/chroma v0.9.4 - github.com/andybalholm/brotli v1.0.3 // indirect - github.com/andybalholm/cascadia v1.2.0 // indirect - github.com/blevesearch/bleve/v2 v2.3.0 - github.com/boombuler/barcode v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect - github.com/caddyserver/certmagic v0.15.2 + github.com/PuerkitoBio/goquery v1.8.0 + github.com/alecthomas/chroma v0.10.0 + github.com/blevesearch/bleve/v2 v2.3.1 + github.com/caddyserver/certmagic v0.15.4 github.com/chi-middleware/proxy v1.1.1 - github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect - github.com/couchbase/gomemcached v0.1.2 // indirect - github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect - github.com/denisenkom/go-mssqldb v0.10.0 + github.com/denisenkom/go-mssqldb v0.12.0 github.com/djherbis/buffer v1.2.0 github.com/djherbis/nio/v3 v3.0.1 - github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b + github.com/duo-labs/webauthn v0.0.0-20220122034320-81aea484c951 github.com/dustin/go-humanize v1.0.0 github.com/editorconfig/editorconfig-core-go/v2 v2.4.2 github.com/emirpasic/gods v1.12.0 github.com/ethantkoenig/rupture v1.0.0 github.com/gliderlabs/ssh v0.3.3 - github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect - github.com/go-chi/chi/v5 v5.0.4 + github.com/go-chi/chi/v5 v5.0.7 github.com/go-chi/cors v1.2.0 github.com/go-enry/go-enry/v2 v2.7.1 github.com/go-git/go-billy/v5 v5.3.1 @@ -48,105 +37,130 @@ require ( github.com/go-swagger/go-swagger v0.27.0 github.com/go-testfixtures/testfixtures/v3 v3.6.1 github.com/gobwas/glob v0.2.3 - github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 + github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 - github.com/golang-jwt/jwt/v4 v4.2.0 - github.com/golang/snappy v0.0.4 // indirect + github.com/golang-jwt/jwt/v4 v4.3.0 github.com/google/go-github/v39 v39.2.0 - github.com/google/uuid v1.2.0 + github.com/google/uuid v1.3.0 github.com/gorilla/feeds v1.1.1 - github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/sessions v1.2.1 - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.0 // indirect - github.com/hashicorp/go-version v1.3.1 + github.com/hashicorp/go-version v1.4.0 github.com/hashicorp/golang-lru v0.5.4 github.com/huandu/xstrings v1.3.2 github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 - github.com/json-iterator/go v1.1.11 + github.com/json-iterator/go v1.1.12 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 - github.com/kevinburke/ssh_config v1.1.0 // indirect github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 - github.com/klauspost/compress v1.13.1 + github.com/klauspost/compress v1.13.6 github.com/klauspost/cpuid/v2 v2.0.9 - github.com/klauspost/pgzip v1.2.5 // indirect github.com/lib/pq v1.10.2 github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 - github.com/markbates/goth v1.68.0 - github.com/mattn/go-isatty v0.0.13 - github.com/mattn/go-runewidth v0.0.13 // indirect - github.com/mattn/go-sqlite3 v1.14.8 - github.com/mholt/archiver/v3 v3.5.0 - github.com/microcosm-cc/bluemonday v1.0.16 - github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/minio-go/v7 v7.0.12 - github.com/minio/sha256-simd v1.0.0 // indirect - github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect - github.com/msteinert/pam v0.0.0-20201130170657-e61372126161 + github.com/markbates/goth v1.69.0 + github.com/mattn/go-isatty v0.0.14 + github.com/mattn/go-sqlite3 v1.14.12 + github.com/mholt/archiver/v3 v3.5.1 + github.com/microcosm-cc/bluemonday v1.0.18 + github.com/minio/minio-go/v7 v7.0.23 + github.com/msteinert/pam v1.0.0 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 - github.com/niklasfasching/go-org v1.5.0 - github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/niklasfasching/go-org v1.6.2 github.com/oliamb/cutter v0.2.2 - github.com/olivere/elastic/v7 v7.0.25 - github.com/pelletier/go-toml v1.9.0 // indirect - github.com/pierrec/lz4/v4 v4.1.8 // indirect + github.com/olivere/elastic/v7 v7.0.31 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.3.0 - github.com/prometheus/client_golang v1.11.0 - github.com/quasoft/websspi v1.0.0 - github.com/rs/xid v1.3.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/prometheus/client_golang v1.12.1 + github.com/quasoft/websspi v1.1.2 github.com/sergi/go-diff v1.2.0 - github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 - github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.0 github.com/tstranex/u2f v1.0.0 - github.com/ulikunitz/xz v0.5.10 // indirect github.com/unknwon/com v1.0.1 github.com/unknwon/i18n v0.0.0-20210321134014-0ebbf2df1c44 github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae github.com/unrolled/render v1.4.0 github.com/urfave/cli v1.22.5 - github.com/xanzy/go-gitlab v0.50.1 + github.com/xanzy/go-gitlab v0.58.0 github.com/yohcop/openid-go v1.0.0 - github.com/yuin/goldmark v1.4.0 - github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01 - github.com/yuin/goldmark-meta v1.0.0 - go.etcd.io/bbolt v1.3.6 // indirect + github.com/yuin/goldmark v1.4.11 + github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 + github.com/yuin/goldmark-meta v1.1.0 go.jolheiser.com/hcaptcha v0.0.4 go.jolheiser.com/pwn v0.0.3 go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.7.0 // indirect - go.uber.org/zap v1.19.0 // indirect - golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 - golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 - golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 - golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 + golang.org/x/net v0.0.0-20220225172249-27dd8689420f + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b + golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 golang.org/x/text v0.3.7 - golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect - golang.org/x/tools v0.1.0 - google.golang.org/protobuf v1.27.1 // indirect - gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + golang.org/x/tools v0.1.9 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df - gopkg.in/ini.v1 v1.62.0 + gopkg.in/ini.v1 v1.66.2 gopkg.in/yaml.v2 v2.4.0 mvdan.cc/xurls/v2 v2.2.0 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 - xorm.io/builder v0.3.9 + xorm.io/builder v0.3.10 xorm.io/xorm v1.2.5 ) +require ( + github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect + github.com/Microsoft/go-winio v0.5.2 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f // indirect + github.com/andybalholm/brotli v1.0.4 // indirect + github.com/bits-and-blooms/bitset v1.2.1 // indirect + github.com/boombuler/barcode v1.0.1 // indirect + github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect + github.com/cloudflare/cfssl v1.6.1 // indirect + github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect + github.com/couchbase/gomemcached v0.1.2 // indirect + github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect + github.com/felixge/httpsnoop v1.0.2 // indirect + github.com/fxamacker/cbor/v2 v2.4.0 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect + github.com/go-openapi/analysis v0.21.2 // indirect + github.com/go-openapi/errors v0.20.2 // indirect + github.com/go-openapi/runtime v0.21.1 // indirect + github.com/go-openapi/strfmt v0.21.1 // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.0 // indirect + github.com/kevinburke/ssh_config v1.1.0 // indirect + github.com/kr/pretty v0.3.0 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mholt/acmez v1.0.2 // indirect + github.com/miekg/dns v1.1.46 // indirect + github.com/minio/md5-simd v1.1.2 // indirect + github.com/minio/sha256-simd v1.0.0 // indirect + github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect + github.com/nwaples/rardecode v1.1.3 // indirect + github.com/pierrec/lz4/v4 v4.1.14 // indirect + github.com/rogpeppe/go-internal v1.8.1 // indirect + github.com/rs/xid v1.3.0 // indirect + github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect + github.com/spf13/afero v1.8.0 // indirect + github.com/spf13/cobra v1.3.0 // indirect + github.com/spf13/viper v1.10.1 // indirect + github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect + github.com/ulikunitz/xz v0.5.10 // indirect + github.com/xanzy/ssh-agent v0.3.1 // indirect + go.etcd.io/bbolt v1.3.6 // indirect + go.mongodb.org/mongo-driver v1.8.2 // indirect + golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect +) + replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 replace github.com/markbates/goth v1.68.0 => github.com/zeripath/goth v1.68.1-0.20220109111530-754359885dce replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 -replace github.com/duo-labs/webauthn => github.com/authelia/webauthn v0.0.0-20211225121951-80d1f2a572e4 - replace github.com/satori/go.uuid v1.2.0 => github.com/gofrs/uuid v4.2.0+incompatible exclude github.com/gofrs/uuid v3.2.0+incompatible diff --git a/go.sum b/go.sum index 22fdb0b7ac..aa4bafad25 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,13 @@ +bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= +bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= 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.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= 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.44.3/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= @@ -16,8 +21,20 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.67.0/go.mod h1:YNan/mUhNZFrYUor0vqrsQ0Ffl7Xtm/ACOy/vsTS858= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0 h1:oKpsiyKMfVpwR3zSAkQixGzlVE5ovitBuO0qSmCf0bI= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= +cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= 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/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -27,22 +44,32 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= 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/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/spanner v1.17.0/go.mod h1:+17t2ixFwRG4lWRwE+5kipDR9Ef07Jkmc8z0IbMDKUs= 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= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= code.gitea.io/gitea-vet v0.2.1 h1:b30by7+3SkmiftK0RjuXqFvZg2q4p68uoPGuxhzBN0s= code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= +code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= +contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= +contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= +contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= +contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= +contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= +contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gitea.com/go-chi/binding v0.0.0-20211013065440-d16dc407c2be h1:IzSwPVzd2hE6e67ujY8ReBCrQ5IFNd0uiBmC7Ux5IaY= -gitea.com/go-chi/binding v0.0.0-20211013065440-d16dc407c2be/go.mod h1:/vR0YjlusOYvosKYW7QKcSnrY0nPLe4RQ/DGi3+i/Do= +gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb h1:Yy0Bxzc8R2wxiwXoG/rECGplJUSpXqCsog9PuJFgiHs= +gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc= gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0= gitea.com/go-chi/cache v0.0.0-20211013020926-78790b11abf1 h1:Z7DcvTkxt8ovcENgPsQ7xzrGNSQmmIjGS9fJEb1l8jk= gitea.com/go-chi/cache v0.0.0-20211013020926-78790b11abf1/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0= @@ -58,24 +85,47 @@ github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 h1:r3qt8PCHnfjOv9PN3H github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121/go.mod h1:Ock8XgA7pvULhIaHGAk/cDnRfNrF9Jey81nPcc403iU= github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U= github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo= -github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= +github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= +github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= +github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= +github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e h1:ZU22z/2YRFLyf/P4ZwUYSdNCWsMEI0VeyrFoI2rAhJQ= +github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e/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/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.2/go.mod h1:af5vUNlDNkCjOZeSGFgIJxDje9qdjsO6hshx0gTmZt4= +github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= -github.com/ProtonMail/go-crypto v0.0.0-20210705153151-cc34b1f6908b h1:BF5p87XWvmgdrTPPzcRMwC0TMQbviwQ+uBKfNfWJy50= -github.com/ProtonMail/go-crypto v0.0.0-20210705153151-cc34b1f6908b/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= -github.com/PuerkitoBio/goquery v1.7.0 h1:O5SP3b9JWqMSVMG69zMfj577zwkSNpxrFf7ybS74eiw= -github.com/PuerkitoBio/goquery v1.7.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= +github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f h1:J2FzIrXN82q5uyUraeJpLIm7U6PffRwje2ORho5yIik= +github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= +github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -91,36 +141,40 @@ github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= -github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= -github.com/alecthomas/chroma v0.7.2-0.20200305040604-4f3623dce67a/go.mod h1:fv5SzZPFJbwp2NXJWpFIX7DZS4HgV1K4ew4Pc2OZD9s= -github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= -github.com/alecthomas/chroma v0.9.4 h1:YL7sOAE3p8HS96T9km7RgvmsZIctqbK1qJ0b7hzed44= -github.com/alecthomas/chroma v0.9.4/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= -github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= -github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= -github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= -github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= +github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM= -github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE= -github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY= +github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= +github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= +github.com/apache/beam v2.28.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= +github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= +github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= +github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= @@ -131,13 +185,18 @@ github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:o github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/authelia/webauthn v0.0.0-20211225121951-80d1f2a572e4 h1:u3eFvgr4A8IjlAokbFt6XY6VdurX7DEYnQMQ4K2yobc= -github.com/authelia/webauthn v0.0.0-20211225121951-80d1f2a572e4/go.mod h1:EYSpSkwoEcryMmQGfhol2IiB3IMN9IIIaNd/wcAQMGQ= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= -github.com/aws/aws-sdk-go v1.38.17/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.42.23/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= @@ -148,12 +207,14 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY= +github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blevesearch/bleve/v2 v2.0.1/go.mod h1:OBP2Pktqik8vEiUlGhuWjYx7KiO4zD542+DHqICwM5w= -github.com/blevesearch/bleve/v2 v2.3.0 h1:5XKlSdpcjeJdE7n0FUEDeJRJwLuhPxq+k5n7h5UaJkg= -github.com/blevesearch/bleve/v2 v2.3.0/go.mod h1:egW/6gZEhM3oBvRjuHXGvGb92cKZ9867OqPZAmCG8MQ= +github.com/blevesearch/bleve/v2 v2.3.1 h1:rbMTDM17tvZ7wTrTp4lJINYRnz57N5oMSw8cYuJ4l0k= +github.com/blevesearch/bleve/v2 v2.3.1/go.mod h1:kAJuWn2L1TNSUyxtPJD4AGma2/PgMSm7GBlx61F9OBs= github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= github.com/blevesearch/bleve_index_api v1.0.1 h1:nx9++0hnyiGOHJwQQYfsUGzpRdEVE5LsylmmngQvaFk= github.com/blevesearch/bleve_index_api v1.0.1/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= @@ -175,49 +236,80 @@ github.com/blevesearch/upsidedown_store_api v1.0.1/go.mod h1:MQDVGpHZrpe3Uy26zJB github.com/blevesearch/vellum v1.0.7 h1:+vn8rfyCRHxKVRgDLeR0FAXej2+6mEb5Q15aQE/XESQ= github.com/blevesearch/vellum v1.0.7/go.mod h1:doBZpmRhwTsASB4QdUZANlJvqVAUdUyX0ZK7QJCTeBE= github.com/blevesearch/zapx/v11 v11.1.10/go.mod h1:DTjbcBqrr/Uo82UBilDC8lEew42gN/OcIyiTNFtSijc= -github.com/blevesearch/zapx/v11 v11.3.2 h1:TDdcbaA0Yz3Y5zpTrpvyW1AeicqWTJL3g8D5g48RiHM= -github.com/blevesearch/zapx/v11 v11.3.2/go.mod h1:YzTfUm4kS3e8OmTXDHVV8OzC5MWPO/VPJZQgPNVb4Lc= +github.com/blevesearch/zapx/v11 v11.3.3 h1:8vQMO5hdA2qPCmicIMuKS+qcvUAEh6Vcb0uve4Nh8e4= +github.com/blevesearch/zapx/v11 v11.3.3/go.mod h1:YzTfUm4kS3e8OmTXDHVV8OzC5MWPO/VPJZQgPNVb4Lc= github.com/blevesearch/zapx/v12 v12.1.10/go.mod h1:14NmKnPrnKAIyiEJM566k/Jk+FQpuiflT5d3uaaK3MI= -github.com/blevesearch/zapx/v12 v12.3.2 h1:XB09XMg/3ibeIJRCm2zjkaVwrtAuk6c55YRSmVlwUDk= -github.com/blevesearch/zapx/v12 v12.3.2/go.mod h1:RMl6lOZqF+sTxKvhQDJ5yK2LT3Mu7E2p/jGdjAaiRxs= +github.com/blevesearch/zapx/v12 v12.3.3 h1:MQO5YNI8MqdPz12ALCoXiJw5cl9QQamYZSp285Z/+Mo= +github.com/blevesearch/zapx/v12 v12.3.3/go.mod h1:RMl6lOZqF+sTxKvhQDJ5yK2LT3Mu7E2p/jGdjAaiRxs= github.com/blevesearch/zapx/v13 v13.1.10/go.mod h1:YsVY6YGpTEAlJOMjdL7EsdBLvjWd8kPa2gwJDNpqLJo= -github.com/blevesearch/zapx/v13 v13.3.2 h1:mTvALh6oayreac07VRAv94FLvTHeSBM9sZ1gmVt0N2k= -github.com/blevesearch/zapx/v13 v13.3.2/go.mod h1:eppobNM35U4C22yDvTuxV9xPqo10pwfP/jugL4INWG4= +github.com/blevesearch/zapx/v13 v13.3.3 h1:TS4xpMK1ARPYHq+1WwuEOKMOiwvKpTK3RuWOkKlI7BE= +github.com/blevesearch/zapx/v13 v13.3.3/go.mod h1:eppobNM35U4C22yDvTuxV9xPqo10pwfP/jugL4INWG4= github.com/blevesearch/zapx/v14 v14.1.10/go.mod h1:hsULl5eJSxs5NEfBsmeT9qrqdCP+/ecpVZKt60M4V64= -github.com/blevesearch/zapx/v14 v14.3.2 h1:oW36JVaZDzrzmBa1X5jdTIYzdhkOQnr/ie13Cb2X7MQ= -github.com/blevesearch/zapx/v14 v14.3.2/go.mod h1:zXNcVzukh0AvG57oUtT1T0ndi09H0kELNaNmekEy0jw= +github.com/blevesearch/zapx/v14 v14.3.3 h1:dqqAzGphKl0yehHKKntDHKlEMhi9B/tJrD4OsWpY7YE= +github.com/blevesearch/zapx/v14 v14.3.3/go.mod h1:zXNcVzukh0AvG57oUtT1T0ndi09H0kELNaNmekEy0jw= github.com/blevesearch/zapx/v15 v15.1.10/go.mod h1:4ypq25bwtSQKzwEF1UERyIhmGTbMT3brY/n4NC5gRnM= -github.com/blevesearch/zapx/v15 v15.3.2 h1:OZNE4CQ9hQhnB21ySC7x2/9Q35U3WtRXLAh5L2gdCXc= -github.com/blevesearch/zapx/v15 v15.3.2/go.mod h1:C+f/97ZzTzK6vt/7sVlZdzZxKu+5+j4SrGCvr9dJzaY= +github.com/blevesearch/zapx/v15 v15.3.3 h1:60oE+qsJkveLenJmbc0eaH59GWYCbJJsPDV6Z5hEoYY= +github.com/blevesearch/zapx/v15 v15.3.3/go.mod h1:C+f/97ZzTzK6vt/7sVlZdzZxKu+5+j4SrGCvr9dJzaY= 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= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= -github.com/caddyserver/certmagic v0.15.2 h1:OMTakTsLM1ZfzMDjwvYprfUgFzpVPh3u87oxMPwmeBc= -github.com/caddyserver/certmagic v0.15.2/go.mod h1:qhkAOthf72ufAcp3Y5jF2RaGE96oip3UbEQRIzwe3/8= +github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= +github.com/caddyserver/certmagic v0.15.4 h1:kz//9+Z/xw197jtIBxxUDub8pQi9gcYvhXk5Ouw2EkM= +github.com/caddyserver/certmagic v0.15.4/go.mod h1:qhkAOthf72ufAcp3Y5jF2RaGE96oip3UbEQRIzwe3/8= +github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= +github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chi-middleware/proxy v1.1.1 h1:4HaXUp8o2+bhHr1OhVy+VjN0+L7/07JDcn6v7YrTjrQ= github.com/chi-middleware/proxy v1.1.1/go.mod h1:jQwMEJct2tz9VmtCELxvnXoMfa+SOdikvbVJVHv/M+0= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 h1:Puu1hUwfps3+1CUzYdAZXijuvLuRMirgiXdf3zsM2Ig= +github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= +github.com/cloudflare/cfssl v1.6.1 h1:aIOUjpeuDJOpWjVJFP2ByplF53OgqG8I1S40Ggdlk3g= +github.com/cloudflare/cfssl v1.6.1/go.mod h1:ENhCj4Z17+bY2XikpxVmTHDg/C2IsG2Q0ZBeXpAqhCk= +github.com/cloudflare/redoctober v0.0.0-20201013214028-99c99a8e7544/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210322005330-6414d713912e/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 h1:hzAQntlaYRkVSFEfj9OTWlVV1H155FMD8BTKktLv0QI= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 h1:KwaoQzs/WeUxxJqiJsZ4euOly1Az/IgZXXSxlD/UBNk= +github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4 h1:Lap807SXTH5tri2TivECb/4abUkMZC9zRoLarvcKDqs= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -225,10 +317,15 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k= @@ -247,35 +344,43 @@ github.com/couchbase/vellum v1.0.2/go.mod h1:FcwrEivFpNi24R3jLOs3n+fs5RnuQnQqCLB github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= -github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/daaku/go.zipexe v1.0.1/go.mod h1:5xWogtqlYnfBXkSB1o9xysukNP9GTvaNkqzUZbt3Bw8= +github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8= github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA= +github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= +github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/djherbis/buffer v1.1.0/go.mod h1:VwN8VdFkMY0DCALdY8o00d3IZ6Amz/UNVMWcSaJT44o= github.com/djherbis/buffer v1.2.0 h1:PH5Dd2ss0C7CRRhQCZ2u7MssF+No9ide8Ye71nPHcrQ= github.com/djherbis/buffer v1.2.0/go.mod h1:fjnebbZjCUpPinBRD+TDwXSOeNQ7fPQWLfGQqiAiUyE= github.com/djherbis/nio/v3 v3.0.1 h1:6wxhnuppteMa6RHA4L81Dq7ThkZH8SwnDzXDYy95vB4= github.com/djherbis/nio/v3 v3.0.1/go.mod h1:Ng4h80pbZFMla1yKzm61cF0tqqilXZYrogmWgZxOcmg= -github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= -github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/duo-labs/webauthn v0.0.0-20220122034320-81aea484c951 h1:17esZ09oW+29rklBtCVphIguql2u3NxYH2OasFPPZoo= +github.com/duo-labs/webauthn v0.0.0-20220122034320-81aea484c951/go.mod h1:nHy3JdztZWcsjenDeBuE8gn171OAwg12LBN027UP5AE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -293,22 +398,47 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.1 h1:cgDRLG7bs59Zd+apAWuzLQL95obVYAymNJek76W3mgw= +github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+nkAAmXrb2j3iq4FLwdrCbXQ= +github.com/envoyproxy/protoc-gen-validate v0.6.2 h1:JiO+kJTpmYGjEodY7O1Zk8oZcNz1+f30UtwtXoFUPzE= +github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= +github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE= github.com/ethantkoenig/rupture v1.0.0 h1:gPInt1N30UErGNzd8t5js5Qbnpjcd1l6yU2MCrJxIe8= github.com/ethantkoenig/rupture v1.0.0/go.mod h1:GyE9QabHfxA6ch0NZgwsHopRbOLcYjUr9g4FTJmq0WM= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= +github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fullstorydev/grpcurl v1.8.0/go.mod h1:Mn2jWbdMrQGJQ8UD62uNyMumT2acsZUCkZIqFxsQf1o= +github.com/fullstorydev/grpcurl v1.8.1 h1:Pp648wlTTg3OKySeqxM5pzh8XF6vLqrm8wRq66+5Xo0= +github.com/fullstorydev/grpcurl v1.8.1/go.mod h1:3BWhvHZwNO7iLXaQlojdg5NA6SxUDePli4ecpK1N7gw= github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= +github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.3.3 h1:mBQ8NiOgDkINJrZtoizkC3nDNYgSaWtxyem6S2XHBtA= @@ -321,8 +451,9 @@ github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro github.com/go-asn1-ber/asn1-ber v1.5.3 h1:u7utq56RUFiynqUzgVMFDymapcOtQ/MZkh3H4QYkxag= github.com/go-asn1-ber/asn1-ber v1.5.3/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.0.4 h1:5e494iHzsYBiyXQAHHuI4tyJS9M3V84OuX3ufIIGHFo= github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= +github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE= github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-enry/go-enry/v2 v2.7.1 h1:WCqtfyteIz61GYk9lRVy8HblvIv4cP9GIiwm/6txCbU= @@ -341,6 +472,7 @@ github.com/go-git/go-git/v5 v5.4.3-0.20210630082519-b4368b2a2ca4/go.mod h1:gQ1kA github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -358,8 +490,10 @@ github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9sn github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ= github.com/go-openapi/analysis v0.19.16/go.mod h1:GLInF007N83Ad3m8a/CbQ5TPzdnGT7workfHwuVjNVk= -github.com/go-openapi/analysis v0.20.0 h1:UN09o0kNhleunxW7LR+KnltD0YrJ8FF03pSqvAN3Vro= github.com/go-openapi/analysis v0.20.0/go.mod h1:BMchjvaHDykmRMsK40iPtvyOfFdMMxlOmQr9FBZk+Og= +github.com/go-openapi/analysis v0.20.1/go.mod h1:BMchjvaHDykmRMsK40iPtvyOfFdMMxlOmQr9FBZk+Og= +github.com/go-openapi/analysis v0.21.2 h1:hXFrOYFHUAMQdu6zwAiKKJHJQ8kqZs1ux/ru1P1wLJU= +github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= @@ -368,8 +502,10 @@ github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpX github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.0 h1:Sxpo9PjEHDzhs3FbnGNonvDgWcMW2U7wGTcDDSFSceM= github.com/go-openapi/errors v0.20.0/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.1/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8= +github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= @@ -382,8 +518,9 @@ github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3Hfo github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -393,16 +530,18 @@ github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2e github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= github.com/go-openapi/loads v0.20.0/go.mod h1:2LhKquiE513rN5xC6Aan6lYOSddlL8Mp20AW9kpviM4= -github.com/go-openapi/loads v0.20.2 h1:z5p5Xf5wujMxS1y8aP+vxwW5qYT2zdJBbXKmQUG3lcc= github.com/go-openapi/loads v0.20.2/go.mod h1:hTVUotJ+UonAMMZsvakEgmWKgtulweO9vYP2bQYKA/o= +github.com/go-openapi/loads v0.21.0 h1:jYtUO4wwP7psAweisP/MDoOpdzsYEESdoPcsWjHDR68= +github.com/go-openapi/loads v0.21.0/go.mod h1:rHYve9nZrQ4CJhyeIIFJINGCg1tQpx2yJrrNo8sf1ws= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98= github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= -github.com/go-openapi/runtime v0.19.27 h1:4zrQCJoP7rqNCUaApDv1MdPkaa5TuPfO05Lq5WLhX9I= github.com/go-openapi/runtime v0.19.27/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M= +github.com/go-openapi/runtime v0.21.1 h1:/KIG00BzA2x2HRStX2tnhbqbQdPcFlkgsYCiNY20FZs= +github.com/go-openapi/runtime v0.21.1/go.mod h1:aQg+kaIQEn+A2CRSY1TxbM8+sT9g2V3aLc1FbIAnbbs= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= @@ -412,8 +551,9 @@ github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHK github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= github.com/go-openapi/spec v0.20.1/go.mod h1:93x7oh+d+FQsmsieroS4cmR3u0p/ywH649a3qwC9OsQ= -github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ= github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= @@ -423,8 +563,11 @@ github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/strfmt v0.19.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= github.com/go-openapi/strfmt v0.20.0/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= -github.com/go-openapi/strfmt v0.20.1 h1:1VgxvehFne1mbChGeCmZ5pc0LxUf6yaACVSIYAR91Xc= github.com/go-openapi/strfmt v0.20.1/go.mod h1:43urheQI9dNtE5lTZQfuFJvjYJKPrxicATpEfZwHUNk= +github.com/go-openapi/strfmt v0.20.2/go.mod h1:43urheQI9dNtE5lTZQfuFJvjYJKPrxicATpEfZwHUNk= +github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= +github.com/go-openapi/strfmt v0.21.1 h1:G6s2t5V5kGCHLVbSdZ/6lI8Wm4OzoPFkc3/cjAsKQrM= +github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= @@ -443,10 +586,12 @@ github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbN github.com/go-openapi/validate v0.19.12/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4= github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI= github.com/go-openapi/validate v0.20.1/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE9E4k54HpKcJ0= -github.com/go-openapi/validate v0.20.2 h1:AhqDegYV3J3iQkMPJSXkvzymHKMTw0BST3RK3hTT4ts= github.com/go-openapi/validate v0.20.2/go.mod h1:e7OJoKNgd0twXZwIn0A43tHbvIcr/rZIVCbJBpTUoY0= -github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= +github.com/go-openapi/validate v0.20.3 h1:GZPPhhKSZrE8HjB4eEkoYAZmoWA4+tCemSgINH1/vKw= +github.com/go-openapi/validate v0.20.3/go.mod h1:goDdqVGiigM3jChcrYJxD2joalke3ZXeftD16byIjA4= github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= github.com/go-redis/redis/v8 v8.11.0 h1:O1Td0mQ8UFChQ3N9zFQqo6kTU2cJ+/it88gDB+zg0wo= github.com/go-redis/redis/v8 v8.11.0/go.mod h1:DLomh7y2e3ggQXQLd1YgmvIfecPJoFl7WU5SOQ/r06M= @@ -455,8 +600,9 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-swagger/go-swagger v0.27.0 h1:K7+nkBuf4oS1jTBrdvWqYFpqD69V5CN8HamZzCDDhAI= github.com/go-swagger/go-swagger v0.27.0/go.mod h1:WodZVysInJilkW7e6IRw+dZGp5yW6rlMFZ4cb+THl9A= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= @@ -489,31 +635,44 @@ github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/V github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= 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/goccy/go-json v0.7.4 h1:B44qRUFwz/vxPKPISQ1KhvzRi9kZ28RAf6YtjriBZ5k= github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= +github.com/goccy/go-json v0.9.5 h1:ooSMW526ZjK+EaL5elrSyN2EzIfi/3V0m4+HJEDYLik= +github.com/goccy/go-json v0.9.5/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 h1:gBeyun7mySAKWg7Fb0GOcv0upX9bdaZScs8QcRo8mEY= -github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs= +github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQdcMdzjbqqXMEnHfq0Or6p8= github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk= 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.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= +github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 h1:+eHOFJl1BaXrQxKX+T06f78590z4qA2ZzBTqahsKSE4= +github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 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-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 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= @@ -521,6 +680,9 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 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= @@ -536,6 +698,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -546,8 +709,12 @@ 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/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/certificate-transparency-go v1.1.2-0.20210422104406-9f33727a7a18/go.mod h1:6CKh9dscIRoqc2kC6YUFICHZMT9NrClyPrRVFrdw1QQ= +github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92 h1:806qveZBQtRNHroYHyg6yrsjqBJh9kIB4nfmB8uJnak= +github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92/go.mod h1:kXWPsHVPSKVuxPPG69BRtumCbAW537FydV/GH89oBhM= 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= @@ -561,15 +728,22 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ= github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= +github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= +github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/licenseclassifier v0.0.0-20210325184830-bb04aff29e72/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 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-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -580,19 +754,38 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= +github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/trillian v1.3.14-0.20210409160123-c5ea3abd4a41/go.mod h1:1dPv0CUjNQVFEDuAUFhZql16pw/VlPgaX8qj+g5pVzQ= +github.com/google/trillian v1.3.14-0.20210428093031-b4ddea2e86b1/go.mod h1:FdIJX+NoDk/dIN2ZxTyz5nAJWgf+NSSSriPAMThChTY= +github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= +github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= 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/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= +github.com/goreleaser/goreleaser v0.134.0/go.mod h1:ZT6Y2rSYa6NxQzIsdfWWNWAlYGXGbreo66NmE+3X3WQ= +github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w= 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.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= @@ -614,29 +807,51 @@ github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 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 v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.0.0 h1:bkKf0BeBXcSYa7f5Fyi9gMuQ8gNsxeiNpZjR6VxNZeo= +github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -650,16 +865,30 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= +github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= @@ -724,38 +953,53 @@ github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= +github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 h1:g0fAGBisHaEQ0TRq1iBvemFRf+8AEWEmBESSiWB3Vsc= github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/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/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= +github.com/jhump/protoreflect v1.8.2 h1:k2xE7wcUomeqwY0LDCYA16y4WWfyTcMx5mKhk0d4ua0= +github.com/jhump/protoreflect v1.8.2/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= +github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= 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/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +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/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= 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 v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o= github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= @@ -763,12 +1007,16 @@ github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+ github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= +github.com/kisom/goutils v1.4.3/go.mod h1:Lp5qrquG7yhYnWzZCI/68Pa/GpFynw//od6EkGnWpac= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ= -github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= @@ -777,7 +1025,6 @@ github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw= @@ -787,19 +1034,26 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/go-gypsy v1.0.0/go.mod h1:chkXM0zjdpXOiqkCW1XcCHDfjfk14PH2KKkQWxfJUcU= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lestrrat-go/jwx v0.9.0/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk= +github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= @@ -812,6 +1066,8 @@ github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbat github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 h1:F/3FfGmKdiKFa8kL3YrpZ7pe9H4l4AzA1pbaOUnRvPI= github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0/go.mod h1:JEfTc3+2DF9Z4PXhLLvXL42zexJyh8rIq3OzUj/0rAk= +github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU= +github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -827,6 +1083,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/going v1.0.0 h1:DQw0ZP7NbNlFGcKbcE/IVSOAFzScxRtLpd0rLMzLhq0= github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA= +github.com/markbates/goth v1.69.0 h1:HoXdRES8Hfx4H4ICM27Im+IuVubflaAX7mXCmYHiWIw= +github.com/markbates/goth v1.69.0/go.mod h1:uk3KIdtCKdmyNABgOSmHFNHN0AcKqkLs8j5Ak3Ioe1Q= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= @@ -834,45 +1092,66 @@ github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlW github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= -github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU= github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= +github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mholt/acmez v1.0.1 h1:J7uquHOKEmo71UDnVApy1sSLA0oF/r+NtVrNzMKKA9I= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mholt/acmez v1.0.1/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= -github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxwWE= -github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc= -github.com/microcosm-cc/bluemonday v1.0.16 h1:kHmAq2t7WPWLjiGvzKa5o3HzSfahUKiOq7fAPUiMNIc= -github.com/microcosm-cc/bluemonday v1.0.16/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= +github.com/mholt/acmez v1.0.2 h1:C8wsEBIUVi6e0DYoxqCcFuXtwc4AWXL/jgcDjF7mjVo= +github.com/mholt/acmez v1.0.2/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= +github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= +github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= +github.com/microcosm-cc/bluemonday v1.0.18 h1:6HcxvXDAi3ARt3slx6nTesbvorIc3QeTzBNRvWktHBo= +github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.46 h1:uzwpxRtSVxtcIZmz/4Uz6/Rn7G11DvsaslXoy5LxQio= +github.com/miekg/dns v1.1.46/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= 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.12 h1:/4pxUdwn9w0QEryNkrrWaodIESPRX+NxpO0Q6hVdaAA= -github.com/minio/minio-go/v7 v7.0.12/go.mod h1:S23iSP5/gbMwtxeY5FM71R+TkAYyzEdoNEDDwpt8yWs= +github.com/minio/minio-go/v7 v7.0.23 h1:NleyGQvAn9VQMU+YHVrgV4CX+EPtxPt/78lHOOTncy4= +github.com/minio/minio-go/v7 v7.0.23/go.mod h1:ei5JjmxwHaMrgsMrn4U/+Nmg+d8MKS1U2DAn1ou4+Do= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -884,25 +1163,34 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 h1:j2kD3MT1z4PXCiUllUJF9mWUESr9TWKS7iEKsQ/IipM= github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= -github.com/msteinert/pam v0.0.0-20201130170657-e61372126161 h1:XQ1+fYPzaWZCVdu1xzjL917Xy9Yb7imLEU0wHelafKA= -github.com/msteinert/pam v0.0.0-20201130170657-e61372126161/go.mod h1:np1wUFZ6tyoke22qDJZY40URn9Ae51gX7ljIWXN5TJs= +github.com/msteinert/pam v1.0.0 h1:4XoXKtMCH3+e6GIkW41uxm6B37eYqci/DH3gzSq7ocg= +github.com/msteinert/pam v1.0.0/go.mod h1:M4FPeAW8g2ITO68W8gACDz13NDJyOQM9IQsQhrR6TOI= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= +github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= @@ -913,10 +1201,13 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/niklasfasching/go-org v1.5.0 h1:V8IwoSPm/d61bceyWFxxnQLtlvNT+CjiYIhtZLdnMF0= -github.com/niklasfasching/go-org v1.5.0/go.mod h1:sSb8ylwnAG+h8MGFDB3R1D5bxf8wA08REfhjShg3kjA= -github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= +github.com/niklasfasching/go-org v1.6.2 h1:kQBIZlfL4oRNApJCrBgaeNBfzxWzP6XlC7/b744Polk= +github.com/niklasfasching/go-org v1.6.2/go.mod h1:wn76Xgu4/KRe43WZhsgZjxYMaloSrl3BSweGV74SwHs= +github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= +github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc= 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 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= @@ -924,15 +1215,17 @@ github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQ github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= 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/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k= github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU= -github.com/olivere/elastic/v7 v7.0.25 h1:q3ef8PqC4PyT3b8BAcjDVo48KNzr0HVKosMqMsF+oME= -github.com/olivere/elastic/v7 v7.0.25/go.mod h1:ySKeM+7yrE9HmsUi6+vSp0anvWiDOuPa9kpuknxjKbU= +github.com/olivere/elastic/v7 v7.0.31 h1:VJu9/zIsbeiulwlRCfGQf6Tzsr++uo+FeUgj5oj+xKk= +github.com/olivere/elastic/v7 v7.0.31/go.mod h1:idEQxe7Es+Wr4XAuNnJdKeMZufkA9vQprOIFck061vg= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= @@ -954,32 +1247,44 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7Q0= -github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pierrec/lz4/v4 v4.1.8 h1:ieHkV+i2BRzngO4Wd/3HGowuZStgq6QkPsD1eolNAO4= -github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= +github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac/go.mod h1:hoLfEwdY11HjRfKFH6KqnPsfxlo3BP6bJehpDv8t6sQ= github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs= github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= @@ -988,9 +1293,13 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1003,31 +1312,46 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.24.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/quasoft/websspi v1.0.0 h1:5nDgdM5xSur9s+B5w2xQ5kxf5nUGqgFgU4W0aDLZ8Mw= -github.com/quasoft/websspi v1.0.0/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk= +github.com/pseudomuto/protoc-gen-doc v1.4.1/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= +github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= +github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw= +github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 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/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -1039,7 +1363,10 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= +github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= @@ -1056,6 +1383,7 @@ github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0 github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -1065,6 +1393,7 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/assertions v1.1.1 h1:T/YLemO5Yp7KPzS+lVtu+WsHn8yoSwTfItdAd1r3cck= github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= @@ -1072,19 +1401,31 @@ github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:X github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/smartystreets/gunit v1.4.2/go.mod h1:ZjM1ozSIMJlAz/ay4SG8PeKF00ckUp+zMHZXV9/bvak= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.8.0 h1:5MmtuhAgYeU6qpa7w7bP0dv6MBYuup0vekhSpSkoq60= +github.com/spf13/afero v1.8.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= +github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -1093,9 +1434,13 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= +github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= +github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= 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/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM= @@ -1106,6 +1451,7 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1120,15 +1466,27 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= +github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ= github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= @@ -1142,16 +1500,24 @@ github.com/unrolled/render v1.4.0 h1:p73obhpsXuE3paXOtcuXTBKgBJpLCfmABnsUiO35x+Q github.com/unrolled/render v1.4.0/go.mod h1:cK4RSTTVdND5j9EYEc0LAMOvdG11JeiKjyjfyZRvV2w= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/weppos/publicsuffix-go v0.13.1-0.20210123135404-5fd73613514e/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= +github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= 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/go-gitlab v0.50.1 h1:eH1G0/ZV1j81rhGrtbcePjbM5Ern7mPA4Xjt+yE+2PQ= -github.com/xanzy/go-gitlab v0.50.1/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE= -github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= +github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= +github.com/xanzy/go-gitlab v0.58.0 h1:Entnl8GrVDlc1jd1BlOWhNR0QVQgiO3WDom5DJbT+1s= +github.com/xanzy/go-gitlab v0.58.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo= +github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= @@ -1159,6 +1525,7 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhe github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= 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/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yohcop/openid-go v1.0.0 h1:EciJ7ZLETHR3wOtxBvKXx9RV6eyHZpCaSZ1inbBaUXE= @@ -1168,23 +1535,52 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.6/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0 h1:OtISOGfH6sOWa1/qXqqAiOIAO6Z5J3AEAE18WAq6BiQ= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01 h1:0SJnXjE4jDClMW6grE0xpNhwpqbPwkBTn8zpVw5C0SI= -github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01/go.mod h1:TwKQPa5XkCCRC2GRZ5wtfNUTQ2+9/i19mGRijFeJ4BE= -github.com/yuin/goldmark-meta v1.0.0 h1:ScsatUIT2gFS6azqzLGUjgOnELsBOxMXerM3ogdJhAM= -github.com/yuin/goldmark-meta v1.0.0/go.mod h1:zsNNOrZ4nLuyHAJeLQEZcQat8dm70SmB2kHbls092Gc= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= +github.com/yuin/goldmark v1.4.6/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= +github.com/yuin/goldmark v1.4.11 h1:i45YIzqLnUc2tGaTlJCyUxSG8TvgyGqhqOZOUKIjJ6w= +github.com/yuin/goldmark v1.4.11/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= +github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg= +github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod h1:U9ihbh+1ZN7fR5Se3daSPoz1CGF9IYtSvWwVQtnzGHU= +github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= +github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -github.com/zeripath/goth v1.68.1-0.20220109111530-754359885dce h1:ul/k+Fu3/2h+hxIaEMrn6m96X1Wf+TQk9G7zyuvy1Ws= -github.com/zeripath/goth v1.68.1-0.20220109111530-754359885dce/go.mod h1:uk3KIdtCKdmyNABgOSmHFNHN0AcKqkLs8j5Ak3Ioe1Q= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= +github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= +github.com/zmap/zcrypto v0.0.0-20210123152837-9cf5beac6d91/go.mod h1:R/deQh6+tSWlgI9tb4jNmXxn8nSCabl5ZQsBX9//I/E= +github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc/go.mod h1:FM4U1E3NzlNMRnSUTU3P1UdukWhYGifqEsjk9fn7BCk= +github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw= +go.etcd.io/etcd/api/v3 v3.5.1 h1:v28cktvBq+7vGyJXF8G+rWJmj+1XUmMtqcLnH8hDocM= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.1 h1:XIQcHCFSG53bJETYeRJtIxdLv2EWRGxcfzR8lSnTH4E= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0-alpha.0/go.mod h1:kdV+xzCJ3luEBSIeQyB/OEKkWKd8Zkux4sbDeANrosU= +go.etcd.io/etcd/client/v2 v2.305.1 h1:vtxYCKWA9x31w0WJj7DdqsHFNjhkigdAnziDtkZb/l4= +go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.etcd.io/etcd/client/v3 v3.5.0-alpha.0 h1:dr1EOILak2pu4Nf5XbRIOCNIBjcz6UmkQd7hHRXwxaM= +go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8= +go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0 h1:odMFuQQCg0UmPd7Cyw6TViRYv9ybGuXuki4CusDSzqA= +go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0/go.mod h1:YPwSaBciV5G6Gpt435AasAG3ROetZsKNUzibRa/++oo= +go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0 h1:3yLUEC0nFCxw/RArImOyRUI4OAFbg4PFpBbAhSNzKNY= +go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0/go.mod h1:tV31atvwzcybuqejDoY3oaNRTtlD2l/Ot78Pc9w7DMY= +go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0 h1:DvYJotxV9q1Lkn7pknzAbFO/CLtCVidCr2K9qRLJ8pA= +go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0/go.mod h1:FAwse6Zlm5v4tEWZaTjmNhe17Int4Oxbu7+2r0DiD3w= +go.etcd.io/etcd/server/v3 v3.5.0-alpha.0 h1:fYv7CmmdyuIu27UmKQjS9K/1GtcCa+XnPKqiKBbQkrk= +go.etcd.io/etcd/server/v3 v3.5.0-alpha.0/go.mod h1:tsKetYpt980ZTpzl/gb+UOJj9RkIyCb1u4wjzMg90BQ= +go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0 h1:UcRoCA1FgXoc4CEM8J31fqEvI69uFIObY5ZDEFH7Znc= +go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0/go.mod h1:HnrHxjyCuZ8YDt8PYVyQQ5d1ZQfzJVEtQWllr5Vp/30= +go.etcd.io/etcd/v3 v3.5.0-alpha.0 h1:ZuqKJkD2HrzFUj8IB+GLkTMKZ3+7mWx172vx6F1TukM= +go.etcd.io/etcd/v3 v3.5.0-alpha.0/go.mod h1:JZ79d3LV6NUfPjUxXrpiFAYcjhT+06qqw+i28snx8To= go.jolheiser.com/hcaptcha v0.0.4 h1:RrDERcr/Tz/kWyJenjVtI+V09RtLinXxlAemiwN5F+I= go.jolheiser.com/hcaptcha v0.0.4/go.mod h1:aw32WQOxnQZ6E06C0LypCf+sxNxPACyOnq+ZGnrIYho= go.jolheiser.com/pwn v0.0.3 h1:MQowb3QvCL5r5NmHmCPxw93SdjfgJ0q6rAwYn4i1Hjg= @@ -1196,8 +1592,12 @@ go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= -go.mongodb.org/mongo-driver v1.5.1 h1:9nOVLGDfOaZ9R0tBumx/BcuqkbFpyTCU2r/Po7A2azI= go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= +go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.mongodb.org/mongo-driver v1.8.2 h1:8ssUXufb90ujcIvR6MyE1SchaNj0SFxsakiZgxIyrMk= +go.mongodb.org/mongo-driver v1.8.2/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -1208,6 +1608,7 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1215,22 +1616,26 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= -go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI= +golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1240,6 +1645,7 @@ golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1248,20 +1654,30 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 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= @@ -1272,6 +1688,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= 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/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1284,8 +1701,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl 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/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/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= @@ -1296,14 +1713,16 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1318,11 +1737,15 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/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-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1330,6 +1753,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -1350,15 +1774,30 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210331060903-cb1fcc7394e5/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/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-20190402181905-9f3314589c9a/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= @@ -1366,9 +1805,19 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= +golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 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= @@ -1390,10 +1839,10 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/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-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/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-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1406,6 +1855,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/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-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1413,10 +1863,14 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/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-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1425,13 +1879,14 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1443,6 +1898,7 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1451,21 +1907,48 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1480,8 +1963,10 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 h1:Vv0JUPWTyeqUq42B2WJ1FeIDjjvGKoA2Ss+Ts0lAVbs= -golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= +golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1496,6 +1981,7 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1506,16 +1992,19 @@ golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190617190820-da514acc4774/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-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/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-20191010075000-0337d82405ff/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-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/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-20191118222007-07fc4c7f2b98/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-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1534,23 +2023,37 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201014170642-d1624618ad65/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1560,9 +2063,12 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= 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.10.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= @@ -1579,22 +2085,42 @@ google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.45.0/go.mod h1:ISLIJCedJolbZvDfAk+Ctuq5hf+aJ33WgtUsfyFoLXA= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/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-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= 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= @@ -1611,8 +2137,10 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -1625,7 +2153,41 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210331142528-b7513248f0ba/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210413151531-c14fb6ef47c3/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210510173355-fb37daa5cd7a/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1645,9 +2207,23 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1658,6 +2234,7 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= @@ -1672,6 +2249,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= +gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= @@ -1682,10 +2261,14 @@ gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= @@ -1693,6 +2276,7 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1712,6 +2296,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.33.6 h1:r63dgSzVzRxUpAJFPQWHy1QeZeY1ydNENUDaBx1GqYc= @@ -1741,14 +2326,18 @@ modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A= mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8= +pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= 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= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= -xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc= xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= +xorm.io/builder v0.3.10 h1:Rvkncad3Lo9YIVqCbgIf6QnpR/HcW3IEr0AANNpuyMQ= +xorm.io/builder v0.3.10/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= xorm.io/xorm v1.2.5 h1:tqN7OhN8P9xi52qBb76I8m5maAJMz/SSbgK2RGPCPbo= xorm.io/xorm v1.2.5/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0= diff --git a/integrations/api_helper_for_declarative_test.go b/integrations/api_helper_for_declarative_test.go index 9c6adaf084..7f2cd787c3 100644 --- a/integrations/api_helper_for_declarative_test.go +++ b/integrations/api_helper_for_declarative_test.go @@ -8,6 +8,7 @@ import ( "context" "fmt" "net/http" + "net/http/httptest" "net/url" "os" "testing" @@ -262,23 +263,26 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64) return func(t *testing.T) { urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s", owner, repo, index, ctx.Token) - req := NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{ - MergeMessageField: "doAPIMergePullRequest Merge", - Do: string(repo_model.MergeStyleMerge), - }) - resp := ctx.Session.MakeRequest(t, req, NoExpectedStatus) + var req *http.Request + var resp *httptest.ResponseRecorder - if resp.Code == http.StatusMethodNotAllowed { - err := api.APIError{} - DecodeJSON(t, resp, &err) - assert.EqualValues(t, "Please try again later", err.Message) - queue.GetManager().FlushAll(context.Background(), 5*time.Second) + for i := 0; i < 6; i++ { req = NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{ MergeMessageField: "doAPIMergePullRequest Merge", Do: string(repo_model.MergeStyleMerge), }) + resp = ctx.Session.MakeRequest(t, req, NoExpectedStatus) + + if resp.Code != http.StatusMethodNotAllowed { + break + } + err := api.APIError{} + DecodeJSON(t, resp, &err) + assert.EqualValues(t, "Please try again later", err.Message) + queue.GetManager().FlushAll(context.Background(), 5*time.Second) + <-time.After(1 * time.Second) } expected := ctx.ExpectedCode diff --git a/integrations/api_private_serv_test.go b/integrations/api_private_serv_test.go index 68308bafc5..13274bcdcc 100644 --- a/integrations/api_private_serv_test.go +++ b/integrations/api_private_serv_test.go @@ -47,7 +47,7 @@ func TestAPIPrivateServ(t *testing.T) { results, err := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "") assert.NoError(t, err) assert.False(t, results.IsWiki) - assert.False(t, results.IsDeployKey) + assert.Zero(t, results.DeployKeyID) assert.Equal(t, int64(1), results.KeyID) assert.Equal(t, "user2@localhost", results.KeyName) assert.Equal(t, "user2", results.UserName) @@ -70,7 +70,7 @@ func TestAPIPrivateServ(t *testing.T) { results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "") assert.NoError(t, err) assert.False(t, results.IsWiki) - assert.False(t, results.IsDeployKey) + assert.Zero(t, results.DeployKeyID) assert.Equal(t, int64(1), results.KeyID) assert.Equal(t, "user2@localhost", results.KeyName) assert.Equal(t, "user2", results.UserName) @@ -92,7 +92,7 @@ func TestAPIPrivateServ(t *testing.T) { results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "") assert.NoError(t, err) assert.False(t, results.IsWiki) - assert.True(t, results.IsDeployKey) + assert.NotZero(t, results.DeployKeyID) assert.Equal(t, deployKey.KeyID, results.KeyID) assert.Equal(t, "test-deploy", results.KeyName) assert.Equal(t, "user15", results.UserName) @@ -129,7 +129,7 @@ func TestAPIPrivateServ(t *testing.T) { results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "") assert.NoError(t, err) assert.False(t, results.IsWiki) - assert.True(t, results.IsDeployKey) + assert.NotZero(t, results.DeployKeyID) assert.Equal(t, deployKey.KeyID, results.KeyID) assert.Equal(t, "test-deploy", results.KeyName) assert.Equal(t, "user15", results.UserName) @@ -142,7 +142,7 @@ func TestAPIPrivateServ(t *testing.T) { results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "") assert.NoError(t, err) assert.False(t, results.IsWiki) - assert.True(t, results.IsDeployKey) + assert.NotZero(t, results.DeployKeyID) assert.Equal(t, deployKey.KeyID, results.KeyID) assert.Equal(t, "test-deploy", results.KeyName) assert.Equal(t, "user15", results.UserName) diff --git a/integrations/api_repo_test.go b/integrations/api_repo_test.go index c909e96f06..1ec9dbad10 100644 --- a/integrations/api_repo_test.go +++ b/integrations/api_repo_test.go @@ -445,7 +445,6 @@ func TestAPIRepoTransfer(t *testing.T) { expectedStatus int }{ // Disclaimer for test story: "user1" is an admin, "user2" is normal user and part of in owner team of org "user3" - // Transfer to a user with teams in another org should fail {ctxUserID: 1, newOwner: "user3", teams: &[]int64{5}, expectedStatus: http.StatusForbidden}, // Transfer to a user with non-existent team IDs should fail diff --git a/integrations/api_user_email_test.go b/integrations/api_user_email_test.go index 9d2b7485d8..08d236df30 100644 --- a/integrations/api_user_email_test.go +++ b/integrations/api_user_email_test.go @@ -69,6 +69,12 @@ func TestAPIAddEmail(t *testing.T) { Primary: false, }, }, emails) + + opts = api.CreateEmailOption{ + Emails: []string{"notAEmail"}, + } + req = NewRequestWithJSON(t, "POST", "/api/v1/user/emails?token="+token, &opts) + session.MakeRequest(t, req, http.StatusUnprocessableEntity) } func TestAPIDeleteEmail(t *testing.T) { diff --git a/integrations/git_helper_for_declarative_test.go b/integrations/git_helper_for_declarative_test.go index 8105bcab8d..05a3e87775 100644 --- a/integrations/git_helper_for_declarative_test.go +++ b/integrations/git_helper_for_declarative_test.go @@ -123,6 +123,17 @@ func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) { } } +func doPartialGitClone(dstLocalPath string, u *url.URL) func(*testing.T) { + return func(t *testing.T) { + assert.NoError(t, git.CloneWithArgs(context.Background(), u.String(), dstLocalPath, allowLFSFilters(), git.CloneRepoOptions{ + Filter: "blob:none", + })) + exist, err := util.IsExist(filepath.Join(dstLocalPath, "README.md")) + assert.NoError(t, err) + assert.True(t, exist) + } +} + func doGitCloneFail(u *url.URL) func(*testing.T) { return func(t *testing.T) { tmpDir, err := os.MkdirTemp("", "doGitCloneFail") diff --git a/integrations/git_test.go b/integrations/git_test.go index 0d33c786aa..f8e3b8dd3f 100644 --- a/integrations/git_test.go +++ b/integrations/git_test.go @@ -69,6 +69,12 @@ func testGit(t *testing.T, u *url.URL) { t.Run("Clone", doGitClone(dstPath, u)) + dstPath2, err := os.MkdirTemp("", httpContext.Reponame) + assert.NoError(t, err) + defer util.RemoveAll(dstPath2) + + t.Run("Partial Clone", doPartialGitClone(dstPath2, u)) + little, big := standardCommitAndPushTest(t, dstPath) littleLFS, bigLFS := lfsCommitAndPushTest(t, dstPath) rawTest(t, &httpContext, little, big, littleLFS, bigLFS) diff --git a/integrations/integration_test.go b/integrations/integration_test.go index 527d4b951a..924a96ce1c 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -112,6 +112,13 @@ func TestMain(m *testing.M) { } } + os.Unsetenv("GIT_AUTHOR_NAME") + os.Unsetenv("GIT_AUTHOR_EMAIL") + os.Unsetenv("GIT_AUTHOR_DATE") + os.Unsetenv("GIT_COMMITTER_NAME") + os.Unsetenv("GIT_COMMITTER_EMAIL") + os.Unsetenv("GIT_COMMITTER_DATE") + err := unittest.InitFixtures( unittest.FixturesOptions{ Dir: filepath.Join(filepath.Dir(setting.AppPath), "models/fixtures/"), diff --git a/integrations/mssql.ini.tmpl b/integrations/mssql.ini.tmpl index b9ed26dccd..afb2b18900 100644 --- a/integrations/mssql.ini.tmpl +++ b/integrations/mssql.ini.tmpl @@ -83,7 +83,7 @@ PROVIDER_CONFIG = integrations/gitea-integration-mssql/data/sessions [log] MODE = test,file -ROOT_PATH = mssql-log +ROOT_PATH = {{REPO_TEST_DIR}}mssql-log ROUTER = , XORM = file ENABLE_SSH_LOG = true diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index 6de2374277..c1780110a3 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -101,7 +101,7 @@ PROVIDER_CONFIG = integrations/gitea-integration-mysql/data/sessions [log] MODE = test,file -ROOT_PATH = mysql-log +ROOT_PATH = {{REPO_TEST_DIR}}mysql-log ROUTER = , XORM = file ENABLE_SSH_LOG = true diff --git a/integrations/mysql8.ini.tmpl b/integrations/mysql8.ini.tmpl index 81a1d8836c..49a0b19a36 100644 --- a/integrations/mysql8.ini.tmpl +++ b/integrations/mysql8.ini.tmpl @@ -80,7 +80,7 @@ PROVIDER_CONFIG = integrations/gitea-integration-mysql8/data/sessions [log] MODE = test,file -ROOT_PATH = mysql8-log +ROOT_PATH = {{REPO_TEST_DIR}}mysql8-log ROUTER = , XORM = file ENABLE_SSH_LOG = true diff --git a/integrations/pgsql.ini.tmpl b/integrations/pgsql.ini.tmpl index db1914a1bb..37b2f3e573 100644 --- a/integrations/pgsql.ini.tmpl +++ b/integrations/pgsql.ini.tmpl @@ -84,7 +84,7 @@ PROVIDER_CONFIG = integrations/gitea-integration-pgsql/data/sessions [log] MODE = test,file -ROOT_PATH = pgsql-log +ROOT_PATH = {{REPO_TEST_DIR}}pgsql-log ROUTER = , XORM = file ENABLE_SSH_LOG = true diff --git a/integrations/pull_merge_test.go b/integrations/pull_merge_test.go index a0b87eeee8..7646d9f412 100644 --- a/integrations/pull_merge_test.go +++ b/integrations/pull_merge_test.go @@ -25,6 +25,8 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/services/pull" + repo_service "code.gitea.io/gitea/services/repository" + files_service "code.gitea.io/gitea/services/repository/files" "github.com/stretchr/testify/assert" "github.com/unknwon/i18n" @@ -65,7 +67,7 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str func TestPullMerge(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { - hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number + hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number assert.NoError(t, err) hookTasksLenBefore := len(hookTasks) @@ -87,7 +89,7 @@ func TestPullMerge(t *testing.T) { func TestPullRebase(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { - hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number + hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number assert.NoError(t, err) hookTasksLenBefore := len(hookTasks) @@ -109,7 +111,7 @@ func TestPullRebase(t *testing.T) { func TestPullRebaseMerge(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { - hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number + hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number assert.NoError(t, err) hookTasksLenBefore := len(hookTasks) @@ -131,7 +133,7 @@ func TestPullRebaseMerge(t *testing.T) { func TestPullSquash(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { - hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number + hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number assert.NoError(t, err) hookTasksLenBefore := len(hookTasks) @@ -335,3 +337,74 @@ func TestCantMergeUnrelated(t *testing.T) { gitRepo.Close() }) } + +func TestConflictChecking(t *testing.T) { + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + + // Create new clean repo to test conflict checking. + baseRepo, err := repo_service.CreateRepository(user, user, models.CreateRepoOptions{ + Name: "conflict-checking", + Description: "Tempo repo", + AutoInit: true, + Readme: "Default", + DefaultBranch: "main", + }) + assert.NoError(t, err) + assert.NotEmpty(t, baseRepo) + + // create a commit on new branch. + _, err = files_service.CreateOrUpdateRepoFile(baseRepo, user, &files_service.UpdateRepoFileOptions{ + TreePath: "important_file", + Message: "Add a important file", + Content: "Just a non-important file", + IsNewFile: true, + OldBranch: "main", + NewBranch: "important-secrets", + }) + assert.NoError(t, err) + + // create a commit on main branch. + _, err = files_service.CreateOrUpdateRepoFile(baseRepo, user, &files_service.UpdateRepoFileOptions{ + TreePath: "important_file", + Message: "Add a important file", + Content: "Not the same content :P", + IsNewFile: true, + OldBranch: "main", + NewBranch: "main", + }) + assert.NoError(t, err) + + // create Pull to merge the important-secrets branch into main branch. + pullIssue := &models.Issue{ + RepoID: baseRepo.ID, + Title: "PR with conflict!", + PosterID: user.ID, + Poster: user, + IsPull: true, + } + + pullRequest := &models.PullRequest{ + HeadRepoID: baseRepo.ID, + BaseRepoID: baseRepo.ID, + HeadBranch: "important-secrets", + BaseBranch: "main", + HeadRepo: baseRepo, + BaseRepo: baseRepo, + Type: models.PullRequestGitea, + } + err = pull.NewPullRequest(baseRepo, pullIssue, nil, nil, pullRequest, nil) + assert.NoError(t, err) + + issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{Title: "PR with conflict!"}).(*models.Issue) + conflictingPR, err := models.GetPullRequestByIssueID(issue.ID) + assert.NoError(t, err) + + // Ensure conflictedFiles is populated. + assert.Equal(t, 1, len(conflictingPR.ConflictedFiles)) + // Check if status is correct. + assert.Equal(t, models.PullRequestStatusConflict, conflictingPR.Status) + // Ensure that mergeable returns false + assert.False(t, conflictingPR.Mergeable()) + }) +} diff --git a/integrations/signin_test.go b/integrations/signin_test.go index 3ea8866150..a6e4b7d4d2 100644 --- a/integrations/signin_test.go +++ b/integrations/signin_test.go @@ -51,8 +51,6 @@ func TestSignin(t *testing.T) { {username: "wrongUsername", password: "password", message: i18n.Tr("en", "form.username_password_incorrect")}, {username: "user15", password: "wrongPassword", message: i18n.Tr("en", "form.username_password_incorrect")}, {username: "user1@example.com", password: "wrongPassword", message: i18n.Tr("en", "form.username_password_incorrect")}, - // test for duplicate email - {username: "user2@example.com", password: "password", message: i18n.Tr("en", "form.email_been_used")}, } for _, s := range samples { diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index 76d9420d81..f8d2b3bb42 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -79,7 +79,7 @@ PROVIDER_CONFIG = integrations/gitea-integration-sqlite/data/sessions [log] MODE = test,file -ROOT_PATH = sqlite-log +ROOT_PATH = {{REPO_TEST_DIR}}sqlite-log ROUTER = , XORM = file ENABLE_SSH_LOG = true diff --git a/models/action.go b/models/action.go index 26d05730c5..951999e8e9 100644 --- a/models/action.go +++ b/models/action.go @@ -337,7 +337,7 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) { actions := make([]*Action, 0, setting.UI.FeedPagingNum) - if err := db.GetEngine(db.DefaultContext).Limit(setting.UI.FeedPagingNum).Desc("created_unix").Where(cond).Find(&actions); err != nil { + if err := db.GetEngine(db.DefaultContext).Limit(setting.UI.FeedPagingNum).Desc("`action`.created_unix").Where(cond).Join("INNER", "repository", "`repository`.id = `action`.repo_id").Find(&actions); err != nil { return nil, fmt.Errorf("Find: %v", err) } @@ -401,7 +401,7 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) { cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID}) } if !opts.IncludePrivate { - cond = cond.And(builder.Eq{"is_private": false}) + cond = cond.And(builder.Eq{"`action`.is_private": false}) } if !opts.IncludeDeleted { cond = cond.And(builder.Eq{"is_deleted": false}) @@ -414,8 +414,8 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) { } else { dateHigh := dateLow.Add(86399000000000) // 23h59m59s - cond = cond.And(builder.Gte{"created_unix": dateLow.Unix()}) - cond = cond.And(builder.Lte{"created_unix": dateHigh.Unix()}) + cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()}) + cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()}) } } diff --git a/models/action_test.go b/models/action_test.go index 306d382364..dec3e81f1a 100644 --- a/models/action_test.go +++ b/models/action_test.go @@ -129,3 +129,20 @@ func TestNotifyWatchers(t *testing.T) { OpType: action.OpType, }) } + +func TestGetFeedsCorrupted(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + unittest.AssertExistsAndLoadBean(t, &Action{ + ID: 8, + RepoID: 1700, + }) + + actions, err := GetFeeds(GetFeedsOptions{ + RequestedUser: user, + Actor: user, + IncludePrivate: true, + }) + assert.NoError(t, err) + assert.Len(t, actions, 0) +} diff --git a/models/asymkey/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go index 4b9d0cfda4..2f66863091 100644 --- a/models/asymkey/gpg_key_commit_verification.go +++ b/models/asymkey/gpg_key_commit_verification.go @@ -71,7 +71,7 @@ const ( ) // ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys. -func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType, isCodeReader func(*user_model.User) (bool, error)) []*SignCommit { +func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error)) []*SignCommit { newCommits := make([]*SignCommit, 0, len(oldCommits)) keyMap := map[string]bool{} @@ -81,7 +81,7 @@ func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repoTrustMod Verification: ParseCommitWithSignature(c.Commit), } - _ = CalculateTrustStatus(signCommit.Verification, repoTrustModel, isCodeReader, &keyMap) + _ = CalculateTrustStatus(signCommit.Verification, repoTrustModel, isOwnerMemberCollaborator, &keyMap) newCommits = append(newCommits, signCommit) } @@ -455,7 +455,7 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use // CalculateTrustStatus will calculate the TrustStatus for a commit verification within a repository // There are several trust models in Gitea -func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_model.TrustModelType, isCodeReader func(*user_model.User) (bool, error), keyMap *map[string]bool) (err error) { +func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error), keyMap *map[string]bool) (err error) { if !verification.Verified { return } @@ -500,11 +500,11 @@ func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_ var has bool isMember, has = (*keyMap)[verification.SigningKey.KeyID] if !has { - isMember, err = isCodeReader(verification.SigningUser) + isMember, err = isOwnerMemberCollaborator(verification.SigningUser) (*keyMap)[verification.SigningKey.KeyID] = isMember } } else { - isMember, err = isCodeReader(verification.SigningUser) + isMember, err = isOwnerMemberCollaborator(verification.SigningUser) } if !isMember { diff --git a/models/asymkey/ssh_key_deploy.go b/models/asymkey/ssh_key_deploy.go index fc6324792a..fe2ade43ae 100644 --- a/models/asymkey/ssh_key_deploy.go +++ b/models/asymkey/ssh_key_deploy.go @@ -58,7 +58,7 @@ func (key *DeployKey) GetContent() error { return nil } -// IsReadOnly checks if the key can only be used for read operations +// IsReadOnly checks if the key can only be used for read operations, used by template func (key *DeployKey) IsReadOnly() bool { return key.Mode == perm.AccessModeRead } @@ -203,12 +203,6 @@ func UpdateDeployKeyCols(key *DeployKey, cols ...string) error { return err } -// UpdateDeployKey updates deploy key information. -func UpdateDeployKey(key *DeployKey) error { - _, err := db.GetEngine(db.DefaultContext).ID(key.ID).AllCols().Update(key) - return err -} - // ListDeployKeysOptions are options for ListDeployKeys type ListDeployKeysOptions struct { db.ListOptions diff --git a/models/auth/webauthn.go b/models/auth/webauthn.go index 9e09134662..1813a68193 100644 --- a/models/auth/webauthn.go +++ b/models/auth/webauthn.go @@ -43,7 +43,7 @@ type WebAuthnCredential struct { Name string LowerName string `xorm:"unique(s)"` UserID int64 `xorm:"INDEX unique(s)"` - CredentialID string `xorm:"INDEX"` + CredentialID string `xorm:"INDEX VARCHAR(410)"` PublicKey []byte AttestationType string AAGUID []byte diff --git a/models/commit.go b/models/commit.go index 5df6964a1d..92a839b780 100644 --- a/models/commit.go +++ b/models/commit.go @@ -18,7 +18,7 @@ func ConvertFromGitCommit(commits []*git.Commit, repo *repo_model.Repository) [] user_model.ValidateCommitsWithEmails(commits), repo.GetTrustModel(), func(user *user_model.User) (bool, error) { - return IsUserRepoAdmin(repo, user) + return IsOwnerMemberCollaborator(repo, user.ID) }, ), repo, diff --git a/models/consistency.go b/models/consistency.go index 0b9d9fd2c3..7eb5115a11 100644 --- a/models/consistency.go +++ b/models/consistency.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" "xorm.io/builder" ) @@ -94,7 +95,8 @@ func CountOrphanedIssues() (int64, error) { return db.GetEngine(db.DefaultContext).Table("issue"). Join("LEFT", "repository", "issue.repo_id=repository.id"). Where(builder.IsNull{"repository.id"}). - Count("id") + Select("COUNT(`issue`.`id`)"). + Count() } // DeleteOrphanedIssues delete issues without a repo @@ -139,8 +141,9 @@ func DeleteOrphanedIssues() error { func CountOrphanedObjects(subject, refobject, joinCond string) (int64, error) { return db.GetEngine(db.DefaultContext).Table("`"+subject+"`"). Join("LEFT", "`"+refobject+"`", joinCond). - Where(builder.IsNull{"`" + refobject + "`.id"}). - Count("id") + Where(builder.IsNull{"`" + refobject + "`.`id`"}). + Select("COUNT(`" + subject + "`.`id`)"). + Count() } // DeleteOrphanedObjects delete subjects with have no existing refobject anymore @@ -240,10 +243,29 @@ func FixIssueLabelWithOutsideLabels() (int64, error) { WHERE (label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id) ) AS il_too )`) - if err != nil { return 0, err } return res.RowsAffected() } + +// CountActionCreatedUnixString count actions where created_unix is an empty string +func CountActionCreatedUnixString() (int64, error) { + if setting.Database.UseSQLite3 { + return db.GetEngine(db.DefaultContext).Where(`created_unix = ""`).Count(new(Action)) + } + return 0, nil +} + +// FixActionCreatedUnixString set created_unix to zero if it is an empty string +func FixActionCreatedUnixString() (int64, error) { + if setting.Database.UseSQLite3 { + res, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`) + if err != nil { + return 0, err + } + return res.RowsAffected() + } + return 0, nil +} diff --git a/models/consistency_test.go b/models/consistency_test.go index d49a0132f0..d7c6cf97bd 100644 --- a/models/consistency_test.go +++ b/models/consistency_test.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" ) @@ -33,3 +34,46 @@ func TestDeleteOrphanedObjects(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, countBefore, countAfter) } + +func TestConsistencyUpdateAction(t *testing.T) { + if !setting.Database.UseSQLite3 { + t.Skip("Test is only for SQLite database.") + } + assert.NoError(t, unittest.PrepareTestDatabase()) + id := 8 + unittest.AssertExistsAndLoadBean(t, &Action{ + ID: int64(id), + }) + _, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = "" WHERE id = ?`, id) + assert.NoError(t, err) + actions := make([]*Action, 0, 1) + // + // XORM returns an error when created_unix is a string + // + err = db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions) + if assert.Error(t, err) { + assert.Contains(t, err.Error(), "type string to a int64: invalid syntax") + } + // + // Get rid of incorrectly set created_unix + // + count, err := CountActionCreatedUnixString() + assert.NoError(t, err) + assert.EqualValues(t, 1, count) + count, err = FixActionCreatedUnixString() + assert.NoError(t, err) + assert.EqualValues(t, 1, count) + + count, err = CountActionCreatedUnixString() + assert.NoError(t, err) + assert.EqualValues(t, 0, count) + count, err = FixActionCreatedUnixString() + assert.NoError(t, err) + assert.EqualValues(t, 0, count) + + // + // XORM must be happy now + // + assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions)) + unittest.CheckConsistencyFor(t, &Action{}) +} diff --git a/models/error.go b/models/error.go index f0e8751d75..1d0f658eb8 100644 --- a/models/error.go +++ b/models/error.go @@ -332,7 +332,6 @@ type ErrInvalidCloneAddr struct { IsProtocolInvalid bool IsPermissionDenied bool LocalPath bool - NotResolvedIP bool } // IsErrInvalidCloneAddr checks if an error is a ErrInvalidCloneAddr. @@ -342,9 +341,6 @@ func IsErrInvalidCloneAddr(err error) bool { } func (err *ErrInvalidCloneAddr) Error() string { - if err.NotResolvedIP { - return fmt.Sprintf("migration/cloning from '%s' is not allowed: unknown hostname", err.Host) - } if err.IsInvalidPath { return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided path is invalid", err.Host) } diff --git a/models/fixtures/action.yml b/models/fixtures/action.yml index e3f3d2a971..32179079bb 100644 --- a/models/fixtures/action.yml +++ b/models/fixtures/action.yml @@ -56,3 +56,11 @@ repo_id: 8 is_private: false created_unix: 1603011540 # grouped with id:7 + +- id: 8 + user_id: 1 + op_type: 12 # close issue + act_user_id: 1 + repo_id: 1700 # dangling intentional + is_private: false + created_unix: 1603011541 diff --git a/models/helper_environment.go b/models/helper_environment.go index 57ec3ea1e9..4cad1e5368 100644 --- a/models/helper_environment.go +++ b/models/helper_environment.go @@ -23,8 +23,8 @@ const ( EnvPusherName = "GITEA_PUSHER_NAME" EnvPusherEmail = "GITEA_PUSHER_EMAIL" EnvPusherID = "GITEA_PUSHER_ID" - EnvKeyID = "GITEA_KEY_ID" - EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY" + EnvKeyID = "GITEA_KEY_ID" // public key ID + EnvDeployKeyID = "GITEA_DEPLOY_KEY_ID" EnvPRID = "GITEA_PR_ID" EnvIsInternal = "GITEA_INTERNAL_PUSH" EnvAppURL = "GITEA_ROOT_URL" diff --git a/models/issue.go b/models/issue.go index cb5791be9e..f2552c0a1e 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1165,7 +1165,8 @@ func GetIssuesByIDs(issueIDs []int64) ([]*Issue, error) { // IssuesOptions represents options of an issue. type IssuesOptions struct { db.ListOptions - RepoIDs []int64 // include all repos if empty + RepoID int64 // overwrites RepoCond if not 0 + RepoCond builder.Cond AssigneeID int64 PosterID int64 MentionedID int64 @@ -1238,7 +1239,7 @@ func sortIssuesSession(sess *xorm.Session, sortType string, priorityRepoID int64 } } -func (opts *IssuesOptions) setupSession(sess *xorm.Session) { +func (opts *IssuesOptions) setupSessionWithLimit(sess *xorm.Session) { if opts.Page >= 0 && opts.PageSize > 0 { var start int if opts.Page == 0 { @@ -1248,20 +1249,23 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) { } sess.Limit(opts.PageSize, start) } + opts.setupSessionNoLimit(sess) +} +func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) { if len(opts.IssueIDs) > 0 { sess.In("issue.id", opts.IssueIDs) } - if len(opts.RepoIDs) > 0 { - applyReposCondition(sess, opts.RepoIDs) + if opts.RepoID != 0 { + opts.RepoCond = builder.Eq{"issue.repo_id": opts.RepoID} + } + if opts.RepoCond != nil { + sess.And(opts.RepoCond) } - switch opts.IsClosed { - case util.OptionalBoolTrue: - sess.And("issue.is_closed=?", true) - case util.OptionalBoolFalse: - sess.And("issue.is_closed=?", false) + if !opts.IsClosed.IsNone() { + sess.And("issue.is_closed=?", opts.IsClosed.IsTrue()) } if opts.AssigneeID > 0 { @@ -1342,9 +1346,7 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) { } if opts.User != nil { - sess.And( - issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue()), - ) + sess.And(issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue())) } } @@ -1380,10 +1382,6 @@ func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *Organizati return cond } -func applyReposCondition(sess *xorm.Session, repoIDs []int64) *xorm.Session { - return sess.In("issue.repo_id", repoIDs) -} - func applyAssigneeCondition(sess *xorm.Session, assigneeID int64) *xorm.Session { return sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). And("issue_assignees.assignee_id = ?", assigneeID) @@ -1413,8 +1411,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) { e := db.GetEngine(db.DefaultContext) sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") - - opts.setupSession(sess) + opts.setupSessionNoLimit(sess) countsSlice := make([]*struct { RepoID int64 @@ -1424,7 +1421,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) { Select("issue.repo_id AS repo_id, COUNT(*) AS count"). Table("issue"). Find(&countsSlice); err != nil { - return nil, err + return nil, fmt.Errorf("unable to CountIssuesByRepo: %w", err) } countMap := make(map[int64]int64, len(countsSlice)) @@ -1440,15 +1437,14 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i e := db.GetEngine(db.DefaultContext) sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") - - opts.setupSession(sess) + opts.setupSessionNoLimit(sess) accessCond := accessibleRepositoryCondition(user) if err := sess.Where(accessCond). Distinct("issue.repo_id"). Table("issue"). Find(&repoIDs); err != nil { - return nil, err + return nil, fmt.Errorf("unable to GetRepoIDsForIssuesOptions: %w", err) } return repoIDs, nil @@ -1459,17 +1455,16 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) { e := db.GetEngine(db.DefaultContext) sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") - opts.setupSession(sess) + opts.setupSessionWithLimit(sess) sortIssuesSession(sess, opts.SortType, opts.PriorityRepoID) issues := make([]*Issue, 0, opts.ListOptions.PageSize) if err := sess.Find(&issues); err != nil { - return nil, fmt.Errorf("Find: %v", err) + return nil, fmt.Errorf("unable to query Issues: %w", err) } - sess.Close() if err := IssueList(issues).LoadAttributes(); err != nil { - return nil, fmt.Errorf("LoadAttributes: %v", err) + return nil, fmt.Errorf("unable to LoadAttributes for Issues: %w", err) } return issues, nil @@ -1480,18 +1475,18 @@ func CountIssues(opts *IssuesOptions) (int64, error) { e := db.GetEngine(db.DefaultContext) countsSlice := make([]*struct { - RepoID int64 - Count int64 + Count int64 }, 0, 1) sess := e.Select("COUNT(issue.id) AS count").Table("issue") sess.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") - opts.setupSession(sess) + opts.setupSessionNoLimit(sess) + if err := sess.Find(&countsSlice); err != nil { - return 0, fmt.Errorf("Find: %v", err) + return 0, fmt.Errorf("unable to CountIssues: %w", err) } - if len(countsSlice) < 1 { - return 0, fmt.Errorf("there is less than one result sql record") + if len(countsSlice) != 1 { + return 0, fmt.Errorf("unable to get one row result when CountIssues, row count=%d", len(countsSlice)) } return countsSlice[0].Count, nil } @@ -1551,6 +1546,7 @@ const ( FilterModeCreate FilterModeMention FilterModeReviewRequested + FilterModeYourRepositories ) func parseCountResult(results []map[string][]byte) int64 { @@ -1695,6 +1691,7 @@ type UserIssueStatsOptions struct { IssueIDs []int64 IsArchived util.OptionalBool LabelIDs []int64 + RepoCond builder.Cond Org *Organization Team *Team } @@ -1712,6 +1709,9 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { if len(opts.IssueIDs) > 0 { cond = cond.And(builder.In("issue.id", opts.IssueIDs)) } + if opts.RepoCond != nil { + cond = cond.And(opts.RepoCond) + } if opts.UserID > 0 { cond = cond.And(issuePullAccessibleRepoCond("issue.repo_id", opts.UserID, opts.Org, opts.Team, opts.IsPull)) @@ -1733,7 +1733,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { } switch opts.FilterMode { - case FilterModeAll: + case FilterModeAll, FilterModeYourRepositories: stats.OpenCount, err = sess(cond). And("issue.is_closed = ?", false). Count(new(Issue)) diff --git a/models/issue_assignees.go b/models/issue_assignees.go index b3511f8b59..10bc2dafbe 100644 --- a/models/issue_assignees.go +++ b/models/issue_assignees.go @@ -155,31 +155,26 @@ func toggleUserAssignee(e db.Engine, issue *Issue, assigneeID int64) (removed bo } // Check if the submitted user is already assigned, if yes delete him otherwise add him - var i int - for i = 0; i < len(issue.Assignees); i++ { + found := false + i := 0 + for ; i < len(issue.Assignees); i++ { if issue.Assignees[i].ID == assigneeID { + found = true break } } assigneeIn := IssueAssignees{AssigneeID: assigneeID, IssueID: issue.ID} - toBeDeleted := i < len(issue.Assignees) - if toBeDeleted { - issue.Assignees = append(issue.Assignees[:i], issue.Assignees[i:]...) + if found { + issue.Assignees = append(issue.Assignees[:i], issue.Assignees[i+1:]...) _, err = e.Delete(assigneeIn) - if err != nil { - return toBeDeleted, err - } } else { issue.Assignees = append(issue.Assignees, assignee) _, err = e.Insert(assigneeIn) - if err != nil { - return toBeDeleted, err - } } - return toBeDeleted, nil + return found, err } // MakeIDsFromAPIAssigneesToAdd returns an array with all assignee IDs diff --git a/models/issue_label.go b/models/issue_label.go index 53d28c0596..ac28829c7d 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -101,12 +102,10 @@ func (label *Label) CalOpenIssues() { // CalOpenOrgIssues calculates the open issues of a label for a specific repo func (label *Label) CalOpenOrgIssues(repoID, labelID int64) { - repoIDs := []int64{repoID} - labelIDs := []int64{labelID} - counts, _ := CountIssuesByRepo(&IssuesOptions{ - RepoIDs: repoIDs, - LabelIDs: labelIDs, + RepoID: repoID, + LabelIDs: []int64{labelID}, + IsClosed: util.OptionalBoolFalse, }) for _, count := range counts { diff --git a/models/issue_milestone.go b/models/issue_milestone.go index 7f2fd9a1f3..4c77815820 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -116,6 +116,11 @@ func getMilestoneByRepoID(e db.Engine, repoID, id int64) (*Milestone, error) { return m, nil } +// HasMilestoneByRepoID returns if the milestone exists in the repository. +func HasMilestoneByRepoID(repoID, id int64) (bool, error) { + return db.GetEngine(db.DefaultContext).ID(id).Where("repo_id=?", repoID).Exist(new(Milestone)) +} + // GetMilestoneByRepoID returns the milestone in a repository. func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) { return getMilestoneByRepoID(db.GetEngine(db.DefaultContext), repoID, id) @@ -134,22 +139,6 @@ func GetMilestoneByRepoIDANDName(repoID int64, name string) (*Milestone, error) return &mile, nil } -// GetMilestoneByID returns the milestone via id . -func GetMilestoneByID(id int64) (*Milestone, error) { - return getMilestoneByID(db.GetEngine(db.DefaultContext), id) -} - -func getMilestoneByID(e db.Engine, id int64) (*Milestone, error) { - var m Milestone - has, err := e.ID(id).Get(&m) - if err != nil { - return nil, err - } else if !has { - return nil, ErrMilestoneNotExist{ID: id, RepoID: 0} - } - return &m, nil -} - // UpdateMilestone updates information of given milestone. func UpdateMilestone(m *Milestone, oldIsClosed bool) error { ctx, committer, err := db.TxContext() @@ -267,6 +256,17 @@ func changeMilestoneStatus(ctx context.Context, m *Milestone, isClosed bool) err } func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *Issue, oldMilestoneID int64) error { + // Only check if milestone exists if we don't remove it. + if issue.MilestoneID > 0 { + has, err := HasMilestoneByRepoID(issue.RepoID, issue.MilestoneID) + if err != nil { + return fmt.Errorf("HasMilestoneByRepoID: %v", err) + } + if !has { + return fmt.Errorf("HasMilestoneByRepoID: issue doesn't exist") + } + } + if err := updateIssueCols(ctx, issue, "milestone_id"); err != nil { return err } diff --git a/models/issue_test.go b/models/issue_test.go index aee9a50184..2581398acf 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -17,6 +17,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "github.com/stretchr/testify/assert" + "xorm.io/builder" ) func TestIssue_ReplaceLabels(t *testing.T) { @@ -153,7 +154,7 @@ func TestIssues(t *testing.T) { }, { IssuesOptions{ - RepoIDs: []int64{1, 3}, + RepoCond: builder.In("repo_id", 1, 3), SortType: "oldest", ListOptions: db.ListOptions{ Page: 1, @@ -340,7 +341,7 @@ func TestGetRepoIDsForIssuesOptions(t *testing.T) { }, { IssuesOptions{ - RepoIDs: []int64{1, 2}, + RepoCond: builder.In("repo_id", 1, 2), }, []int64{1, 2}, }, diff --git a/models/issues/content_history.go b/models/issues/content_history.go index 721ce11f85..57a6ea728f 100644 --- a/models/issues/content_history.go +++ b/models/issues/content_history.go @@ -137,6 +137,7 @@ func QueryIssueContentHistoryEditedCountMap(dbCtx context.Context, issueID int64 type IssueContentListItem struct { UserID int64 UserName string + UserFullName string UserAvatarLink string HistoryID int64 @@ -148,7 +149,7 @@ type IssueContentListItem struct { // FetchIssueContentHistoryList fetch list func FetchIssueContentHistoryList(dbCtx context.Context, issueID, commentID int64) ([]*IssueContentListItem, error) { res := make([]*IssueContentListItem, 0) - err := db.GetEngine(dbCtx).Select("u.id as user_id, u.name as user_name,"+ + err := db.GetEngine(dbCtx).Select("u.id as user_id, u.name as user_name, u.full_name as user_full_name,"+ "h.id as history_id, h.edited_unix, h.is_first_created, h.is_deleted"). Table([]string{"issue_content_history", "h"}). Join("LEFT", []string{"user", "u"}, "h.poster_id = u.id"). diff --git a/models/issues/content_history_test.go b/models/issues/content_history_test.go index cc9a7c5107..71ccc6e6a7 100644 --- a/models/issues/content_history_test.go +++ b/models/issues/content_history_test.go @@ -43,8 +43,9 @@ func TestContentHistory(t *testing.T) { when the refactor of models are done, this test will be possible to be run then with a real `User` model. */ type User struct { - ID int64 - Name string + ID int64 + Name string + FullName string } _ = dbEngine.Sync2(&User{}) diff --git a/models/lfs.go b/models/lfs.go index cf596f5468..0ddbdef5e1 100644 --- a/models/lfs.go +++ b/models/lfs.go @@ -193,12 +193,13 @@ func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int6 // admin can associate any LFS object to any repository, and we do not care about errors (eg: duplicated unique key), // even if error occurs, it won't hurt users and won't make things worse for i := range metas { + p := lfs.Pointer{Oid: metas[i].Oid, Size: metas[i].Size} _, err = sess.Insert(&LFSMetaObject{ - Pointer: lfs.Pointer{Oid: metas[i].Oid, Size: metas[i].Size}, + Pointer: p, RepositoryID: repoID, }) if err != nil { - log.Warn("failed to insert LFS meta object into database, err=%v", err) + log.Warn("failed to insert LFS meta object %-v for repo_id: %d into database, err=%v", p, repoID, err) } } } diff --git a/models/migrate.go b/models/migrate.go index 4da426887b..bbfba1fa1e 100644 --- a/models/migrate.go +++ b/models/migrate.go @@ -52,10 +52,6 @@ func InsertIssues(issues ...*Issue) error { return err } } - err = UpdateRepoStats(ctx, issues[0].RepoID) - if err != nil { - return err - } return committer.Commit() } @@ -147,11 +143,6 @@ func InsertPullRequests(prs ...*PullRequest) error { return err } } - - err = UpdateRepoStats(ctx, prs[0].Issue.RepoID) - if err != nil { - return err - } return committer.Commit() } diff --git a/models/migrate_test.go b/models/migrate_test.go index 09433b6b41..2a4f026766 100644 --- a/models/migrate_test.go +++ b/models/migrate_test.go @@ -32,8 +32,9 @@ func TestMigrate_InsertMilestones(t *testing.T) { unittest.CheckConsistencyFor(t, &Milestone{}) } -func assertCreateIssues(t *testing.T, reponame string, isPull bool) { +func assertCreateIssues(t *testing.T, isPull bool) { assert.NoError(t, unittest.PrepareTestDatabase()) + reponame := "repo1" repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label) @@ -63,38 +64,14 @@ func assertCreateIssues(t *testing.T, reponame string, isPull bool) { i := unittest.AssertExistsAndLoadBean(t, &Issue{Title: title}).(*Issue) unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID}) - - labelModified := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label) - assert.EqualValues(t, label.NumIssues+1, labelModified.NumIssues) - assert.EqualValues(t, label.NumClosedIssues+1, labelModified.NumClosedIssues) - - milestoneModified := unittest.AssertExistsAndLoadBean(t, &Milestone{ID: milestone.ID}).(*Milestone) - assert.EqualValues(t, milestone.NumIssues+1, milestoneModified.NumIssues) - assert.EqualValues(t, milestone.NumClosedIssues+1, milestoneModified.NumClosedIssues) } func TestMigrate_CreateIssuesIsPullFalse(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - reponame := "repo1" - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository) - - assertCreateIssues(t, reponame, false) - - repoModified := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}).(*repo_model.Repository) - assert.EqualValues(t, repo.NumIssues+1, repoModified.NumIssues) - assert.EqualValues(t, repo.NumClosedIssues+1, repoModified.NumClosedIssues) + assertCreateIssues(t, false) } func TestMigrate_CreateIssuesIsPullTrue(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - reponame := "repo1" - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository) - - assertCreateIssues(t, reponame, true) - - repoModified := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}).(*repo_model.Repository) - assert.EqualValues(t, repo.NumPulls+1, repoModified.NumPulls) - assert.EqualValues(t, repo.NumClosedPulls+1, repoModified.NumClosedPulls) + assertCreateIssues(t, true) } func TestMigrate_InsertIssueComments(t *testing.T) { diff --git a/models/migrations/fixtures/Test_remigrateU2FCredentials/expected_webauthn_credential.yml b/models/migrations/fixtures/Test_remigrateU2FCredentials/expected_webauthn_credential.yml new file mode 100644 index 0000000000..0e68a5d012 --- /dev/null +++ b/models/migrations/fixtures/Test_remigrateU2FCredentials/expected_webauthn_credential.yml @@ -0,0 +1,12 @@ +- + id: 1 + credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG=" +- + id: 2 + credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG=" +- + id: 3 + credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG=" +- + id: 4 + credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG=" diff --git a/models/migrations/fixtures/Test_remigrateU2FCredentials/u2f_registration.yml b/models/migrations/fixtures/Test_remigrateU2FCredentials/u2f_registration.yml new file mode 100644 index 0000000000..5a7b70fd6a --- /dev/null +++ b/models/migrations/fixtures/Test_remigrateU2FCredentials/u2f_registration.yml @@ -0,0 +1,21 @@ +- + id: 1 + name: "u2fkey-correctly-migrated" + user_id: 1 + raw: 0x05040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf240efe2e213b889daf3fc88e3952e8dd6b4cfd82f1a1212e2ab4b19389455ecf3e67f0aeafc91b9c0d413c9d6215a45177c1d5076358aa6ee20e1b30e3d7467cae2308202bd308201a5a00302010202041e8f8734300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a306e310b300906035504061302534531123010060355040a0c0959756269636f20414231223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e3127302506035504030c1e59756269636f205532462045452053657269616c203531323732323734303059301306072a8648ce3d020106082a8648ce3d03010703420004a879f82338ed1494bac0704bcc7fc663d1b271715976243101c7605115d7c1529e281c1c67322d384b5cd55dd3e9818d5fd85c22af326e0c64fc20afe33f2366a36c306a302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e373013060b2b0601040182e51c0201010404030204303021060b2b0601040182e51c010104041204102fc0579f811347eab116bb5a8db9202a300c0603551d130101ff04023000300d06092a864886f70d01010b050003820101008693ff62df0d5779d4748d7fc8d10227318a8e580e6a3a57c108e94e03c38568b366894fce5624be4a3efd7f34118b3d993743f792a1989160c8fc9ae0b04e3df9ee15e3e88c04fc82a8dcbf5818e108dcc2968577ae79ff662b94734e3dec4597305d73e6e55ee2beb9cd9678ca0935e533eb638f8e26fabb817cda441fbe9831832ae5f6e2ad992f9ebbdb4c62238b8f8d7ab481d6d3263bcdbf9e4a57550370988ad5813440fa032cadb6723cadd8f8d7ba809f75b43cffa0a5b9add14232ef9d9e14812638233c4ca4a873b9f8ac98e32ba19167606e15909fcddb4a2dffbdae4620249f9a6646ac81e4832d1119febfaa731a882da25a77827d46d190173046022100b579338a44c236d3f214b2e150011a08cf251193ecfae2244edb0a5794e9b301022100fab468862c47d98204d437cf2be8c54a5a4ecd1ebb1c61a6c23da7b9c75f6841 + counter: 0 +- id: 2 + name: "u2fkey-incorrectly-migrated" + user_id: 1 + raw: 0x05040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf240efe2e213b889daf3fc88e3952e8dd6b4cfd82f1a1212e2ab4b19389455ecf3e67f0aeafc91b9c0d413c9d6215a45177c1d5076358aa6ee20e1b30e3d7467cae2308202bd308201a5a00302010202041e8f8734300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a306e310b300906035504061302534531123010060355040a0c0959756269636f20414231223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e3127302506035504030c1e59756269636f205532462045452053657269616c203531323732323734303059301306072a8648ce3d020106082a8648ce3d03010703420004a879f82338ed1494bac0704bcc7fc663d1b271715976243101c7605115d7c1529e281c1c67322d384b5cd55dd3e9818d5fd85c22af326e0c64fc20afe33f2366a36c306a302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e373013060b2b0601040182e51c0201010404030204303021060b2b0601040182e51c010104041204102fc0579f811347eab116bb5a8db9202a300c0603551d130101ff04023000300d06092a864886f70d01010b050003820101008693ff62df0d5779d4748d7fc8d10227318a8e580e6a3a57c108e94e03c38568b366894fce5624be4a3efd7f34118b3d993743f792a1989160c8fc9ae0b04e3df9ee15e3e88c04fc82a8dcbf5818e108dcc2968577ae79ff662b94734e3dec4597305d73e6e55ee2beb9cd9678ca0935e533eb638f8e26fabb817cda441fbe9831832ae5f6e2ad992f9ebbdb4c62238b8f8d7ab481d6d3263bcdbf9e4a57550370988ad5813440fa032cadb6723cadd8f8d7ba809f75b43cffa0a5b9add14232ef9d9e14812638233c4ca4a873b9f8ac98e32ba19167606e15909fcddb4a2dffbdae4620249f9a6646ac81e4832d1119febfaa731a882da25a77827d46d190173046022100b579338a44c236d3f214b2e150011a08cf251193ecfae2244edb0a5794e9b301022100fab468862c47d98204d437cf2be8c54a5a4ecd1ebb1c61a6c23da7b9c75f6841 + counter: 0 +- id: 3 + name: "u2fkey-deleted" + user_id: 1 + raw: 0x05040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf240efe2e213b889daf3fc88e3952e8dd6b4cfd82f1a1212e2ab4b19389455ecf3e67f0aeafc91b9c0d413c9d6215a45177c1d5076358aa6ee20e1b30e3d7467cae2308202bd308201a5a00302010202041e8f8734300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a306e310b300906035504061302534531123010060355040a0c0959756269636f20414231223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e3127302506035504030c1e59756269636f205532462045452053657269616c203531323732323734303059301306072a8648ce3d020106082a8648ce3d03010703420004a879f82338ed1494bac0704bcc7fc663d1b271715976243101c7605115d7c1529e281c1c67322d384b5cd55dd3e9818d5fd85c22af326e0c64fc20afe33f2366a36c306a302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e373013060b2b0601040182e51c0201010404030204303021060b2b0601040182e51c010104041204102fc0579f811347eab116bb5a8db9202a300c0603551d130101ff04023000300d06092a864886f70d01010b050003820101008693ff62df0d5779d4748d7fc8d10227318a8e580e6a3a57c108e94e03c38568b366894fce5624be4a3efd7f34118b3d993743f792a1989160c8fc9ae0b04e3df9ee15e3e88c04fc82a8dcbf5818e108dcc2968577ae79ff662b94734e3dec4597305d73e6e55ee2beb9cd9678ca0935e533eb638f8e26fabb817cda441fbe9831832ae5f6e2ad992f9ebbdb4c62238b8f8d7ab481d6d3263bcdbf9e4a57550370988ad5813440fa032cadb6723cadd8f8d7ba809f75b43cffa0a5b9add14232ef9d9e14812638233c4ca4a873b9f8ac98e32ba19167606e15909fcddb4a2dffbdae4620249f9a6646ac81e4832d1119febfaa731a882da25a77827d46d190173046022100b579338a44c236d3f214b2e150011a08cf251193ecfae2244edb0a5794e9b301022100fab468862c47d98204d437cf2be8c54a5a4ecd1ebb1c61a6c23da7b9c75f6841 + counter: 0 +- id: 4 + name: "u2fkey-wrong-user-id" + user_id: 2 + raw: 0x05040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf240efe2e213b889daf3fc88e3952e8dd6b4cfd82f1a1212e2ab4b19389455ecf3e67f0aeafc91b9c0d413c9d6215a45177c1d5076358aa6ee20e1b30e3d7467cae2308202bd308201a5a00302010202041e8f8734300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a306e310b300906035504061302534531123010060355040a0c0959756269636f20414231223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e3127302506035504030c1e59756269636f205532462045452053657269616c203531323732323734303059301306072a8648ce3d020106082a8648ce3d03010703420004a879f82338ed1494bac0704bcc7fc663d1b271715976243101c7605115d7c1529e281c1c67322d384b5cd55dd3e9818d5fd85c22af326e0c64fc20afe33f2366a36c306a302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e373013060b2b0601040182e51c0201010404030204303021060b2b0601040182e51c010104041204102fc0579f811347eab116bb5a8db9202a300c0603551d130101ff04023000300d06092a864886f70d01010b050003820101008693ff62df0d5779d4748d7fc8d10227318a8e580e6a3a57c108e94e03c38568b366894fce5624be4a3efd7f34118b3d993743f792a1989160c8fc9ae0b04e3df9ee15e3e88c04fc82a8dcbf5818e108dcc2968577ae79ff662b94734e3dec4597305d73e6e55ee2beb9cd9678ca0935e533eb638f8e26fabb817cda441fbe9831832ae5f6e2ad992f9ebbdb4c62238b8f8d7ab481d6d3263bcdbf9e4a57550370988ad5813440fa032cadb6723cadd8f8d7ba809f75b43cffa0a5b9add14232ef9d9e14812638233c4ca4a873b9f8ac98e32ba19167606e15909fcddb4a2dffbdae4620249f9a6646ac81e4832d1119febfaa731a882da25a77827d46d190173046022100b579338a44c236d3f214b2e150011a08cf251193ecfae2244edb0a5794e9b301022100fab468862c47d98204d437cf2be8c54a5a4ecd1ebb1c61a6c23da7b9c75f6841 + counter: 0 diff --git a/models/migrations/fixtures/Test_remigrateU2FCredentials/webauthn_credential.yml b/models/migrations/fixtures/Test_remigrateU2FCredentials/webauthn_credential.yml new file mode 100644 index 0000000000..7f9f10f89a --- /dev/null +++ b/models/migrations/fixtures/Test_remigrateU2FCredentials/webauthn_credential.yml @@ -0,0 +1,30 @@ +- + id: 1 + lower_name: "u2fkey-correctly-migrated" + name: "u2fkey-correctly-migrated" + user_id: 1 + credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG=" + public_key: 0x040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf2 + attestation_type: 'fido-u2f' + sign_count: 1 + clone_warning: false +- + id: 2 + lower_name: "u2fkey-incorrectly-migrated" + name: "u2fkey-incorrectly-migrated" + user_id: 1 + credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8A" + public_key: 0x040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf2 + attestation_type: 'fido-u2f' + sign_count: 1 + clone_warning: false +- + id: 4 + lower_name: "u2fkey-wrong-user-id" + name: "u2fkey-wrong-user-id" + user_id: 1 + credential_id: "THIS SHOULD CHANGE" + public_key: 0x040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf2 + attestation_type: 'fido-u2f' + sign_count: 1 + clone_warning: false diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 5aaf283bd3..6dff3e055b 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -61,7 +61,6 @@ type Version struct { // update minDBVersion accordingly var migrations = []Migration{ // Gitea 1.5.0 ends at v69 - // v70 -> v71 NewMigration("add issue_dependencies", addIssueDependencies), // v71 -> v72 @@ -367,9 +366,13 @@ var migrations = []Migration{ // v206 -> v207 NewMigration("Add authorize column to team_unit table", addAuthorizeColForTeamUnit), // v207 -> v208 - NewMigration("Add webauthn table and migrate u2f data to webauthn", addWebAuthnCred), + NewMigration("Add webauthn table and migrate u2f data to webauthn - NO-OPED", addWebAuthnCred), // v208 -> v209 - NewMigration("Use base32.HexEncoding instead of base64 encoding for cred ID as it is case insensitive", useBase32HexForCredIDInWebAuthnCredential), + NewMigration("Use base32.HexEncoding instead of base64 encoding for cred ID as it is case insensitive - NO-OPED", useBase32HexForCredIDInWebAuthnCredential), + // v209 -> v210 + NewMigration("Increase WebAuthentication CredentialID size to 410 - NO-OPED", increaseCredentialIDTo410), + // v210 -> v211 + NewMigration("v208 was completely broken - remigrate", remigrateU2FCredentials), } // GetCurrentDBVersion returns the current db version @@ -450,9 +453,12 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t // Downgrading Gitea's database version not supported if int(v-minDBVersion) > len(migrations) { - msg := fmt.Sprintf("Downgrading database version from '%d' to '%d' is not supported and may result in loss of data integrity.\nIf you really know what you're doing, execute `UPDATE version SET version=%d WHERE id=1;`\n", - v, minDBVersion+len(migrations), minDBVersion+len(migrations)) - fmt.Fprint(os.Stderr, msg) + msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Gitea, you can not use the newer database for this old Gitea release (%d).", v, minDBVersion+len(migrations)) + msg += "\nGitea will exit to keep your database safe and unchanged. Please use the correct Gitea release, do not change the migration version manually (incorrect manual operation may lose data)." + if !setting.IsProd { + msg += fmt.Sprintf("\nIf you are in development and really know what you're doing, you can force changing the migration version by executing: UPDATE version SET version=%d WHERE id=1;", minDBVersion+len(migrations)) + } + _, _ = fmt.Fprintln(os.Stderr, msg) log.Fatal(msg) return nil } diff --git a/models/migrations/v207.go b/models/migrations/v207.go index 82e2e3aa31..f60dfc3dc3 100644 --- a/models/migrations/v207.go +++ b/models/migrations/v207.go @@ -5,87 +5,11 @@ package migrations import ( - "crypto/elliptic" - "encoding/base64" - "strings" - - "code.gitea.io/gitea/modules/timeutil" - - "github.com/tstranex/u2f" "xorm.io/xorm" ) func addWebAuthnCred(x *xorm.Engine) error { - - // Create webauthnCredential table - type webauthnCredential struct { - ID int64 `xorm:"pk autoincr"` - Name string - LowerName string `xorm:"unique(s)"` - UserID int64 `xorm:"INDEX unique(s)"` - CredentialID string `xorm:"INDEX"` - PublicKey []byte - AttestationType string - AAGUID []byte - SignCount uint32 `xorm:"BIGINT"` - CloneWarning bool - CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` - } - if err := x.Sync2(&webauthnCredential{}); err != nil { - return err - } - - // Now migrate the old u2f registrations to the new format - type u2fRegistration struct { - ID int64 `xorm:"pk autoincr"` - Name string - UserID int64 `xorm:"INDEX"` - Raw []byte - Counter uint32 `xorm:"BIGINT"` - CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` - } - - var start int - regs := make([]*u2fRegistration, 0, 50) - for { - err := x.OrderBy("id").Limit(50, start).Find(®s) - if err != nil { - return err - } - - for _, reg := range regs { - parsed := new(u2f.Registration) - err = parsed.UnmarshalBinary(reg.Raw) - if err != nil { - continue - } - - c := &webauthnCredential{ - ID: reg.ID, - Name: reg.Name, - LowerName: strings.ToLower(reg.Name), - UserID: reg.UserID, - CredentialID: base64.RawStdEncoding.EncodeToString(parsed.KeyHandle), - PublicKey: elliptic.Marshal(elliptic.P256(), parsed.PubKey.X, parsed.PubKey.Y), - AttestationType: "fido-u2f", - AAGUID: []byte{}, - SignCount: reg.Counter, - } - - _, err := x.Insert(c) - if err != nil { - return err - } - } - - if len(regs) < 50 { - break - } - start += 50 - regs = regs[:0] - } + // NO-OP Don't migrate here - let v210 do this. return nil } diff --git a/models/migrations/v208.go b/models/migrations/v208.go index 04bb981a4e..2875406121 100644 --- a/models/migrations/v208.go +++ b/models/migrations/v208.go @@ -5,47 +5,10 @@ package migrations import ( - "encoding/base32" - "encoding/base64" - "xorm.io/xorm" ) func useBase32HexForCredIDInWebAuthnCredential(x *xorm.Engine) error { - - // Create webauthnCredential table - type webauthnCredential struct { - ID int64 `xorm:"pk autoincr"` - CredentialID string `xorm:"INDEX"` - } - if err := x.Sync2(&webauthnCredential{}); err != nil { - return err - } - - var start int - regs := make([]*webauthnCredential, 0, 50) - for { - err := x.OrderBy("id").Limit(50, start).Find(®s) - if err != nil { - return err - } - - for _, reg := range regs { - credID, _ := base64.RawStdEncoding.DecodeString(reg.CredentialID) - reg.CredentialID = base32.HexEncoding.EncodeToString(credID) - - _, err := x.Update(reg) - if err != nil { - return err - } - } - - if len(regs) < 50 { - break - } - start += 50 - regs = regs[:0] - } - + // noop return nil } diff --git a/models/migrations/v209.go b/models/migrations/v209.go new file mode 100644 index 0000000000..ac03f11cc1 --- /dev/null +++ b/models/migrations/v209.go @@ -0,0 +1,17 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "xorm.io/xorm" +) + +func increaseCredentialIDTo410(x *xorm.Engine) error { + // no-op + // V208 is badly broken + // So now we have to no-op again. + + return nil +} diff --git a/models/migrations/v210.go b/models/migrations/v210.go new file mode 100644 index 0000000000..f32fae77ba --- /dev/null +++ b/models/migrations/v210.go @@ -0,0 +1,184 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "crypto/elliptic" + "encoding/base32" + "fmt" + "strings" + + "code.gitea.io/gitea/modules/timeutil" + + "github.com/tstranex/u2f" + "xorm.io/xorm" + "xorm.io/xorm/schemas" +) + +// v208 migration was completely broken +func remigrateU2FCredentials(x *xorm.Engine) error { + // Create webauthnCredential table + type webauthnCredential struct { + ID int64 `xorm:"pk autoincr"` + Name string + LowerName string `xorm:"unique(s)"` + UserID int64 `xorm:"INDEX unique(s)"` + CredentialID string `xorm:"INDEX VARCHAR(410)"` // CredentalID in U2F is at most 255bytes / 5 * 8 = 408 - add a few extra characters for safety + PublicKey []byte + AttestationType string + AAGUID []byte + SignCount uint32 `xorm:"BIGINT"` + CloneWarning bool + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` + } + if err := x.Sync2(&webauthnCredential{}); err != nil { + return err + } + + switch x.Dialect().URI().DBType { + case schemas.MYSQL: + _, err := x.Exec("ALTER TABLE webauthn_credential MODIFY COLUMN credential_id VARCHAR(410)") + if err != nil { + return err + } + case schemas.ORACLE: + _, err := x.Exec("ALTER TABLE webauthn_credential MODIFY credential_id VARCHAR(410)") + if err != nil { + return err + } + case schemas.MSSQL: + // This column has an index on it. I could write all of the code to attempt to change the index OR + // I could just use recreate table. + sess := x.NewSession() + if err := sess.Begin(); err != nil { + _ = sess.Close() + return err + } + + if err := recreateTable(sess, new(webauthnCredential)); err != nil { + _ = sess.Close() + return err + } + if err := sess.Commit(); err != nil { + _ = sess.Close() + return err + } + if err := sess.Close(); err != nil { + return err + } + case schemas.POSTGRES: + _, err := x.Exec("ALTER TABLE webauthn_credential ALTER COLUMN credential_id TYPE VARCHAR(410)") + if err != nil { + return err + } + default: + // SQLite doesn't support ALTER COLUMN, and it already makes String _TEXT_ by default so no migration needed + // nor is there any need to re-migrate + } + + exist, err := x.IsTableExist("u2f_registration") + if err != nil { + return err + } + if !exist { + return nil + } + + // Now migrate the old u2f registrations to the new format + type u2fRegistration struct { + ID int64 `xorm:"pk autoincr"` + Name string + UserID int64 `xorm:"INDEX"` + Raw []byte + Counter uint32 `xorm:"BIGINT"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` + } + + var start int + regs := make([]*u2fRegistration, 0, 50) + for { + err := x.OrderBy("id").Limit(50, start).Find(®s) + if err != nil { + return err + } + + err = func() error { + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return fmt.Errorf("unable to allow start session. Error: %w", err) + } + if x.Dialect().URI().DBType == schemas.MSSQL { + if _, err := sess.Exec("SET IDENTITY_INSERT `webauthn_credential` ON"); err != nil { + return fmt.Errorf("unable to allow identity insert on webauthn_credential. Error: %w", err) + } + } + for _, reg := range regs { + parsed := new(u2f.Registration) + err = parsed.UnmarshalBinary(reg.Raw) + if err != nil { + continue + } + remigrated := &webauthnCredential{ + ID: reg.ID, + Name: reg.Name, + LowerName: strings.ToLower(reg.Name), + UserID: reg.UserID, + CredentialID: base32.HexEncoding.EncodeToString(parsed.KeyHandle), + PublicKey: elliptic.Marshal(elliptic.P256(), parsed.PubKey.X, parsed.PubKey.Y), + AttestationType: "fido-u2f", + AAGUID: []byte{}, + SignCount: reg.Counter, + UpdatedUnix: reg.UpdatedUnix, + CreatedUnix: reg.CreatedUnix, + } + + has, err := sess.ID(reg.ID).Get(new(webauthnCredential)) + if err != nil { + return fmt.Errorf("unable to get webauthn_credential[%d]. Error: %w", reg.ID, err) + } + if !has { + has, err := sess.Where("`lower_name`=?", remigrated.LowerName).And("`user_id`=?", remigrated.UserID).Exist(new(webauthnCredential)) + if err != nil { + return fmt.Errorf("unable to check webauthn_credential[lower_name: %s, user_id:%v]. Error: %w", remigrated.LowerName, remigrated.UserID, err) + } + if !has { + _, err = sess.Insert(remigrated) + if err != nil { + return fmt.Errorf("unable to (re)insert webauthn_credential[%d]. Error: %w", reg.ID, err) + } + + continue + } + } + + _, err = sess.ID(remigrated.ID).AllCols().Update(remigrated) + if err != nil { + return fmt.Errorf("unable to update webauthn_credential[%d]. Error: %w", reg.ID, err) + } + } + return sess.Commit() + }() + if err != nil { + return err + } + + if len(regs) < 50 { + break + } + start += 50 + regs = regs[:0] + } + + if x.Dialect().URI().DBType == schemas.POSTGRES { + if _, err := x.Exec("SELECT setval('webauthn_credential_id_seq', COALESCE((SELECT MAX(id)+1 FROM `webauthn_credential`), 1), false)"); err != nil { + return err + } + } + + return nil +} diff --git a/models/migrations/v210_test.go b/models/migrations/v210_test.go new file mode 100644 index 0000000000..70dbe61b06 --- /dev/null +++ b/models/migrations/v210_test.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "testing" + + "code.gitea.io/gitea/modules/timeutil" + + "github.com/stretchr/testify/assert" + "xorm.io/xorm/schemas" +) + +func Test_remigrateU2FCredentials(t *testing.T) { + // Create webauthnCredential table + type WebauthnCredential struct { + ID int64 `xorm:"pk autoincr"` + Name string + LowerName string `xorm:"unique(s)"` + UserID int64 `xorm:"INDEX unique(s)"` + CredentialID string `xorm:"INDEX VARCHAR(410)"` // CredentalID in U2F is at most 255bytes / 5 * 8 = 408 - add a few extra characters for safety + PublicKey []byte + AttestationType string + SignCount uint32 `xorm:"BIGINT"` + CloneWarning bool + } + + // Now migrate the old u2f registrations to the new format + type U2fRegistration struct { + ID int64 `xorm:"pk autoincr"` + Name string + UserID int64 `xorm:"INDEX"` + Raw []byte + Counter uint32 `xorm:"BIGINT"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` + } + + type ExpectedWebauthnCredential struct { + ID int64 `xorm:"pk autoincr"` + CredentialID string `xorm:"INDEX VARCHAR(410)"` // CredentalID in U2F is at most 255bytes / 5 * 8 = 408 - add a few extra characters for safety + } + + // Prepare and load the testing database + x, deferable := prepareTestEnv(t, 0, new(WebauthnCredential), new(U2fRegistration), new(ExpectedWebauthnCredential)) + if x == nil || t.Failed() { + defer deferable() + return + } + defer deferable() + + if x.Dialect().URI().DBType == schemas.SQLITE { + return + } + + // Run the migration + if err := remigrateU2FCredentials(x); err != nil { + assert.NoError(t, err) + return + } + + expected := []ExpectedWebauthnCredential{} + if err := x.Table("expected_webauthn_credential").Asc("id").Find(&expected); !assert.NoError(t, err) { + return + } + + got := []ExpectedWebauthnCredential{} + if err := x.Table("webauthn_credential").Select("id, credential_id").Asc("id").Find(&got); !assert.NoError(t, err) { + return + } + + assert.EqualValues(t, expected, got) +} diff --git a/models/notification.go b/models/notification.go index 8f5d9d01e6..b53d236e43 100644 --- a/models/notification.go +++ b/models/notification.go @@ -498,14 +498,15 @@ func (n *Notification) APIURL() string { type NotificationList []*Notification // LoadAttributes load Repo Issue User and Comment if not loaded -func (nl NotificationList) LoadAttributes() (err error) { +func (nl NotificationList) LoadAttributes() error { + var err error for i := 0; i < len(nl); i++ { err = nl[i].LoadAttributes() if err != nil && !IsErrCommentNotExist(err) { - return + return err } } - return + return nil } func (nl NotificationList) getPendingRepoIDs() []int64 { diff --git a/models/org_team.go b/models/org_team.go index bce4afb061..77acddc0e0 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -19,6 +19,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -49,22 +50,67 @@ func init() { db.RegisterModel(new(TeamUnit)) } -// SearchTeamOptions holds the search options -type SearchTeamOptions struct { +// SearchOrgTeamOptions holds the search options +type SearchOrgTeamOptions struct { db.ListOptions - UserID int64 Keyword string OrgID int64 IncludeDesc bool } +// GetUserTeamOptions holds the search options. +type GetUserTeamOptions struct { + db.ListOptions + UserID int64 +} + // SearchMembersOptions holds the search options type SearchMembersOptions struct { db.ListOptions } -// SearchTeam search for teams. Caller is responsible to check permissions. -func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) { +// GetUserTeams search for org teams. Caller is responsible to check permissions. +func GetUserTeams(opts *GetUserTeamOptions) ([]*Team, int64, error) { + if opts.Page <= 0 { + opts.Page = 1 + } + if opts.PageSize == 0 { + // Default limit + opts.PageSize = 10 + } + + sess := db.GetEngine(db.DefaultContext) + + sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id"). + And("team_user.uid=?", opts.UserID) + + count, err := sess. + Count(new(Team)) + if err != nil { + return nil, 0, err + } + + if opts.PageSize == -1 { + opts.PageSize = int(count) + } else { + sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) + } + + sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id"). + And("team_user.uid=?", opts.UserID) + + teams := make([]*Team, 0, opts.PageSize) + if err = sess. + OrderBy("lower_name"). + Find(&teams); err != nil { + return nil, 0, err + } + + return teams, count, nil +} + +// SearchOrgTeams search for org teams. Caller is responsible to check permissions. +func SearchOrgTeams(opts *SearchOrgTeamOptions) ([]*Team, int64, error) { if opts.Page <= 0 { opts.Page = 1 } @@ -196,7 +242,7 @@ func (t *Team) getRepositories(e db.Engine) error { } // GetRepositories returns paginated repositories in team of organization. -func (t *Team) GetRepositories(opts *SearchTeamOptions) error { +func (t *Team) GetRepositories(opts *SearchOrgTeamOptions) error { if opts.Page == 0 { return t.getRepositories(db.GetEngine(db.DefaultContext)) } @@ -716,7 +762,7 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) { // DeleteTeam deletes given team. // It's caller's responsibility to assign organization ID. func DeleteTeam(t *Team) error { - if err := t.GetRepositories(&SearchTeamOptions{}); err != nil { + if err := t.GetRepositories(&SearchOrgTeamOptions{}); err != nil { return err } @@ -731,8 +777,45 @@ func DeleteTeam(t *Team) error { return err } - if err := t.removeAllRepositories(ctx); err != nil { - return err + // update branch protections + { + protections := make([]*ProtectedBranch, 0, 10) + err := sess.In("repo_id", + builder.Select("id").From("repository").Where(builder.Eq{"owner_id": t.OrgID})). + Find(&protections) + if err != nil { + return fmt.Errorf("findProtectedBranches: %v", err) + } + for _, p := range protections { + var matched1, matched2, matched3 bool + if len(p.WhitelistTeamIDs) != 0 { + p.WhitelistTeamIDs, matched1 = util.RemoveIDFromList( + p.WhitelistTeamIDs, t.ID) + } + if len(p.ApprovalsWhitelistTeamIDs) != 0 { + p.ApprovalsWhitelistTeamIDs, matched2 = util.RemoveIDFromList( + p.ApprovalsWhitelistTeamIDs, t.ID) + } + if len(p.MergeWhitelistTeamIDs) != 0 { + p.MergeWhitelistTeamIDs, matched3 = util.RemoveIDFromList( + p.MergeWhitelistTeamIDs, t.ID) + } + if matched1 || matched2 || matched3 { + if _, err = sess.ID(p.ID).Cols( + "whitelist_team_i_ds", + "merge_whitelist_team_i_ds", + "approvals_whitelist_team_i_ds", + ).Update(p); err != nil { + return fmt.Errorf("updateProtectedBranches: %v", err) + } + } + } + } + + if !t.IncludesAllRepositories { + if err := t.removeAllRepositories(ctx); err != nil { + return err + } } // Delete team-user. @@ -857,11 +940,6 @@ func AddTeamMember(team *Team, userID int64) error { return err } - // Get team and its repositories. - if err := team.GetRepositories(&SearchTeamOptions{}); err != nil { - return err - } - ctx, committer, err := db.TxContext() if err != nil { return err @@ -883,17 +961,51 @@ func AddTeamMember(team *Team, userID int64) error { team.NumMembers++ // Give access to team repositories. - for _, repo := range team.Repos { - if err := recalculateUserAccess(ctx, repo, userID); err != nil { - return err - } - if setting.Service.AutoWatchNewRepos { - if err = repo_model.WatchRepoCtx(ctx, userID, repo.ID, true); err != nil { - return err + // update exist access if mode become bigger + subQuery := builder.Select("repo_id").From("team_repo"). + Where(builder.Eq{"team_id": team.ID}) + + if _, err := sess.Where("user_id=?", userID). + In("repo_id", subQuery). + And("mode < ?", team.AccessMode). + SetExpr("mode", team.AccessMode). + Update(new(Access)); err != nil { + return fmt.Errorf("update user accesses: %v", err) + } + + // for not exist access + var repoIDs []int64 + accessSubQuery := builder.Select("repo_id").From("access").Where(builder.Eq{"user_id": userID}) + if err := sess.SQL(subQuery.And(builder.NotIn("repo_id", accessSubQuery))).Find(&repoIDs); err != nil { + return fmt.Errorf("select id accesses: %v", err) + } + + accesses := make([]*Access, 0, 100) + for i, repoID := range repoIDs { + accesses = append(accesses, &Access{RepoID: repoID, UserID: userID, Mode: team.AccessMode}) + if (i%100 == 0 || i == len(repoIDs)-1) && len(accesses) > 0 { + if err = db.Insert(ctx, accesses); err != nil { + return fmt.Errorf("insert new user accesses: %v", err) } + accesses = accesses[:0] } } + // watch could be failed, so run it in a goroutine + if setting.Service.AutoWatchNewRepos { + // Get team and its repositories. + if err := team.GetRepositories(&SearchOrgTeamOptions{}); err != nil { + log.Error("getRepositories failed: %v", err) + } + go func(repos []*repo_model.Repository) { + for _, repo := range repos { + if err = repo_model.WatchRepoCtx(db.DefaultContext, userID, repo.ID, true); err != nil { + log.Error("watch repo failed: %v", err) + } + } + }(team.Repos) + } + return committer.Commit() } diff --git a/models/org_team_test.go b/models/org_team_test.go index aa62cc58e2..cf3a797991 100644 --- a/models/org_team_test.go +++ b/models/org_team_test.go @@ -46,7 +46,7 @@ func TestTeam_GetRepositories(t *testing.T) { test := func(teamID int64) { team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team) - assert.NoError(t, team.GetRepositories(&SearchTeamOptions{})) + assert.NoError(t, team.GetRepositories(&SearchOrgTeamOptions{})) assert.Len(t, team.Repos, team.NumRepos) for _, repo := range team.Repos { unittest.AssertExistsAndLoadBean(t, &TeamRepo{TeamID: teamID, RepoID: repo.ID}) @@ -292,7 +292,7 @@ func TestGetTeamMembers(t *testing.T) { func TestGetUserTeams(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(userID int64) { - teams, _, err := SearchTeam(&SearchTeamOptions{UserID: userID}) + teams, _, err := GetUserTeams(&GetUserTeamOptions{UserID: userID}) assert.NoError(t, err) for _, team := range teams { unittest.AssertExistsAndLoadBean(t, &TeamUser{TeamID: team.ID, UID: userID}) diff --git a/models/project_issue.go b/models/project_issue.go index c7735addcc..024ab914fa 100644 --- a/models/project_issue.go +++ b/models/project_issue.go @@ -150,6 +150,17 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U e := db.GetEngine(ctx) oldProjectID := issue.projectID(e) + // Only check if we add a new project and not remove it. + if newProjectID > 0 { + newProject, err := GetProjectByID(newProjectID) + if err != nil { + return err + } + if newProject.RepoID != issue.RepoID { + return fmt.Errorf("issue's repository is not the same as project's repository") + } + } + if _, err := e.Where("project_issue.issue_id=?", issue.ID).Delete(&ProjectIssue{}); err != nil { return err } diff --git a/models/pull.go b/models/pull.go index 243d40b1fa..cc25165ef7 100644 --- a/models/pull.go +++ b/models/pull.go @@ -222,22 +222,19 @@ func (pr *PullRequest) loadProtectedBranch(ctx context.Context) (err error) { } // GetDefaultMergeMessage returns default message used when merging pull request -func (pr *PullRequest) GetDefaultMergeMessage() string { +func (pr *PullRequest) GetDefaultMergeMessage() (string, error) { if pr.HeadRepo == nil { var err error pr.HeadRepo, err = repo_model.GetRepositoryByID(pr.HeadRepoID) if err != nil { - log.Error("GetRepositoryById[%d]: %v", pr.HeadRepoID, err) - return "" + return "", fmt.Errorf("GetRepositoryById[%d]: %v", pr.HeadRepoID, err) } } if err := pr.LoadIssue(); err != nil { - log.Error("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err) - return "" + return "", fmt.Errorf("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err) } if err := pr.LoadBaseRepo(); err != nil { - log.Error("LoadBaseRepo: %v", err) - return "" + return "", fmt.Errorf("LoadBaseRepo: %v", err) } issueReference := "#" @@ -246,10 +243,10 @@ func (pr *PullRequest) GetDefaultMergeMessage() string { } if pr.BaseRepoID == pr.HeadRepoID { - return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch) + return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), nil } - return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch) + return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch), nil } // ReviewCount represents a count of Reviews @@ -335,19 +332,17 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error { } // GetDefaultSquashMessage returns default message used when squash and merging pull request -func (pr *PullRequest) GetDefaultSquashMessage() string { +func (pr *PullRequest) GetDefaultSquashMessage() (string, error) { if err := pr.LoadIssue(); err != nil { - log.Error("LoadIssue: %v", err) - return "" + return "", fmt.Errorf("LoadIssue: %v", err) } if err := pr.LoadBaseRepo(); err != nil { - log.Error("LoadBaseRepo: %v", err) - return "" + return "", fmt.Errorf("LoadBaseRepo: %v", err) } if pr.BaseRepo.UnitEnabled(unit.TypeExternalTracker) { - return fmt.Sprintf("%s (!%d)", pr.Issue.Title, pr.Issue.Index) + return fmt.Sprintf("%s (!%d)", pr.Issue.Title, pr.Issue.Index), nil } - return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index) + return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index), nil } // GetGitRefName returns git ref for hidden pull request branch @@ -627,7 +622,7 @@ func (pr *PullRequest) IsWorkInProgress() bool { // HasWorkInProgressPrefix determines if the given PR title has a Work In Progress prefix func HasWorkInProgressPrefix(title string) bool { for _, prefix := range setting.Repository.PullRequest.WorkInProgressPrefixes { - if strings.HasPrefix(strings.ToUpper(title), prefix) { + if strings.HasPrefix(strings.ToUpper(title), strings.ToUpper(prefix)) { return true } } @@ -648,7 +643,7 @@ func (pr *PullRequest) GetWorkInProgressPrefix() string { } for _, prefix := range setting.Repository.PullRequest.WorkInProgressPrefixes { - if strings.HasPrefix(strings.ToUpper(pr.Issue.Title), prefix) { + if strings.HasPrefix(strings.ToUpper(pr.Issue.Title), strings.ToUpper(prefix)) { return pr.Issue.Title[0:len(prefix)] } } @@ -702,3 +697,14 @@ func (pr *PullRequest) GetHeadBranchHTMLURL() string { } return pr.HeadRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch) } + +// Mergeable returns if the pullrequest is mergeable. +func (pr *PullRequest) Mergeable() bool { + // If a pull request isn't mergable if it's: + // - Being conflict checked. + // - Has a conflict. + // - Received a error while being conflict checked. + // - Is a work-in-progress pull request. + return pr.Status != PullRequestStatusChecking && pr.Status != PullRequestStatusConflict && + pr.Status != PullRequestStatusError && !pr.IsWorkInProgress() +} diff --git a/models/pull_test.go b/models/pull_test.go index 2567984cc1..9098b61161 100644 --- a/models/pull_test.go +++ b/models/pull_test.go @@ -261,11 +261,15 @@ func TestPullRequest_GetDefaultMergeMessage_InternalTracker(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2}).(*PullRequest) - assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", pr.GetDefaultMergeMessage()) + msg, err := pr.GetDefaultMergeMessage() + assert.NoError(t, err) + assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", msg) pr.BaseRepoID = 1 pr.HeadRepoID = 2 - assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", pr.GetDefaultMergeMessage()) + msg, err = pr.GetDefaultMergeMessage() + assert.NoError(t, err) + assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", msg) } func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) { @@ -283,9 +287,13 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) { pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2, BaseRepo: baseRepo}).(*PullRequest) - assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", pr.GetDefaultMergeMessage()) + msg, err := pr.GetDefaultMergeMessage() + assert.NoError(t, err) + assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", msg) pr.BaseRepoID = 1 pr.HeadRepoID = 2 - assert.Equal(t, "Merge pull request 'issue3' (!3) from user2/repo1:branch2 into master", pr.GetDefaultMergeMessage()) + msg, err = pr.GetDefaultMergeMessage() + assert.NoError(t, err) + assert.Equal(t, "Merge pull request 'issue3' (!3) from user2/repo1:branch2 into master", msg) } diff --git a/models/repo.go b/models/repo.go index 83031c508c..29bb196e8e 100644 --- a/models/repo.go +++ b/models/repo.go @@ -132,7 +132,7 @@ func CheckRepoUnitUser(repo *repo_model.Repository, user *user_model.User, unitT } func checkRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool { - if user.IsAdmin { + if user != nil && user.IsAdmin { return true } perm, err := getUserRepoPermission(ctx, repo, user) @@ -150,27 +150,56 @@ func getRepoAssignees(ctx context.Context, repo *repo_model.Repository) (_ []*us } e := db.GetEngine(ctx) - accesses := make([]*Access, 0, 10) - if err = e. + userIDs := make([]int64, 0, 10) + if err = e.Table("access"). Where("repo_id = ? AND mode >= ?", repo.ID, perm.AccessModeWrite). - Find(&accesses); err != nil { + Select("user_id"). + Find(&userIDs); err != nil { return nil, err } + additionalUserIDs := make([]int64, 0, 10) + if err = e.Table("team_user"). + Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id"). + Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id"). + Where("`team_repo`.repo_id = ? AND `team_unit`.access_mode >= ?", repo.ID, perm.AccessModeWrite). + Distinct("`team_user`.uid"). + Select("`team_user`.uid"). + Find(&additionalUserIDs); err != nil { + return nil, err + } + + uidMap := map[int64]bool{} + i := 0 + for _, uid := range userIDs { + if uidMap[uid] { + continue + } + uidMap[uid] = true + userIDs[i] = uid + i++ + } + userIDs = userIDs[:i] + userIDs = append(userIDs, additionalUserIDs...) + + for _, uid := range additionalUserIDs { + if uidMap[uid] { + continue + } + userIDs[i] = uid + i++ + } + userIDs = userIDs[:i] + // Leave a seat for owner itself to append later, but if owner is an organization // and just waste 1 unit is cheaper than re-allocate memory once. - users := make([]*user_model.User, 0, len(accesses)+1) - if len(accesses) > 0 { - userIDs := make([]int64, len(accesses)) - for i := 0; i < len(accesses); i++ { - userIDs[i] = accesses[i].UserID - } - + users := make([]*user_model.User, 0, len(userIDs)+1) + if len(userIDs) > 0 { if err = e.In("id", userIDs).Find(&users); err != nil { return nil, err } } - if !repo.Owner.IsOrganization() { + if !repo.Owner.IsOrganization() && !uidMap[repo.OwnerID] { users = append(users, repo.Owner) } @@ -948,7 +977,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { // Remove attachment with no issue_id and release_id. for i := range newAttachmentPaths { - admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", attachmentPaths[i]) + admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", newAttachmentPaths[i]) } if len(repo.Avatar) > 0 { diff --git a/models/repo/mirror.go b/models/repo/mirror.go index bdb449af3a..e329dc8693 100644 --- a/models/repo/mirror.go +++ b/models/repo/mirror.go @@ -6,6 +6,7 @@ package repo import ( + "context" "errors" "fmt" "time" @@ -115,6 +116,13 @@ func UpdateMirror(m *Mirror) error { return updateMirror(db.GetEngine(db.DefaultContext), m) } +// TouchMirror updates the mirror updatedUnix +func TouchMirror(ctx context.Context, m *Mirror) error { + m.UpdatedUnix = timeutil.TimeStampNow() + _, err := db.GetEngine(ctx).ID(m.ID).Cols("updated_unix").Update(m) + return err +} + // DeleteMirrorByRepoID deletes a mirror by repoID func DeleteMirrorByRepoID(repoID int64) error { _, err := db.GetEngine(db.DefaultContext).Delete(&Mirror{RepoID: repoID}) diff --git a/models/repo_list.go b/models/repo_list.go index 9cb7a163fc..a8bff15520 100644 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -233,14 +233,28 @@ func teamUnitsRepoCond(id string, userID, orgID, teamID int64, units ...unit.Typ builder.Select("repo_id").From("team_repo").Where( builder.Eq{ "team_id": teamID, - }.And( + }.And(builder.Or( + // Check if the user is member of the team. builder.In( "team_id", builder.Select("team_id").From("team_user").Where( builder.Eq{ "uid": userID, }, ), - )).And( + ), + // Check if the user is in the owner team of the organisation. + builder.Exists(builder.Select("team_id").From("team_user"). + Where(builder.Eq{ + "org_id": orgID, + "team_id": builder.Select("id").From("team").Where( + builder.Eq{ + "org_id": orgID, + "lower_name": strings.ToLower(ownerTeamName), + }), + "uid": userID, + }), + ), + )).And( builder.In( "team_id", builder.Select("team_id").From("team_unit").Where( builder.Eq{ diff --git a/models/repo_test.go b/models/repo_test.go index c0790e532d..ea250be976 100644 --- a/models/repo_test.go +++ b/models/repo_test.go @@ -167,3 +167,21 @@ func TestLinkedRepository(t *testing.T) { }) } } + +func TestRepoAssignees(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + users, err := GetRepoAssignees(repo2) + assert.NoError(t, err) + assert.Len(t, users, 1) + assert.Equal(t, users[0].ID, int64(2)) + + repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21}).(*repo_model.Repository) + users, err = GetRepoAssignees(repo21) + assert.NoError(t, err) + assert.Len(t, users, 3) + assert.Equal(t, users[0].ID, int64(15)) + assert.Equal(t, users[1].ID, int64(18)) + assert.Equal(t, users[2].ID, int64(16)) +} diff --git a/models/unit/unit.go b/models/unit/unit.go index eb71276786..a6a47eb1f3 100644 --- a/models/unit/unit.go +++ b/models/unit/unit.go @@ -328,7 +328,12 @@ func AllUnitKeyNames() []string { // MinUnitAccessMode returns the minial permission of the permission map func MinUnitAccessMode(unitsMap map[Type]perm.AccessMode) perm.AccessMode { res := perm.AccessModeNone - for _, mode := range unitsMap { + for t, mode := range unitsMap { + // Don't allow `TypeExternal{Tracker,Wiki}` to influence this as they can only be set to READ perms. + if t == TypeExternalTracker || t == TypeExternalWiki { + continue + } + // get the minial permission great than AccessModeNone except all are AccessModeNone if mode > perm.AccessModeNone && (res == perm.AccessModeNone || mode < res) { res = mode diff --git a/models/unittest/consistency.go b/models/unittest/consistency.go index 2645084d3e..af05348868 100644 --- a/models/unittest/consistency.go +++ b/models/unittest/consistency.go @@ -175,8 +175,10 @@ func init() { checkForActionConsistency := func(t assert.TestingT, bean interface{}) { action := reflectionWrap(bean) - repoRow := AssertExistsAndLoadMap(t, "repository", builder.Eq{"id": action.int("RepoID")}) - assert.Equal(t, parseBool(repoRow["is_private"]), action.bool("IsPrivate"), "action: %+v", action) + if action.int("RepoID") != 1700 { // dangling intentional + repoRow := AssertExistsAndLoadMap(t, "repository", builder.Eq{"id": action.int("RepoID")}) + assert.Equal(t, parseBool(repoRow["is_private"]), action.bool("IsPrivate"), "action: %+v", action) + } } consistencyCheckMap["user"] = checkForUserConsistency diff --git a/models/user.go b/models/user.go index 5f7bedd36d..51ee740c8d 100644 --- a/models/user.go +++ b/models/user.go @@ -13,11 +13,13 @@ import ( _ "image/jpeg" // Needed for jpeg support asymkey_model "code.gitea.io/gitea/models/asymkey" + auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -82,6 +84,11 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { } // ***** END: Follow ***** + if _, err := db.GetEngine(ctx).In("grant_id", builder.Select("id").From("oauth2_grant").Where(builder.Eq{"oauth2_grant.user_id": u.ID})). + Delete(&auth_model.OAuth2AuthorizationCode{}); err != nil { + return err + } + if err = deleteBeans(e, &AccessToken{UID: u.ID}, &Collaboration{UserID: u.ID}, @@ -99,6 +106,8 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { &Collaboration{UserID: u.ID}, &Stopwatch{UserID: u.ID}, &user_model.Setting{UserID: u.ID}, + &auth_model.OAuth2Application{UID: u.ID}, + &auth_model.OAuth2Grant{UserID: u.ID}, ); err != nil { return fmt.Errorf("deleteBeans: %v", err) } @@ -130,6 +139,50 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { } } + // ***** START: Branch Protections ***** + { + const batchSize = 50 + for start := 0; ; start += batchSize { + protections := make([]*ProtectedBranch, 0, batchSize) + // @perf: We can't filter on DB side by u.ID, as those IDs are serialized as JSON strings. + // We could filter down with `WHERE repo_id IN (reposWithPushPermission(u))`, + // though that query will be quite complex and tricky to maintain (compare `getRepoAssignees()`). + // Also, as we didn't update branch protections when removing entries from `access` table, + // it's safer to iterate all protected branches. + if err = e.Limit(batchSize, start).Find(&protections); err != nil { + return fmt.Errorf("findProtectedBranches: %v", err) + } + if len(protections) == 0 { + break + } + for _, p := range protections { + var matched1, matched2, matched3 bool + if len(p.WhitelistUserIDs) != 0 { + p.WhitelistUserIDs, matched1 = util.RemoveIDFromList( + p.WhitelistUserIDs, u.ID) + } + if len(p.ApprovalsWhitelistUserIDs) != 0 { + p.ApprovalsWhitelistUserIDs, matched2 = util.RemoveIDFromList( + p.ApprovalsWhitelistUserIDs, u.ID) + } + if len(p.MergeWhitelistUserIDs) != 0 { + p.MergeWhitelistUserIDs, matched3 = util.RemoveIDFromList( + p.MergeWhitelistUserIDs, u.ID) + } + if matched1 || matched2 || matched3 { + if _, err = e.ID(p.ID).Cols( + "whitelist_user_i_ds", + "merge_whitelist_user_i_ds", + "approvals_whitelist_user_i_ds", + ).Update(p); err != nil { + return fmt.Errorf("updateProtectedBranches: %v", err) + } + } + } + } + } + // ***** END: Branch Protections ***** + // ***** START: PublicKey ***** if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil { return fmt.Errorf("deletePublicKeys: %v", err) diff --git a/models/user/email_address.go b/models/user/email_address.go index 0ff62fb6a8..564d018dac 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "net/mail" + "regexp" "strings" "code.gitea.io/gitea/models/db" @@ -21,10 +22,23 @@ import ( "xorm.io/builder" ) -var ( - // ErrEmailNotActivated e-mail address has not been activated error - ErrEmailNotActivated = errors.New("E-mail address has not been activated") -) +// ErrEmailNotActivated e-mail address has not been activated error +var ErrEmailNotActivated = errors.New("e-mail address has not been activated") + +// ErrEmailCharIsNotSupported e-mail address contains unsupported character +type ErrEmailCharIsNotSupported struct { + Email string +} + +// IsErrEmailCharIsNotSupported checks if an error is an ErrEmailCharIsNotSupported +func IsErrEmailCharIsNotSupported(err error) bool { + _, ok := err.(ErrEmailCharIsNotSupported) + return ok +} + +func (err ErrEmailCharIsNotSupported) Error() string { + return fmt.Sprintf("e-mail address contains unsupported character [email: %s]", err.Email) +} // ErrEmailInvalid represents an error where the email address does not comply with RFC 5322 type ErrEmailInvalid struct { @@ -108,12 +122,24 @@ func (email *EmailAddress) BeforeInsert() { } } +var emailRegexp = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$") + // ValidateEmail check if email is a allowed address func ValidateEmail(email string) error { if len(email) == 0 { return nil } + if !emailRegexp.MatchString(email) { + return ErrEmailCharIsNotSupported{email} + } + + if !(email[0] >= 'a' && email[0] <= 'z') && + !(email[0] >= 'A' && email[0] <= 'Z') && + !(email[0] >= '0' && email[0] <= '9') { + return ErrEmailInvalid{email} + } + if _, err := mail.ParseAddress(email); err != nil { return ErrEmailInvalid{email} } diff --git a/models/user/email_address_test.go b/models/user/email_address_test.go index 4a539e150a..7eeb469b26 100644 --- a/models/user/email_address_test.go +++ b/models/user/email_address_test.go @@ -252,3 +252,58 @@ func TestListEmails(t *testing.T) { assert.Len(t, emails, 5) assert.Greater(t, count, int64(len(emails))) } + +func TestEmailAddressValidate(t *testing.T) { + kases := map[string]error{ + "abc@gmail.com": nil, + "132@hotmail.com": nil, + "1-3-2@test.org": nil, + "1.3.2@test.org": nil, + "a_123@test.org.cn": nil, + `first.last@iana.org`: nil, + `first!last@iana.org`: nil, + `first#last@iana.org`: nil, + `first$last@iana.org`: nil, + `first%last@iana.org`: nil, + `first&last@iana.org`: nil, + `first'last@iana.org`: nil, + `first*last@iana.org`: nil, + `first+last@iana.org`: nil, + `first/last@iana.org`: nil, + `first=last@iana.org`: nil, + `first?last@iana.org`: nil, + `first^last@iana.org`: nil, + "first`last@iana.org": nil, + `first{last@iana.org`: nil, + `first|last@iana.org`: nil, + `first}last@iana.org`: nil, + `first~last@iana.org`: nil, + `first;last@iana.org`: ErrEmailCharIsNotSupported{`first;last@iana.org`}, + ".233@qq.com": ErrEmailInvalid{".233@qq.com"}, + "!233@qq.com": ErrEmailInvalid{"!233@qq.com"}, + "#233@qq.com": ErrEmailInvalid{"#233@qq.com"}, + "$233@qq.com": ErrEmailInvalid{"$233@qq.com"}, + "%233@qq.com": ErrEmailInvalid{"%233@qq.com"}, + "&233@qq.com": ErrEmailInvalid{"&233@qq.com"}, + "'233@qq.com": ErrEmailInvalid{"'233@qq.com"}, + "*233@qq.com": ErrEmailInvalid{"*233@qq.com"}, + "+233@qq.com": ErrEmailInvalid{"+233@qq.com"}, + "/233@qq.com": ErrEmailInvalid{"/233@qq.com"}, + "=233@qq.com": ErrEmailInvalid{"=233@qq.com"}, + "?233@qq.com": ErrEmailInvalid{"?233@qq.com"}, + "^233@qq.com": ErrEmailInvalid{"^233@qq.com"}, + "`233@qq.com": ErrEmailInvalid{"`233@qq.com"}, + "{233@qq.com": ErrEmailInvalid{"{233@qq.com"}, + "|233@qq.com": ErrEmailInvalid{"|233@qq.com"}, + "}233@qq.com": ErrEmailInvalid{"}233@qq.com"}, + "~233@qq.com": ErrEmailInvalid{"~233@qq.com"}, + ";233@qq.com": ErrEmailCharIsNotSupported{";233@qq.com"}, + "Foo ": ErrEmailCharIsNotSupported{"Foo "}, + string([]byte{0xE2, 0x84, 0xAA}): ErrEmailCharIsNotSupported{string([]byte{0xE2, 0x84, 0xAA})}, + } + for kase, err := range kases { + t.Run(kase, func(t *testing.T) { + assert.EqualValues(t, err, ValidateEmail(kase)) + }) + } +} diff --git a/models/user/external_login_user.go b/models/user/external_login_user.go index 8cf7c652b1..d1abe292f5 100644 --- a/models/user/external_login_user.go +++ b/models/user/external_login_user.go @@ -60,7 +60,7 @@ type ExternalLoginUser struct { LastName string NickName string Description string - AvatarURL string + AvatarURL string `xorm:"TEXT"` Location string AccessToken string `xorm:"TEXT"` AccessTokenSecret string `xorm:"TEXT"` diff --git a/models/user/list.go b/models/user/list.go index 13138b3e50..06ec511375 100644 --- a/models/user/list.go +++ b/models/user/list.go @@ -30,13 +30,19 @@ func (users UserList) GetTwoFaStatus() map[int64]bool { for _, user := range users { results[user.ID] = false // Set default to false } - tokenMaps, err := users.loadTwoFactorStatus(db.GetEngine(db.DefaultContext)) - if err == nil { + + if tokenMaps, err := users.loadTwoFactorStatus(db.GetEngine(db.DefaultContext)); err == nil { for _, token := range tokenMaps { results[token.UID] = true } } + if ids, err := users.userIDsWithWebAuthn(db.GetEngine(db.DefaultContext)); err == nil { + for _, id := range ids { + results[id] = true + } + } + return results } @@ -47,15 +53,23 @@ func (users UserList) loadTwoFactorStatus(e db.Engine) (map[int64]*auth.TwoFacto userIDs := users.GetUserIDs() tokenMaps := make(map[int64]*auth.TwoFactor, len(userIDs)) - err := e. - In("uid", userIDs). - Find(&tokenMaps) - if err != nil { + if err := e.In("uid", userIDs).Find(&tokenMaps); err != nil { return nil, fmt.Errorf("find two factor: %v", err) } return tokenMaps, nil } +func (users UserList) userIDsWithWebAuthn(e db.Engine) ([]int64, error) { + if len(users) == 0 { + return nil, nil + } + ids := make([]int64, 0, len(users)) + if err := e.Table(new(auth.WebAuthnCredential)).In("user_id", users.GetUserIDs()).Select("user_id").Distinct("user_id").Find(&ids); err != nil { + return nil, fmt.Errorf("find two factor: %v", err) + } + return ids, nil +} + // GetUsersByIDs returns all resolved users from a list of Ids. func GetUsersByIDs(ids []int64) (UserList, error) { ous := make([]*User, 0, len(ids)) diff --git a/models/user/search.go b/models/user/search.go index fac180529f..a81cee1c22 100644 --- a/models/user/search.go +++ b/models/user/search.go @@ -20,6 +20,7 @@ import ( // SearchUserOptions contains the options for searching type SearchUserOptions struct { db.ListOptions + Keyword string Type UserType UID int64 @@ -33,6 +34,8 @@ type SearchUserOptions struct { IsRestricted util.OptionalBool IsTwoFactorEnabled util.OptionalBool IsProhibitLogin util.OptionalBool + + ExtraParamStrings map[string]string } func (opts *SearchUserOptions) toSearchQueryBase() *xorm.Session { diff --git a/models/user/user.go b/models/user/user.go index 57a7fcadfa..7e7657070a 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -316,37 +316,45 @@ func (u *User) GenerateEmailActivateCode(email string) string { } // GetUserFollowers returns range of user's followers. -func GetUserFollowers(u *User, listOptions db.ListOptions) ([]*User, error) { - sess := db.GetEngine(db.DefaultContext). +func GetUserFollowers(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) { + sess := db.GetEngine(ctx). + Select("`user`.*"). + Join("LEFT", "follow", "`user`.id=follow.user_id"). Where("follow.follow_id=?", u.ID). - Join("LEFT", "follow", "`user`.id=follow.user_id") + And(isUserVisibleToViewerCond(viewer)) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) users := make([]*User, 0, listOptions.PageSize) - return users, sess.Find(&users) + count, err := sess.FindAndCount(&users) + return users, count, err } users := make([]*User, 0, 8) - return users, sess.Find(&users) + count, err := sess.FindAndCount(&users) + return users, count, err } // GetUserFollowing returns range of user's following. -func GetUserFollowing(u *User, listOptions db.ListOptions) ([]*User, error) { +func GetUserFollowing(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) { sess := db.GetEngine(db.DefaultContext). + Select("`user`.*"). + Join("LEFT", "follow", "`user`.id=follow.follow_id"). Where("follow.user_id=?", u.ID). - Join("LEFT", "follow", "`user`.id=follow.follow_id") + And(isUserVisibleToViewerCond(viewer)) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) users := make([]*User, 0, listOptions.PageSize) - return users, sess.Find(&users) + count, err := sess.FindAndCount(&users) + return users, count, err } users := make([]*User, 0, 8) - return users, sess.Find(&users) + count, err := sess.FindAndCount(&users) + return users, count, err } // NewGitSig generates and returns the signature of given user. @@ -622,7 +630,14 @@ func IsUsableUsername(name string) error { // CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation type CreateUserOverwriteOptions struct { - Visibility structs.VisibleType + KeepEmailPrivate util.OptionalBool + Visibility *structs.VisibleType + AllowCreateOrganization util.OptionalBool + EmailNotificationsPreference *string + MaxRepoCreation *int + Theme *string + IsRestricted util.OptionalBool + IsActive util.OptionalBool } // CreateUser creates record of a new user. @@ -638,10 +653,45 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification u.MaxRepoCreation = -1 u.Theme = setting.UI.DefaultTheme + u.IsRestricted = setting.Service.DefaultUserIsRestricted + u.IsActive = !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm) // overwrite defaults if set if len(overwriteDefault) != 0 && overwriteDefault[0] != nil { - u.Visibility = overwriteDefault[0].Visibility + overwrite := overwriteDefault[0] + if !overwrite.KeepEmailPrivate.IsNone() { + u.KeepEmailPrivate = overwrite.KeepEmailPrivate.IsTrue() + } + if overwrite.Visibility != nil { + u.Visibility = *overwrite.Visibility + } + if !overwrite.AllowCreateOrganization.IsNone() { + u.AllowCreateOrganization = overwrite.AllowCreateOrganization.IsTrue() + } + if overwrite.EmailNotificationsPreference != nil { + u.EmailNotificationsPreference = *overwrite.EmailNotificationsPreference + } + if overwrite.MaxRepoCreation != nil { + u.MaxRepoCreation = *overwrite.MaxRepoCreation + } + if overwrite.Theme != nil { + u.Theme = *overwrite.Theme + } + if !overwrite.IsRestricted.IsNone() { + u.IsRestricted = overwrite.IsRestricted.IsTrue() + } + if !overwrite.IsActive.IsNone() { + u.IsActive = overwrite.IsActive.IsTrue() + } + } + + // validate data + if err := validateUser(u); err != nil { + return err + } + + if err := ValidateEmail(u.Email); err != nil { + return err } ctx, committer, err := db.TxContext() @@ -652,11 +702,6 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e sess := db.GetEngine(ctx) - // validate data - if err := validateUser(u); err != nil { - return err - } - isExist, err := isUserExist(sess, 0, u.Name) if err != nil { return err @@ -827,8 +872,9 @@ func validateUser(u *User) error { return ValidateEmail(u.Email) } -func updateUser(ctx context.Context, u *User, changePrimaryEmail bool) error { - if err := validateUser(u); err != nil { +func updateUser(ctx context.Context, u *User, changePrimaryEmail bool, cols ...string) error { + err := validateUser(u) + if err != nil { return err } @@ -860,15 +906,35 @@ func updateUser(ctx context.Context, u *User, changePrimaryEmail bool) error { }); err != nil { return err } + } else if !u.IsOrganization() { // check if primary email in email_address table + primaryEmailExist, err := e.Where("uid=? AND is_primary=?", u.ID, true).Exist(&EmailAddress{}) + if err != nil { + return err + } + + if !primaryEmailExist { + if _, err = e.Insert(&EmailAddress{ + Email: u.Email, + UID: u.ID, + IsActivated: true, + IsPrimary: true, + }); err != nil { + return err + } + } } - _, err := e.ID(u.ID).AllCols().Update(u) + if len(cols) == 0 { + _, err = e.ID(u.ID).AllCols().Update(u) + } else { + _, err = e.ID(u.ID).Cols(cols...).Update(u) + } return err } // UpdateUser updates user's information. -func UpdateUser(u *User, emailChanged bool) error { - return updateUser(db.DefaultContext, u, emailChanged) +func UpdateUser(u *User, emailChanged bool, cols ...string) error { + return updateUser(db.DefaultContext, u, emailChanged, cols...) } // UpdateUserCols update user according special columns @@ -1104,19 +1170,9 @@ func GetUserByEmailContext(ctx context.Context, email string) (*User, error) { } email = strings.ToLower(email) - // First try to find the user by primary email - user := &User{Email: email} - has, err := db.GetEngine(ctx).Get(user) - if err != nil { - return nil, err - } - if has { - return user, nil - } - // Otherwise, check in alternative list for activated email addresses - emailAddress := &EmailAddress{Email: email, IsActivated: true} - has, err = db.GetEngine(ctx).Get(emailAddress) + emailAddress := &EmailAddress{LowerEmail: email, IsActivated: true} + has, err := db.GetEngine(ctx).Get(emailAddress) if err != nil { return nil, err } @@ -1183,3 +1239,36 @@ func GetAdminUser() (*User, error) { return &admin, nil } + +func isUserVisibleToViewerCond(viewer *User) builder.Cond { + if viewer != nil && viewer.IsAdmin { + return builder.NewCond() + } + + if viewer == nil || viewer.IsRestricted { + return builder.Eq{ + "`user`.visibility": structs.VisibleTypePublic, + } + } + + return builder.Neq{ + "`user`.visibility": structs.VisibleTypePrivate, + }.Or( + builder.In("`user`.id", + builder. + Select("`follow`.user_id"). + From("follow"). + Where(builder.Eq{"`follow`.follow_id": viewer.ID})), + builder.In("`user`.id", + builder. + Select("`team_user`.uid"). + From("team_user"). + Join("INNER", "`team_user` AS t2", "`team_user`.id = `t2`.id"). + Where(builder.Eq{"`t2`.uid": viewer.ID})), + builder.In("`user`.id", + builder. + Select("`team_user`.uid"). + From("team_user"). + Join("INNER", "`team_user` AS t2", "`team_user`.org_id = `t2`.org_id"). + Where(builder.Eq{"`t2`.uid": viewer.ID}))) +} diff --git a/models/user/user_test.go b/models/user/user_test.go index 70591c8c12..335537aa13 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -232,7 +232,21 @@ func TestCreateUserInvalidEmail(t *testing.T) { err := CreateUser(user) assert.Error(t, err) - assert.True(t, IsErrEmailInvalid(err)) + assert.True(t, IsErrEmailCharIsNotSupported(err)) +} + +func TestCreateUserEmailAlreadyUsed(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) + + // add new user with user2's email + user.Name = "testuser" + user.LowerName = strings.ToLower(user.Name) + user.ID = 0 + err := CreateUser(user) + assert.Error(t, err) + assert.True(t, IsErrEmailAlreadyUsed(err)) } func TestGetUserIDsByNames(t *testing.T) { diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index 21c01d9289..0c62d927b2 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -497,14 +497,19 @@ func GetSystemOrDefaultWebhook(id int64) (*Webhook, error) { } // GetSystemWebhooks returns all admin system webhooks. -func GetSystemWebhooks() ([]*Webhook, error) { - return getSystemWebhooks(db.GetEngine(db.DefaultContext)) +func GetSystemWebhooks(isActive util.OptionalBool) ([]*Webhook, error) { + return getSystemWebhooks(db.GetEngine(db.DefaultContext), isActive) } -func getSystemWebhooks(e db.Engine) ([]*Webhook, error) { +func getSystemWebhooks(e db.Engine, isActive util.OptionalBool) ([]*Webhook, error) { webhooks := make([]*Webhook, 0, 5) + if isActive.IsNone() { + return webhooks, e. + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true). + Find(&webhooks) + } return webhooks, e. - Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true). + Where("repo_id=? AND org_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.IsTrue()). Find(&webhooks) } diff --git a/modules/auth/pam/pam.go b/modules/auth/pam/pam.go index 73ecae0c2c..08558fad99 100644 --- a/modules/auth/pam/pam.go +++ b/modules/auth/pam/pam.go @@ -35,6 +35,10 @@ func Auth(serviceName, userName, passwd string) (string, error) { if err = t.Authenticate(0); err != nil { return "", err } + + if err = t.AcctMgmt(0); err != nil { + return "", err + } // PAM login names might suffer transformations in the PAM stack. // We should take whatever the PAM stack returns for it. diff --git a/modules/charset/charset.go b/modules/charset/charset.go index ae5cf5aa1a..a6234a4ae5 100644 --- a/modules/charset/charset.go +++ b/modules/charset/charset.go @@ -131,7 +131,26 @@ func RemoveBOMIfPresent(content []byte) []byte { // DetectEncoding detect the encoding of content func DetectEncoding(content []byte) (string, error) { - if utf8.Valid(content) { + // First we check if the content represents valid utf8 content excepting a truncated character at the end. + + // Now we could decode all the runes in turn but this is not necessarily the cheapest thing to do + // instead we walk backwards from the end to trim off a the incomplete character + toValidate := content + end := len(toValidate) - 1 + + if end < 0 { + // no-op + } else if toValidate[end]>>5 == 0b110 { + // Incomplete 1 byte extension e.g. Ā© which has been truncated to + toValidate = toValidate[:end] + } else if end > 0 && toValidate[end]>>6 == 0b10 && toValidate[end-1]>>4 == 0b1110 { + // Incomplete 2 byte extension e.g. ā›” <9b><94> which has been truncated to <9b> + toValidate = toValidate[:end-1] + } else if end > 1 && toValidate[end]>>6 == 0b10 && toValidate[end-1]>>6 == 0b10 && toValidate[end-2]>>3 == 0b11110 { + // Incomplete 3 byte extension e.g. šŸ’© <9f><92> which has been truncated to <9f><92> + toValidate = toValidate[:end-2] + } + if utf8.Valid(toValidate) { log.Debug("Detected encoding: utf-8 (fast)") return "UTF-8", nil } diff --git a/modules/charset/charset_test.go b/modules/charset/charset_test.go index 8957bf3c1c..31b4c8b944 100644 --- a/modules/charset/charset_test.go +++ b/modules/charset/charset_test.go @@ -5,6 +5,8 @@ package charset import ( + "bytes" + "io" "strings" "testing" @@ -272,3 +274,145 @@ func stringMustEndWith(t *testing.T, expected, value string) { func bytesMustStartWith(t *testing.T, expected, value []byte) { assert.Equal(t, expected, value[:len(expected)]) } + +func TestToUTF8WithFallbackReader(t *testing.T) { + resetDefaultCharsetsOrder() + + for testLen := 0; testLen < 2048; testLen++ { + pattern := " test { () }\n" + input := "" + for len(input) < testLen { + input += pattern + } + input = input[:testLen] + input += "// Š’Ń‹ŠŗŠ»ŃŽŃ‡Š°ŠµŠ¼" + rd := ToUTF8WithFallbackReader(bytes.NewReader([]byte(input))) + r, _ := io.ReadAll(rd) + assert.EqualValuesf(t, input, string(r), "testing string len=%d", testLen) + } + + truncatedOneByteExtension := failFastBytes + encoding, _ := DetectEncoding(truncatedOneByteExtension) + assert.Equal(t, "UTF-8", encoding) + + truncatedTwoByteExtension := failFastBytes + truncatedTwoByteExtension[len(failFastBytes)-1] = 0x9b + truncatedTwoByteExtension[len(failFastBytes)-2] = 0xe2 + + encoding, _ = DetectEncoding(truncatedTwoByteExtension) + assert.Equal(t, "UTF-8", encoding) + + truncatedThreeByteExtension := failFastBytes + truncatedThreeByteExtension[len(failFastBytes)-1] = 0x92 + truncatedThreeByteExtension[len(failFastBytes)-2] = 0x9f + truncatedThreeByteExtension[len(failFastBytes)-3] = 0xf0 + + encoding, _ = DetectEncoding(truncatedThreeByteExtension) + assert.Equal(t, "UTF-8", encoding) +} + +var failFastBytes = []byte{ + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x74, 0x6f, + 0x6f, 0x6c, 0x73, 0x2e, 0x61, 0x6e, 0x74, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x64, 0x65, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4f, 0x73, 0x0a, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x72, 0x67, + 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x62, 0x6f, 0x6f, + 0x74, 0x2e, 0x67, 0x72, 0x61, 0x64, 0x6c, 0x65, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x72, 0x75, 0x6e, 0x2e, 0x42, + 0x6f, 0x6f, 0x74, 0x52, 0x75, 0x6e, 0x0a, 0x0a, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x64, 0x28, 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, + 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x22, 0x29, 0x0a, 0x7d, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x65, + 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x22, 0x3a, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x61, 0x70, 0x69, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x28, 0x22, 0x3a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x61, 0x70, 0x69, 0x2d, 0x64, 0x6f, 0x63, 0x73, 0x22, 0x29, + 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x22, 0x3a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x64, 0x62, + 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x22, 0x3a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x22, 0x3a, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x66, + 0x73, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x22, 0x3a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x3a, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x71, 0x22, 0x29, 0x29, 0x0a, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, + 0x6a, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x65, 0x3a, 0x70, 0x65, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2d, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x65, 0x72, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6a, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x65, 0x3a, 0x70, 0x65, 0x2d, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2d, 0x68, 0x61, 0x6c, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6a, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x2e, + 0x70, 0x65, 0x3a, 0x70, 0x65, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x29, 0x0a, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, + 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x3a, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x6f, 0x6f, 0x74, 0x2d, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x65, 0x72, 0x2d, 0x77, 0x65, 0x62, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, + 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x3a, 0x73, 0x70, 0x72, + 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x6f, 0x6f, 0x74, 0x2d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x72, 0x2d, 0x61, 0x6f, 0x70, + 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, + 0x72, 0x6b, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x3a, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x6f, 0x6f, 0x74, 0x2d, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x72, 0x2d, 0x61, 0x63, 0x74, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x29, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6f, + 0x72, 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x65, 0x72, 0x2d, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x22, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6f, 0x72, + 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x3a, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x65, 0x72, 0x2d, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2d, 0x61, 0x6c, 0x6c, 0x22, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6f, 0x72, + 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x3a, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x6c, 0x65, 0x75, 0x74, 0x68, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x70, + 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x72, 0x65, 0x74, 0x72, 0x79, 0x3a, + 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x72, 0x65, 0x74, 0x72, 0x79, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x63, 0x68, 0x2e, 0x71, + 0x6f, 0x73, 0x2e, 0x6c, 0x6f, 0x67, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x6c, 0x6f, 0x67, 0x62, 0x61, 0x63, 0x6b, 0x2d, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x69, 0x63, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x3a, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x79, 0x2d, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6b, 0x6f, 0x74, + 0x6c, 0x69, 0x6e, 0x28, 0x22, 0x73, 0x74, 0x64, 0x6c, 0x69, 0x62, 0x22, 0x29, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x65, 0x73, 0x74, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6a, + 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x65, 0x3a, 0x70, 0x65, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2d, + 0x74, 0x65, 0x73, 0x74, 0x22, 0x29, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x20, 0x70, 0x61, 0x74, 0x63, 0x68, 0x4a, + 0x61, 0x72, 0x20, 0x62, 0x79, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x28, 0x4a, 0x61, 0x72, 0x3a, 0x3a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2e, + 0x73, 0x65, 0x74, 0x28, 0x22, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x6c, 0x20, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x70, 0x61, 0x74, 0x68, + 0x20, 0x62, 0x79, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x67, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x73, 0x28, 0x22, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x2d, 0x50, 0x61, 0x74, 0x68, 0x22, 0x20, 0x74, 0x6f, 0x20, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, + 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x3d, + 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2b, 0x22, 0x2e, 0x74, 0x6f, 0x52, 0x65, 0x67, 0x65, 0x78, 0x28, 0x29, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, + 0x65, 0x20, 0x66, 0x75, 0x6e, 0x20, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x3a, 0x20, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x70, + 0x61, 0x74, 0x68, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x28, 0x22, 0x20, 0x22, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x74, 0x2e, 0x74, 0x6f, 0x55, 0x52, 0x49, 0x28, 0x29, 0x2e, 0x74, 0x6f, 0x55, + 0x52, 0x4c, 0x28, 0x29, 0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x2e, 0x72, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x46, 0x69, 0x72, 0x73, 0x74, 0x28, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x2c, 0x20, 0x22, 0x2f, + 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x3c, 0x42, 0x6f, 0x6f, 0x74, 0x52, 0x75, 0x6e, 0x3e, 0x28, 0x22, 0x62, + 0x6f, 0x6f, 0x74, 0x52, 0x75, 0x6e, 0x22, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x4f, + 0x73, 0x2e, 0x69, 0x73, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x28, 0x4f, 0x73, 0x2e, 0x46, 0x41, 0x4d, 0x49, 0x4c, 0x59, + 0x5f, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x29, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x28, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x74, 0x73, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x28, 0x22, 0x6d, 0x61, 0x69, + 0x6e, 0x22, 0x29, 0x2e, 0x6d, 0x61, 0x70, 0x20, 0x7b, 0x20, 0x69, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, + 0x7d, 0x2c, 0x20, 0x70, 0x61, 0x74, 0x63, 0x68, 0x4a, 0x61, 0x72, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0xd0, +} diff --git a/modules/charset/escape.go b/modules/charset/escape.go index abe813b465..9883700e88 100644 --- a/modules/charset/escape.go +++ b/modules/charset/escape.go @@ -63,6 +63,7 @@ func EscapeControlBytes(text []byte) (EscapeStatus, []byte) { func EscapeControlReader(text io.Reader, output io.Writer) (escaped EscapeStatus, err error) { buf := make([]byte, 4096) readStart := 0 + runeCount := 0 var n int var writePos int @@ -74,10 +75,13 @@ readingloop: for err == nil { n, err = text.Read(buf[readStart:]) bs := buf[:n+readStart] + n = len(bs) i := 0 for i < len(bs) { r, size := utf8.DecodeRune(bs[i:]) + runeCount++ + // Now handle the codepoints switch { case r == utf8.RuneError: @@ -112,6 +116,8 @@ readingloop: lineHasRTLScript = false lineHasLTRScript = false + case runeCount == 1 && r == 0xFEFF: // UTF BOM + // the first BOM is safe case r == '\r' || r == '\t' || r == ' ': // These are acceptable control characters and space characters case unicode.IsSpace(r): @@ -143,7 +149,8 @@ readingloop: return } writePos = i + size - case unicode.Is(unicode.C, r): + // 65279 == BOM rune. + case unicode.Is(unicode.C, r) && r != rune(65279): escaped.Escaped = true escaped.HasControls = true if writePos < i { diff --git a/modules/charset/escape_test.go b/modules/charset/escape_test.go index dec92b4992..01ccca7724 100644 --- a/modules/charset/escape_test.go +++ b/modules/charset/escape_test.go @@ -129,6 +129,14 @@ then resh (ר), and finally heh (ה) (which should appear leftmost).`, "\n" + `if access_level != "user` + "\u202e" + ` ` + "\u2066" + `// Check if admin` + "\u2069" + ` ` + "\u2066" + `" {` + "\n", status: EscapeStatus{Escaped: true, HasBIDI: true, BadBIDI: true, HasLTRScript: true, HasRTLScript: true}, }, + { + // UTF-8/16/32 all use the same codepoint for BOM + // Gitea could read UTF-16/32 content and convert into UTF-8 internally then render it, so we only process UTF-8 internally + name: "UTF BOM", + text: "\xef\xbb\xbftest", + result: "\xef\xbb\xbftest", + status: EscapeStatus{HasLTRScript: true}, + }, } func TestEscapeControlString(t *testing.T) { @@ -163,10 +171,18 @@ func TestEscapeControlReader(t *testing.T) { // lets add some control characters to the tests tests := make([]escapeControlTest, 0, len(escapeControlTests)*3) copy(tests, escapeControlTests) + + // if there is a BOM, we should keep the BOM + addPrefix := func(prefix, s string) string { + if strings.HasPrefix(s, "\xef\xbb\xbf") { + return s[:3] + prefix + s[3:] + } + return prefix + s + } for _, test := range escapeControlTests { test.name += " (+Control)" - test.text = "\u001E" + test.text - test.result = `` + "\u001e" + `` + test.result + test.text = addPrefix("\u001E", test.text) + test.result = addPrefix(``+"\u001e"+``, test.result) test.status.Escaped = true test.status.HasControls = true tests = append(tests, test) @@ -174,8 +190,8 @@ func TestEscapeControlReader(t *testing.T) { for _, test := range escapeControlTests { test.name += " (+Mark)" - test.text = "\u0300" + test.text - test.result = `` + "\u0300" + `` + test.result + test.text = addPrefix("\u0300", test.text) + test.result = addPrefix(``+"\u0300"+``, test.result) test.status.Escaped = true test.status.HasMarks = true tests = append(tests, test) @@ -200,3 +216,12 @@ func TestEscapeControlReader(t *testing.T) { }) } } + +func TestEscapeControlReader_panic(t *testing.T) { + bs := make([]byte, 0, 20479) + bs = append(bs, 'A') + for i := 0; i < 6826; i++ { + bs = append(bs, []byte("—")...) + } + _, _ = EscapeControlBytes(bs) +} diff --git a/modules/context/api.go b/modules/context/api.go index b079385aff..432d285a98 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -288,6 +288,7 @@ func APIContexter() func(http.Handler) http.Handler { }, Org: &APIOrganization{}, } + defer ctx.Close() ctx.Req = WithAPIContext(WithContext(req, ctx.Context), &ctx) ctx.csrf = Csrfer(csrfOpts, ctx.Context) diff --git a/modules/context/context.go b/modules/context/context.go index 5038850649..381a914786 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -9,9 +9,11 @@ import ( "context" "crypto/sha256" "encoding/hex" + "errors" "html" "html/template" "io" + "net" "net/http" "net/url" "path" @@ -69,6 +71,16 @@ type Context struct { Org *Organization } +// Close frees all resources hold by Context +func (ctx *Context) Close() error { + var err error + if ctx.Req != nil && ctx.Req.MultipartForm != nil { + err = ctx.Req.MultipartForm.RemoveAll() // remove the temp files buffered to tmp directory + } + // TODO: close opened repo, and more + return err +} + // TrHTMLEscapeArgs runs Tr but pre-escapes all arguments with html.EscapeString. // This is useful if the locale message is intended to only produce HTML content. func (ctx *Context) TrHTMLEscapeArgs(msg string, args ...string) string { @@ -179,6 +191,12 @@ func (ctx *Context) RedirectToFirst(location ...string) { continue } + // Unfortunately browsers consider a redirect Location with preceding "//" and "/\" as meaning redirect to "http(s)://REST_OF_PATH" + // Therefore we should ignore these redirect locations to prevent open redirects + if len(loc) > 1 && loc[0] == '/' && (loc[1] == '/' || loc[1] == '\\') { + continue + } + u, err := url.Parse(loc) if err != nil || ((u.Scheme != "" || u.Host != "") && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) { continue @@ -264,6 +282,12 @@ func (ctx *Context) ServerError(logMsg string, logErr error) { func (ctx *Context) serverErrorInternal(logMsg string, logErr error) { if logErr != nil { log.ErrorWithSkip(2, "%s: %v", logMsg, logErr) + if _, ok := logErr.(*net.OpError); ok || errors.Is(logErr, &net.OpError{}) { + // This is an error within the underlying connection + // and further rendering will not work so just return + return + } + if !setting.IsProd { ctx.Data["ErrorMsg"] = logErr } @@ -291,6 +315,7 @@ func (ctx *Context) PlainTextBytes(status int, bs []byte) { } ctx.Resp.WriteHeader(status) ctx.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8") + ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff") if _, err := ctx.Resp.Write(bs); err != nil { log.Error("Write bytes failed: %v", err) } @@ -628,6 +653,8 @@ func Contexter() func(next http.Handler) http.Handler { "RunModeIsProd": setting.IsProd, }, } + defer ctx.Close() + // PageData is passed by reference, and it will be rendered to `window.config.pageData` in `head.tmpl` for JavaScript modules ctx.PageData = map[string]interface{}{} ctx.Data["PageData"] = ctx.PageData diff --git a/modules/context/csrf.go b/modules/context/csrf.go index 8d179ca904..66ea6bd0a3 100644 --- a/modules/context/csrf.go +++ b/modules/context/csrf.go @@ -229,6 +229,7 @@ func Csrfer(opt CsrfOptions, ctx *Context) CSRF { } } + needsNew = needsNew || ctx.Req.Method == "GET" // If this request is a Get request, it will generate a new token, make sure the token is always up-to-date. if needsNew { // FIXME: actionId. x.Token = GenerateToken(x.Secret, x.ID, "POST") diff --git a/modules/context/org.go b/modules/context/org.go index 585a5fd762..8d82abbee1 100644 --- a/modules/context/org.go +++ b/modules/context/org.go @@ -70,12 +70,6 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { org := ctx.Org.Organization ctx.Data["Org"] = org - teams, err := org.LoadTeams() - if err != nil { - ctx.ServerError("LoadTeams", err) - } - ctx.Data["OrgTeams"] = teams - // Admin has super access. if ctx.IsSigned && ctx.User.IsAdmin { ctx.Org.IsOwner = true @@ -129,7 +123,23 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { // Team. if ctx.Org.IsMember { + shouldSeeAllTeams := false if ctx.Org.IsOwner { + shouldSeeAllTeams = true + } else { + teams, err := org.GetUserTeams(ctx.User.ID) + if err != nil { + ctx.ServerError("GetUserTeams", err) + return + } + for _, team := range teams { + if team.IncludesAllRepositories && team.AccessMode >= perm.AccessModeAdmin { + shouldSeeAllTeams = true + break + } + } + } + if shouldSeeAllTeams { ctx.Org.Teams, err = org.LoadTeams() if err != nil { ctx.ServerError("LoadTeams", err) diff --git a/modules/context/private.go b/modules/context/private.go index dfefa1d2f0..05d60d0403 100644 --- a/modules/context/private.go +++ b/modules/context/private.go @@ -38,6 +38,8 @@ func PrivateContexter() func(http.Handler) http.Handler { Data: map[string]interface{}{}, }, } + defer ctx.Close() + ctx.Req = WithPrivateContext(req, ctx) next.ServeHTTP(ctx.Resp, ctx.Req) }) diff --git a/modules/context/repo.go b/modules/context/repo.go index bf782383b5..4eeab710ff 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -410,6 +410,12 @@ func RepoIDAssignment() func(ctx *Context) { // RepoAssignment returns a middleware to handle repository assignment func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { + if _, repoAssignmentOnce := ctx.Data["repoAssignmentExecuted"]; repoAssignmentOnce { + log.Trace("RepoAssignment was exec already, skipping second call ...") + return + } + ctx.Data["repoAssignmentExecuted"] = true + var ( owner *user_model.User err error @@ -440,6 +446,26 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.Repo.Owner = owner ctx.Data["Username"] = ctx.Repo.Owner.Name + // redirect link to wiki + if strings.HasSuffix(repoName, ".wiki") { + // ctx.Req.URL.Path does not have the preceding appSubURL - any redirect must have this added + // Now we happen to know that all of our paths are: /:username/:reponame/whatever_else + originalRepoName := ctx.Params(":reponame") + redirectRepoName := strings.TrimSuffix(repoName, ".wiki") + redirectRepoName += originalRepoName[len(redirectRepoName)+5:] + redirectPath := strings.Replace( + ctx.Req.URL.EscapedPath(), + url.PathEscape(userName)+"/"+url.PathEscape(originalRepoName), + url.PathEscape(userName)+"/"+url.PathEscape(redirectRepoName)+"/wiki", + 1, + ) + if ctx.Req.URL.RawQuery != "" { + redirectPath += "?" + ctx.Req.URL.RawQuery + } + ctx.Redirect(path.Join(setting.AppSubURL, redirectPath)) + return + } + // Get repository. repo, err := repo_model.GetRepositoryByName(owner.ID, repoName) if err != nil { @@ -572,6 +598,9 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.ServerError("RepoAssignment Invalid repo "+repo_model.RepoPath(userName, repoName), err) return } + if ctx.Repo.GitRepo != nil { + ctx.Repo.GitRepo.Close() + } ctx.Repo.GitRepo = gitRepo // We opened it, we should close it @@ -911,7 +940,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context if refType == RepoRefLegacy { // redirect from old URL scheme to new URL scheme - prefix := strings.TrimPrefix(setting.AppSubURL+strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*")), ctx.Repo.RepoLink) + prefix := strings.TrimPrefix(setting.AppSubURL+strings.ToLower(strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*"))), strings.ToLower(ctx.Repo.RepoLink)) ctx.Redirect(path.Join( ctx.Repo.RepoLink, diff --git a/modules/convert/pull.go b/modules/convert/pull.go index 2e2c1b85bc..ad757dbe5f 100644 --- a/modules/convert/pull.go +++ b/modules/convert/pull.go @@ -67,6 +67,7 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRe PatchURL: pr.Issue.PatchURL(), HasMerged: pr.HasMerged, MergeBase: pr.MergeBase, + Mergeable: pr.Mergeable(), Deadline: apiIssue.Deadline, Created: pr.Issue.CreatedUnix.AsTimePtr(), Updated: pr.Issue.UpdatedUnix.AsTimePtr(), @@ -190,10 +191,6 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRe } } - if pr.Status != models.PullRequestStatusChecking { - mergeable := !(pr.Status == models.PullRequestStatusConflict || pr.Status == models.PullRequestStatusError) && !pr.IsWorkInProgress() - apiPullRequest.Mergeable = mergeable - } if pr.HasMerged { apiPullRequest.Merged = pr.MergedUnix.AsTimePtr() apiPullRequest.MergedCommitID = &pr.MergedCommitID diff --git a/modules/doctor/authorizedkeys.go b/modules/doctor/authorizedkeys.go index 1a9b60e248..ab949b737e 100644 --- a/modules/doctor/authorizedkeys.go +++ b/modules/doctor/authorizedkeys.go @@ -71,8 +71,8 @@ func checkAuthorizedKeys(logger log.Logger, autofix bool) error { "authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"", fPath, "gitea admin regenerate keys", - "gitea doctor --run authorized_keys --fix") - return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized_keys --fix"`) + "gitea doctor --run authorized-keys --fix") + return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized-keys --fix"`) } logger.Warn("authorized_keys is out of date. Attempting rewrite...") err = asymkey_model.RewriteAllPublicKeys() diff --git a/modules/doctor/dbconsistency.go b/modules/doctor/dbconsistency.go index cd34994e1a..dea33d97fe 100644 --- a/modules/doctor/dbconsistency.go +++ b/modules/doctor/dbconsistency.go @@ -142,6 +142,12 @@ func checkDBConsistency(logger log.Logger, autofix bool) error { Fixer: models.FixIssueLabelWithOutsideLabels, FixedMessage: "Removed", }, + { + Name: "Action with created_unix set as an empty string", + Counter: models.CountActionCreatedUnixString, + Fixer: models.FixActionCreatedUnixString, + FixedMessage: "Set to zero", + }, } // TODO: function to recalc all counters @@ -177,6 +183,18 @@ func checkDBConsistency(logger log.Logger, autofix bool) error { // find access without repository genericOrphanCheck("Access entries without existing repository", "access", "repository", "access.repo_id=repository.id"), + // find action without repository + genericOrphanCheck("Action entries without existing repository", + "action", "repository", "action.repo_id=repository.id"), + // find OAuth2Grant without existing user + genericOrphanCheck("Orphaned OAuth2Grant without existing User", + "oauth2_grant", "user", "oauth2_grant.user_id=`user`.id"), + // find OAuth2Application without existing user + genericOrphanCheck("Orphaned OAuth2Application without existing User", + "oauth2_application", "user", "oauth2_application.uid=`user`.id"), + // find OAuth2AuthorizationCode without existing OAuth2Grant + genericOrphanCheck("Orphaned OAuth2AuthorizationCode without existing OAuth2Grant", + "oauth2_authorization_code", "oauth2_grant", "oauth2_authorization_code.grant_id=oauth2_grant.id"), ) for _, c := range consistencyChecks { diff --git a/modules/git/batch_reader.go b/modules/git/batch_reader.go index 7f7272c19e..3b9d0f95c4 100644 --- a/modules/git/batch_reader.go +++ b/modules/git/batch_reader.go @@ -54,6 +54,12 @@ func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError, <-closed } + // Ensure cancel is called as soon as the provided context is cancelled + go func() { + <-ctx.Done() + cancel() + }() + _, filename, line, _ := runtime.Caller(2) filename = strings.TrimPrefix(filename, callerPrefix) @@ -93,6 +99,12 @@ func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi <-closed } + // Ensure cancel is called as soon as the provided context is cancelled + go func() { + <-ctx.Done() + cancel() + }() + _, filename, line, _ := runtime.Caller(2) filename = strings.TrimPrefix(filename, callerPrefix) diff --git a/modules/git/blame.go b/modules/git/blame.go index b30124594d..f887e4bf7d 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -130,6 +130,7 @@ func createBlameReader(ctx context.Context, dir string, command ...string) (*Bla cmd := exec.CommandContext(ctx, command[0], command[1:]...) cmd.Dir = dir cmd.Stderr = os.Stderr + process.SetSysProcAttribute(cmd) stdout, err := cmd.StdoutPipe() if err != nil { diff --git a/modules/git/command.go b/modules/git/command.go index 3cf85c2d85..135e9755fd 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/util" ) var ( @@ -32,10 +33,11 @@ const DefaultLocale = "C" // Command represents a command with its subcommands or arguments. type Command struct { - name string - args []string - parentContext context.Context - desc string + name string + args []string + parentContext context.Context + desc string + globalArgsLength int } func (c *Command) String() string { @@ -56,9 +58,10 @@ func NewCommandContext(ctx context.Context, args ...string) *Command { cargs := make([]string, len(GlobalCommandArgs)) copy(cargs, GlobalCommandArgs) return &Command{ - name: GitExecutable, - args: append(cargs, args...), - parentContext: ctx, + name: GitExecutable, + args: append(cargs, args...), + parentContext: ctx, + globalArgsLength: len(GlobalCommandArgs), } } @@ -145,7 +148,21 @@ func (c *Command) RunWithContext(rc *RunContext) error { desc := c.desc if desc == "" { - desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(c.args, " "), rc.Dir) + args := c.args[c.globalArgsLength:] + var argSensitiveURLIndexes []int + for i, arg := range c.args { + if strings.Contains(arg, "://") && strings.Contains(arg, "@") { + argSensitiveURLIndexes = append(argSensitiveURLIndexes, i) + } + } + if len(argSensitiveURLIndexes) > 0 { + args = make([]string, len(c.args)) + copy(args, c.args) + for _, urlArgIndex := range argSensitiveURLIndexes { + args[urlArgIndex] = util.NewStringURLSanitizer(args[urlArgIndex], true).Replace(args[urlArgIndex]) + } + } + desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), rc.Dir) } ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, rc.Timeout, desc) @@ -163,12 +180,15 @@ func (c *Command) RunWithContext(rc *RunContext) error { fmt.Sprintf("LC_ALL=%s", DefaultLocale), // avoid prompting for credentials interactively, supported since git v2.3 "GIT_TERMINAL_PROMPT=0", + // ignore replace references (https://git-scm.com/docs/git-replace) + "GIT_NO_REPLACE_OBJECTS=1", ) // TODO: verify if this is still needed in golang 1.15 if goVersionLessThan115 { cmd.Env = append(cmd.Env, "GODEBUG=asyncpreemptoff=1") } + process.SetSysProcAttribute(cmd) cmd.Dir = rc.Dir cmd.Stdout = rc.Stdout cmd.Stderr = rc.Stderr diff --git a/modules/git/commit_info_test.go b/modules/git/commit_info_test.go index 8467bdaa90..f89ac5794b 100644 --- a/modules/git/commit_info_test.go +++ b/modules/git/commit_info_test.go @@ -16,20 +16,25 @@ import ( "github.com/stretchr/testify/assert" ) -const testReposDir = "tests/repos/" -const benchmarkReposDir = "benchmark/repos/" +const ( + testReposDir = "tests/repos/" +) -func cloneRepo(url, dir, name string) (string, error) { - repoDir := filepath.Join(dir, name) - if _, err := os.Stat(repoDir); err == nil { - return repoDir, nil +func cloneRepo(url, name string) (string, error) { + repoDir, err := os.MkdirTemp("", name) + if err != nil { + return "", err } - return repoDir, Clone(url, repoDir, CloneRepoOptions{ + if err := Clone(url, repoDir, CloneRepoOptions{ Mirror: false, Bare: false, Quiet: true, Timeout: 5 * time.Minute, - }) + }); err != nil { + _ = util.RemoveAll(repoDir) + return "", err + } + return repoDir, nil } func testGetCommitsInfo(t *testing.T, repo1 *Repository) { @@ -59,20 +64,35 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) { } for _, testCase := range testCases { commit, err := repo1.GetCommit(testCase.CommitID) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err, "Unable to get commit: %s from testcase due to error: %v", testCase.CommitID, err) + // no point trying to do anything else for this test. + continue + } assert.NotNil(t, commit) assert.NotNil(t, commit.Tree) assert.NotNil(t, commit.Tree.repo) tree, err := commit.Tree.SubTree(testCase.Path) + if err != nil { + assert.NoError(t, err, "Unable to get subtree: %s of commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err) + // no point trying to do anything else for this test. + continue + } + assert.NotNil(t, tree, "tree is nil for testCase CommitID %s in Path %s", testCase.CommitID, testCase.Path) assert.NotNil(t, tree.repo, "repo is nil for testCase CommitID %s in Path %s", testCase.CommitID, testCase.Path) - assert.NoError(t, err) entries, err := tree.ListEntries() - assert.NoError(t, err) - commitsInfo, treeCommit, err := entries.GetCommitsInfo(context.Background(), commit, testCase.Path, nil) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err, "Unable to get entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err) + // no point trying to do anything else for this test. + continue + } + + // FIXME: Context.TODO() - if graceful has started we should use its Shutdown context otherwise use install signals in TestMain. + commitsInfo, treeCommit, err := entries.GetCommitsInfo(context.TODO(), commit, testCase.Path, nil) + assert.NoError(t, err, "Unable to get commit information for entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err) if err != nil { t.FailNow() } @@ -98,40 +118,52 @@ func TestEntries_GetCommitsInfo(t *testing.T) { testGetCommitsInfo(t, bareRepo1) - clonedPath, err := cloneRepo(bareRepo1Path, testReposDir, "repo1_TestEntries_GetCommitsInfo") - assert.NoError(t, err) + clonedPath, err := cloneRepo(bareRepo1Path, "repo1_TestEntries_GetCommitsInfo") + if err != nil { + assert.NoError(t, err) + } defer util.RemoveAll(clonedPath) clonedRepo1, err := OpenRepository(clonedPath) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + } defer clonedRepo1.Close() testGetCommitsInfo(t, clonedRepo1) } func BenchmarkEntries_GetCommitsInfo(b *testing.B) { - benchmarks := []struct { + type benchmarkType struct { url string name string - }{ + } + + benchmarks := []benchmarkType{ {url: "https://github.com/go-gitea/gitea.git", name: "gitea"}, {url: "https://github.com/ethantkoenig/manyfiles.git", name: "manyfiles"}, {url: "https://github.com/moby/moby.git", name: "moby"}, {url: "https://github.com/golang/go.git", name: "go"}, {url: "https://github.com/torvalds/linux.git", name: "linux"}, } - for _, benchmark := range benchmarks { + + doBenchmark := func(benchmark benchmarkType) { var commit *Commit var entries Entries var repo *Repository - if repoPath, err := cloneRepo(benchmark.url, benchmarkReposDir, benchmark.name); err != nil { + repoPath, err := cloneRepo(benchmark.url, benchmark.name) + if err != nil { b.Fatal(err) - } else if repo, err = OpenRepository(repoPath); err != nil { + } + defer util.RemoveAll(repoPath) + + if repo, err = OpenRepository(repoPath); err != nil { b.Fatal(err) - } else if commit, err = repo.GetBranchCommit("master"); err != nil { - repo.Close() + } + defer repo.Close() + + if commit, err = repo.GetBranchCommit("master"); err != nil { b.Fatal(err) } else if entries, err = commit.Tree.ListEntries(); err != nil { - repo.Close() b.Fatal(err) } entries.Sort() @@ -144,6 +176,9 @@ func BenchmarkEntries_GetCommitsInfo(b *testing.B) { } } }) - repo.Close() + } + + for _, benchmark := range benchmarks { + doBenchmark(benchmark) } } diff --git a/modules/git/diff.go b/modules/git/diff.go index f90f911be0..8ca58b4809 100644 --- a/modules/git/diff.go +++ b/modules/git/diff.go @@ -59,27 +59,28 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff ctx, _, finished := process.GetManager().AddContext(repo.Ctx, fmt.Sprintf("GetRawDiffForFile: [repo_path: %s]", repo.Path)) defer finished() - var cmd *exec.Cmd + cmd := exec.CommandContext(ctx, GitExecutable, GlobalCommandArgs...) + switch diffType { case RawDiffNormal: if len(startCommit) != 0 { - cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"diff", "-M", startCommit, endCommit}, fileArgs...)...) + cmd.Args = append(cmd.Args, append([]string{"diff", "-M", startCommit, endCommit}, fileArgs...)...) } else if commit.ParentCount() == 0 { - cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"show", endCommit}, fileArgs...)...) + cmd.Args = append(cmd.Args, append([]string{"show", endCommit}, fileArgs...)...) } else { c, _ := commit.Parent(0) - cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"diff", "-M", c.ID.String(), endCommit}, fileArgs...)...) + cmd.Args = append(cmd.Args, append([]string{"diff", "-M", c.ID.String(), endCommit}, fileArgs...)...) } case RawDiffPatch: if len(startCommit) != 0 { query := fmt.Sprintf("%s...%s", endCommit, startCommit) - cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", "--root", query}, fileArgs...)...) + cmd.Args = append(cmd.Args, append([]string{"format-patch", "--no-signature", "--stdout", "--root", query}, fileArgs...)...) } else if commit.ParentCount() == 0 { - cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", "--root", endCommit}, fileArgs...)...) + cmd.Args = append(cmd.Args, append([]string{"format-patch", "--no-signature", "--stdout", "--root", endCommit}, fileArgs...)...) } else { c, _ := commit.Parent(0) query := fmt.Sprintf("%s...%s", endCommit, c.ID.String()) - cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", query}, fileArgs...)...) + cmd.Args = append(cmd.Args, append([]string{"format-patch", "--no-signature", "--stdout", query}, fileArgs...)...) } default: return fmt.Errorf("invalid diffType: %s", diffType) diff --git a/modules/git/git.go b/modules/git/git.go index cca5ce6714..bc4c4b833e 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -112,8 +112,8 @@ func SetExecutablePath(path string) error { // VersionInfo returns git version information func VersionInfo() string { - var format = "Git Version: %s" - var args = []interface{}{gitVersion.Original()} + format := "Git Version: %s" + args := []interface{}{gitVersion.Original()} // Since git wire protocol has been released from git v2.18 if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { format += ", Wire Protocol %s Enabled" @@ -148,7 +148,7 @@ func Init(ctx context.Context) error { // By default partial clones are disabled, enable them from git v2.22 if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil { - GlobalCommandArgs = append(GlobalCommandArgs, "-c", "uploadpack.allowfilter=true") + GlobalCommandArgs = append(GlobalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true") } // Save current git version on init to gitVersion otherwise it would require an RWMutex diff --git a/modules/git/notes_gogit.go b/modules/git/notes_gogit.go index 6cb719ce92..b1e5e453e4 100644 --- a/modules/git/notes_gogit.go +++ b/modules/git/notes_gogit.go @@ -22,6 +22,9 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note) log.Trace("Searching for git note corresponding to the commit %q in the repository %q", commitID, repo.Path) notes, err := repo.GetCommit(NotesRef) if err != nil { + if IsErrNotExist(err) { + return err + } log.Error("Unable to get commit from ref %q. Error: %v", NotesRef, err) return err } diff --git a/modules/git/notes_nogogit.go b/modules/git/notes_nogogit.go index 13b4b7b36a..4e44167c3d 100644 --- a/modules/git/notes_nogogit.go +++ b/modules/git/notes_nogogit.go @@ -21,6 +21,9 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note) log.Trace("Searching for git note corresponding to the commit %q in the repository %q", commitID, repo.Path) notes, err := repo.GetCommit(NotesRef) if err != nil { + if IsErrNotExist(err) { + return err + } log.Error("Unable to get commit from ref %q. Error: %v", NotesRef, err) return err } @@ -44,7 +47,10 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note) commitID = commitID[2:] } if err != nil { - log.Error("Unable to find git note corresponding to the commit %q. Error: %v", originalCommitID, err) + // Err may have been updated by the SubTree we need to recheck if it's again an ErrNotExist + if !IsErrNotExist(err) { + log.Error("Unable to find git note corresponding to the commit %q. Error: %v", originalCommitID, err) + } return err } } diff --git a/modules/git/repo.go b/modules/git/repo.go index b19e80cd44..8864f159a5 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -19,6 +19,7 @@ import ( "time" "code.gitea.io/gitea/modules/proxy" + "code.gitea.io/gitea/modules/util" ) // GPGSettings represents the default GPG settings for this repository @@ -79,28 +80,34 @@ func InitRepository(repoPath string, bare bool) error { // IsEmpty Check if repository is empty. func (repo *Repository) IsEmpty() (bool, error) { - var errbuf strings.Builder - if err := NewCommand("log", "-1").RunInDirPipeline(repo.Path, nil, &errbuf); err != nil { - if strings.Contains(errbuf.String(), "fatal: bad default revision 'HEAD'") || - strings.Contains(errbuf.String(), "fatal: your current branch 'master' does not have any commits yet") { + var errbuf, output strings.Builder + if err := NewCommandContext(repo.Ctx, "show-ref", "--head", "^HEAD$").RunWithContext(&RunContext{ + Timeout: -1, + Dir: repo.Path, + Stdout: &output, + Stderr: &errbuf, + }); err != nil { + if err.Error() == "exit status 1" && errbuf.String() == "" { return true, nil } return true, fmt.Errorf("check empty: %v - %s", err, errbuf.String()) } - return false, nil + return strings.TrimSpace(output.String()) == "", nil } // CloneRepoOptions options when clone a repository type CloneRepoOptions struct { - Timeout time.Duration - Mirror bool - Bare bool - Quiet bool - Branch string - Shared bool - NoCheckout bool - Depth int + Timeout time.Duration + Mirror bool + Bare bool + Quiet bool + Branch string + Shared bool + NoCheckout bool + Depth int + Filter string + SkipTLSVerify bool } // Clone clones original repository to target path. @@ -123,6 +130,9 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo } cmd := NewCommandContextNoGlobals(ctx, args...).AddArguments("clone") + if opts.SkipTLSVerify { + cmd.AddArguments("-c", "http.sslVerify=false") + } if opts.Mirror { cmd.AddArguments("--mirror") } @@ -141,12 +151,20 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo if opts.Depth > 0 { cmd.AddArguments("--depth", strconv.Itoa(opts.Depth)) } - + if opts.Filter != "" { + cmd.AddArguments("--filter", opts.Filter) + } if len(opts.Branch) > 0 { cmd.AddArguments("-b", opts.Branch) } cmd.AddArguments("--", from, to) + if strings.Contains(from, "://") && strings.Contains(from, "@") { + cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, util.NewStringURLSanitizer(from, true).Replace(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)) + } + if opts.Timeout <= 0 { opts.Timeout = -1 } @@ -223,6 +241,11 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error { if len(opts.Branch) > 0 { cmd.AddArguments(opts.Branch) } + if strings.Contains(opts.Remote, "://") && strings.Contains(opts.Remote, "@") { + cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, util.NewStringURLSanitizer(opts.Remote, true).Replace(opts.Remote), opts.Force, opts.Mirror)) + } else { + cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, opts.Remote, opts.Force, opts.Mirror)) + } var outbuf, errbuf strings.Builder if opts.Timeout == 0 { diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go index 0bb550bb4b..1fbedae5d5 100644 --- a/modules/git/repo_attribute.go +++ b/modules/git/repo_attribute.go @@ -87,7 +87,7 @@ func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[ return nil, fmt.Errorf("wrong number of fields in return from check-attr") } - var name2attribute2info = make(map[string]map[string]string) + name2attribute2info := make(map[string]map[string]string) for i := 0; i < (len(fields) / 3); i++ { filename := string(fields[3*i]) @@ -119,12 +119,10 @@ type CheckAttributeReader struct { env []string ctx context.Context cancel context.CancelFunc - running chan struct{} } // Init initializes the cmd func (c *CheckAttributeReader) Init(ctx context.Context) error { - c.running = make(chan struct{}) cmdArgs := []string{"check-attr", "--stdin", "-z"} if len(c.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil { @@ -179,17 +177,16 @@ func (c *CheckAttributeReader) Init(ctx context.Context) error { // Run run cmd func (c *CheckAttributeReader) Run() error { defer func() { - _ = c.Close() + _ = c.stdinReader.Close() + _ = c.stdOut.Close() }() stdErr := new(bytes.Buffer) - err := c.cmd.RunInDirTimeoutEnvFullPipelineFunc(c.env, -1, c.Repo.Path, c.stdOut, stdErr, c.stdinReader, func(_ context.Context, _ context.CancelFunc) error { - close(c.running) - return nil - }) - if err != nil && c.ctx.Err() != nil && err.Error() != "signal: killed" { + err := c.cmd.RunInDirTimeoutEnvFullPipeline(c.env, -1, c.Repo.Path, c.stdOut, stdErr, c.stdinReader) + if err != nil && // If there is an error we need to return but: + c.ctx.Err() != err && // 1. Ignore the context error if the context is cancelled or exceeds the deadline (RunWithContext could return c.ctx.Err() which is Canceled or DeadlineExceeded) + err.Error() != "signal: killed" { // 2. We should not pass up errors due to the program being killed return fmt.Errorf("failed to run attr-check. Error: %w\nStderr: %s", err, stdErr.String()) } - return nil } @@ -204,7 +201,7 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err select { case <-c.ctx.Done(): return nil, c.ctx.Err() - case <-c.running: + default: } if _, err = c.stdinWriter.Write([]byte(path + "\x00")); err != nil { @@ -229,15 +226,8 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err // Close close pip after use func (c *CheckAttributeReader) Close() error { - err := c.stdinWriter.Close() - _ = c.stdinReader.Close() - _ = c.stdOut.Close() c.cancel() - select { - case <-c.running: - default: - close(c.running) - } + err := c.stdinWriter.Close() return err } diff --git a/modules/git/repo_branch_gogit.go b/modules/git/repo_branch_gogit.go index d159aafd6f..13b42306a6 100644 --- a/modules/git/repo_branch_gogit.go +++ b/modules/git/repo_branch_gogit.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/storer" ) // IsObjectExist returns true if given reference exists in the repository. @@ -82,7 +83,8 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) { } // WalkReferences walks all the references from the repository -func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) error) (int, error) { +// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty. +func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) { repo, err := OpenRepositoryCtx(ctx, repoPath) if err != nil { return 0, err @@ -97,9 +99,45 @@ func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) er defer iter.Close() err = iter.ForEach(func(ref *plumbing.Reference) error { - err := walkfn(string(ref.Name())) + err := walkfn(ref.Hash().String(), string(ref.Name())) i++ return err }) return i, err } + +// WalkReferences walks all the references from the repository +func (repo *Repository) WalkReferences(arg ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) { + i := 0 + var iter storer.ReferenceIter + var err error + switch arg { + case ObjectTag: + iter, err = repo.gogitRepo.Tags() + case ObjectBranch: + iter, err = repo.gogitRepo.Branches() + default: + iter, err = repo.gogitRepo.References() + } + if err != nil { + return i, err + } + defer iter.Close() + + err = iter.ForEach(func(ref *plumbing.Reference) error { + if i < skip { + i++ + return nil + } + err := walkfn(ref.Hash().String(), string(ref.Name())) + i++ + if err != nil { + return err + } + if limit != 0 && i >= skip+limit { + return storer.ErrStop + } + return nil + }) + return i, err +} diff --git a/modules/git/repo_branch_nogogit.go b/modules/git/repo_branch_nogogit.go index 55952acda4..080a7a3b26 100644 --- a/modules/git/repo_branch_nogogit.go +++ b/modules/git/repo_branch_nogogit.go @@ -68,13 +68,29 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) { } // WalkReferences walks all the references from the repository -func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) error) (int, error) { +func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) { return walkShowRef(ctx, repoPath, "", 0, 0, walkfn) } +// WalkReferences walks all the references from the repository +// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty. +func (repo *Repository) WalkReferences(refType ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) { + var arg string + switch refType { + case ObjectTag: + arg = "--tags" + case ObjectBranch: + arg = "--heads" + default: + arg = "" + } + + return walkShowRef(repo.Ctx, repo.Path, arg, skip, limit, walkfn) +} + // callShowRef return refs, if limit = 0 it will not limit func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit int) (branchNames []string, countAll int, err error) { - countAll, err = walkShowRef(ctx, repoPath, arg, skip, limit, func(branchName string) error { + countAll, err = walkShowRef(ctx, repoPath, arg, skip, limit, func(_, branchName string) error { branchName = strings.TrimPrefix(branchName, prefix) branchNames = append(branchNames, branchName) @@ -83,7 +99,7 @@ func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit return } -func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, walkfn func(string) error) (countAll int, err error) { +func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) { stdoutReader, stdoutWriter := io.Pipe() defer func() { _ = stdoutReader.Close() @@ -125,11 +141,7 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal for limit == 0 || i < skip+limit { // The output of show-ref is simply a list: // SP LF - _, err := bufReader.ReadSlice(' ') - for err == bufio.ErrBufferFull { - // This shouldn't happen but we'll tolerate it for the sake of peace - _, err = bufReader.ReadSlice(' ') - } + sha, err := bufReader.ReadString(' ') if err == io.EOF { return i, nil } @@ -149,7 +161,12 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal if len(branchName) > 0 { branchName = branchName[:len(branchName)-1] } - err = walkfn(branchName) + + if len(sha) > 0 { + sha = sha[:len(sha)-1] + } + + err = walkfn(sha, branchName) if err != nil { return i, err } diff --git a/modules/git/repo_commitgraph.go b/modules/git/repo_commitgraph.go new file mode 100644 index 0000000000..44c41c0b42 --- /dev/null +++ b/modules/git/repo_commitgraph.go @@ -0,0 +1,21 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "context" + "fmt" +) + +// 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 CheckGitVersionAtLeast("2.18") == nil { + if _, err := NewCommandContext(ctx, "commit-graph", "write").RunInDir(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_test.go b/modules/git/repo_compare_test.go index 301e085aae..82d3257c0f 100644 --- a/modules/git/repo_compare_test.go +++ b/modules/git/repo_compare_test.go @@ -17,17 +17,33 @@ import ( func TestGetFormatPatch(t *testing.T) { bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") - clonedPath, err := cloneRepo(bareRepo1Path, testReposDir, "repo1_TestGetFormatPatch") + clonedPath, err := cloneRepo(bareRepo1Path, "repo1_TestGetFormatPatch") + if err != nil { + assert.NoError(t, err) + return + } defer util.RemoveAll(clonedPath) - assert.NoError(t, err) + repo, err := OpenRepository(clonedPath) + if err != nil { + assert.NoError(t, err) + return + } defer repo.Close() - assert.NoError(t, err) + rd := &bytes.Buffer{} err = repo.GetPatch("8d92fc95^", "8d92fc95", rd) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } + patchb, err := io.ReadAll(rd) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } + patch := string(patchb) assert.Regexp(t, "^From 8d92fc95", patch) assert.Contains(t, patch, "Subject: [PATCH] Add file2.txt") @@ -37,17 +53,25 @@ func TestReadPatch(t *testing.T) { // Ensure we can read the patch files bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") repo, err := OpenRepository(bareRepo1Path) + if err != nil { + assert.NoError(t, err) + return + } defer repo.Close() - assert.NoError(t, err) // This patch doesn't exist noFile, err := repo.ReadPatchCommit(0) assert.Error(t, err) + // This patch is an empty one (sometimes it's a 404) noCommit, err := repo.ReadPatchCommit(1) assert.Error(t, err) + // This patch is legit and should return a commit oldCommit, err := repo.ReadPatchCommit(2) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } assert.Empty(t, noFile) assert.Empty(t, noCommit) @@ -58,23 +82,45 @@ func TestReadPatch(t *testing.T) { func TestReadWritePullHead(t *testing.T) { // Ensure we can write SHA1 head corresponding to PR and open them bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") - repo, err := OpenRepository(bareRepo1Path) - assert.NoError(t, err) + + // As we are writing we should clone the repository first + clonedPath, err := cloneRepo(bareRepo1Path, "TestReadWritePullHead") + if err != nil { + assert.NoError(t, err) + return + } + defer util.RemoveAll(clonedPath) + + repo, err := OpenRepository(clonedPath) + if err != nil { + assert.NoError(t, err) + return + } defer repo.Close() + // Try to open non-existing Pull _, err = repo.GetRefCommitID(PullPrefix + "0/head") assert.Error(t, err) + // Write a fake sha1 with only 40 zeros newCommit := "feaf4ba6bc635fec442f46ddd4512416ec43c2c2" err = repo.SetReference(PullPrefix+"1/head", newCommit) - assert.NoError(t, err) - // Remove file after the test - defer func() { - _ = repo.RemoveReference(PullPrefix + "1/head") - }() + if err != nil { + assert.NoError(t, err) + return + } + // Read the file created headContents, err := repo.GetRefCommitID(PullPrefix + "1/head") - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } + assert.Len(t, string(headContents), 40) assert.True(t, string(headContents) == newCommit) + + // Remove file after the test + err = repo.RemoveReference(PullPrefix + "1/head") + assert.NoError(t, err) } diff --git a/modules/git/repo_language_stats_nogogit.go b/modules/git/repo_language_stats_nogogit.go index 0b21bf6344..adb11dd8fa 100644 --- a/modules/git/repo_language_stats_nogogit.go +++ b/modules/git/repo_language_stats_nogogit.go @@ -88,7 +88,10 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err } }() } - defer cancel() + defer func() { + _ = checker.Close() + cancel() + }() } } diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 6b5dbeef48..4e4f0eae33 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -10,7 +10,6 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" ) @@ -34,69 +33,6 @@ func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error return err } -func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) { - t, ok := repo.tagCache.Get(tagID.String()) - if ok { - log.Debug("Hit cache: %s", tagID) - tagClone := *t.(*Tag) - tagClone.Name = name // This is necessary because lightweight tags may have same id - return &tagClone, nil - } - - tp, err := repo.GetTagType(tagID) - if err != nil { - return nil, err - } - - // Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object - commitIDStr, err := repo.GetTagCommitID(name) - if err != nil { - // every tag should have a commit ID so return all errors - return nil, err - } - commitID, err := NewIDFromString(commitIDStr) - if err != nil { - return nil, err - } - - // If type is "commit, the tag is a lightweight tag - if ObjectType(tp) == ObjectCommit { - commit, err := repo.GetCommit(commitIDStr) - if err != nil { - return nil, err - } - tag := &Tag{ - Name: name, - ID: tagID, - Object: commitID, - Type: tp, - Tagger: commit.Committer, - Message: commit.Message(), - } - - repo.tagCache.Set(tagID.String(), tag) - return tag, nil - } - - // The tag is an annotated tag with a message. - data, err := NewCommandContext(repo.Ctx, "cat-file", "-p", tagID.String()).RunInDirBytes(repo.Path) - if err != nil { - return nil, err - } - - tag, err := parseTagData(data) - if err != nil { - return nil, err - } - - tag.Name = name - tag.ID = tagID - tag.Type = tp - - repo.tagCache.Set(tagID.String(), tag) - return tag, nil -} - // GetTagNameBySHA returns the name of a tag from its tag object SHA or commit SHA func (repo *Repository) GetTagNameBySHA(sha string) (string, error) { if len(sha) < 5 { @@ -159,6 +95,20 @@ func (repo *Repository) GetTag(name string) (*Tag, error) { return tag, nil } +// GetTagWithID returns a Git tag by given name and ID +func (repo *Repository) GetTagWithID(idStr, name string) (*Tag, error) { + id, err := NewIDFromString(idStr) + if err != nil { + return nil, err + } + + tag, err := repo.getTag(id, name) + if err != nil { + return nil, err + } + return tag, nil +} + // GetTagInfos returns all tag infos of the repository. func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) { // TODO this a slow implementation, makes one git command per tag @@ -192,19 +142,6 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) { return tags, tagsTotal, nil } -// GetTagType gets the type of the tag, either commit (simple) or tag (annotated) -func (repo *Repository) GetTagType(id SHA1) (string, error) { - // Get tag type - stdout, err := NewCommandContext(repo.Ctx, "cat-file", "-t", id.String()).RunInDir(repo.Path) - if err != nil { - return "", err - } - if len(stdout) == 0 { - return "", ErrNotExist{ID: id.String()} - } - return strings.TrimSpace(stdout), nil -} - // GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) { id, err := NewIDFromString(sha) diff --git a/modules/git/repo_tag_gogit.go b/modules/git/repo_tag_gogit.go index ff8a6d53ee..5c87e914c0 100644 --- a/modules/git/repo_tag_gogit.go +++ b/modules/git/repo_tag_gogit.go @@ -11,6 +11,8 @@ package git import ( "strings" + "code.gitea.io/gitea/modules/log" + "github.com/go-git/go-git/v5/plumbing" ) @@ -53,3 +55,83 @@ func (repo *Repository) GetTags(skip, limit int) ([]string, error) { return tagNames, nil } + +// GetTagType gets the type of the tag, either commit (simple) or tag (annotated) +func (repo *Repository) GetTagType(id SHA1) (string, error) { + // Get tag type + obj, err := repo.gogitRepo.Object(plumbing.AnyObject, id) + if err != nil { + if err == plumbing.ErrReferenceNotFound { + return "", &ErrNotExist{ID: id.String()} + } + return "", err + } + + return obj.Type().String(), nil +} + +func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) { + t, ok := repo.tagCache.Get(tagID.String()) + if ok { + log.Debug("Hit cache: %s", tagID) + tagClone := *t.(*Tag) + tagClone.Name = name // This is necessary because lightweight tags may have same id + return &tagClone, nil + } + + tp, err := repo.GetTagType(tagID) + if err != nil { + return nil, err + } + + // Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object + commitIDStr, err := repo.GetTagCommitID(name) + if err != nil { + // every tag should have a commit ID so return all errors + return nil, err + } + commitID, err := NewIDFromString(commitIDStr) + if err != nil { + return nil, err + } + + // If type is "commit, the tag is a lightweight tag + if ObjectType(tp) == ObjectCommit { + commit, err := repo.GetCommit(commitIDStr) + if err != nil { + return nil, err + } + tag := &Tag{ + Name: name, + ID: tagID, + Object: commitID, + Type: tp, + Tagger: commit.Committer, + Message: commit.Message(), + } + + repo.tagCache.Set(tagID.String(), tag) + return tag, nil + } + + gogitTag, err := repo.gogitRepo.TagObject(tagID) + if err != nil { + if err == plumbing.ErrReferenceNotFound { + return nil, &ErrNotExist{ID: tagID.String()} + } + + return nil, err + } + + tag := &Tag{ + Name: name, + ID: tagID, + Object: gogitTag.Target, + Type: tp, + Tagger: &gogitTag.Tagger, + Message: gogitTag.Message, + } + + repo.tagCache.Set(tagID.String(), tag) + return tag, nil +} diff --git a/modules/git/repo_tag_nogogit.go b/modules/git/repo_tag_nogogit.go index 1a23755aa6..f2da7d8857 100644 --- a/modules/git/repo_tag_nogogit.go +++ b/modules/git/repo_tag_nogogit.go @@ -8,6 +8,13 @@ package git +import ( + "errors" + "io" + + "code.gitea.io/gitea/modules/log" +) + // IsTagExist returns true if given tag exists in the repository. func (repo *Repository) IsTagExist(name string) bool { if name == "" { @@ -23,3 +30,104 @@ func (repo *Repository) GetTags(skip, limit int) (tags []string, err error) { tags, _, err = callShowRef(repo.Ctx, repo.Path, TagPrefix, "--tags", skip, limit) return } + +// GetTagType gets the type of the tag, either commit (simple) or tag (annotated) +func (repo *Repository) GetTagType(id SHA1) (string, error) { + wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx) + defer cancel() + _, err := wr.Write([]byte(id.String() + "\n")) + if err != nil { + return "", err + } + _, typ, _, err := ReadBatchLine(rd) + if IsErrNotExist(err) { + return "", ErrNotExist{ID: id.String()} + } + return typ, nil +} + +func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) { + t, ok := repo.tagCache.Get(tagID.String()) + if ok { + log.Debug("Hit cache: %s", tagID) + tagClone := *t.(*Tag) + tagClone.Name = name // This is necessary because lightweight tags may have same id + return &tagClone, nil + } + + tp, err := repo.GetTagType(tagID) + if err != nil { + return nil, err + } + + // Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object + commitIDStr, err := repo.GetTagCommitID(name) + if err != nil { + // every tag should have a commit ID so return all errors + return nil, err + } + commitID, err := NewIDFromString(commitIDStr) + if err != nil { + return nil, err + } + + // If type is "commit, the tag is a lightweight tag + if ObjectType(tp) == ObjectCommit { + commit, err := repo.GetCommit(commitIDStr) + if err != nil { + return nil, err + } + tag := &Tag{ + Name: name, + ID: tagID, + Object: commitID, + Type: tp, + Tagger: commit.Committer, + Message: commit.Message(), + } + + repo.tagCache.Set(tagID.String(), tag) + return tag, nil + } + + // The tag is an annotated tag with a message. + wr, rd, cancel := repo.CatFileBatch(repo.Ctx) + defer cancel() + + if _, err := wr.Write([]byte(tagID.String() + "\n")); err != nil { + return nil, err + } + _, typ, size, err := ReadBatchLine(rd) + if err != nil { + if errors.Is(err, io.EOF) || IsErrNotExist(err) { + return nil, ErrNotExist{ID: tagID.String()} + } + return nil, err + } + if typ != "tag" { + return nil, ErrNotExist{ID: tagID.String()} + } + + // then we need to parse the tag + // and load the commit + data, err := io.ReadAll(io.LimitReader(rd, size)) + if err != nil { + return nil, err + } + _, err = rd.Discard(1) + if err != nil { + return nil, err + } + + tag, err := parseTagData(data) + if err != nil { + return nil, err + } + + tag.Name = name + tag.ID = tagID + tag.Type = tp + + repo.tagCache.Set(tagID.String(), tag) + return tag, nil +} diff --git a/modules/git/repo_tag_test.go b/modules/git/repo_tag_test.go index f4d6726ea1..25fb8fcd9b 100644 --- a/modules/git/repo_tag_test.go +++ b/modules/git/repo_tag_test.go @@ -16,11 +16,17 @@ import ( func TestRepository_GetTags(t *testing.T) { bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") bareRepo1, err := OpenRepository(bareRepo1Path) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } defer bareRepo1.Close() tags, total, err := bareRepo1.GetTagInfos(0, 0) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } assert.Len(t, tags, 1) assert.Equal(t, len(tags), total) assert.EqualValues(t, "test", tags[0].Name) @@ -31,40 +37,75 @@ func TestRepository_GetTags(t *testing.T) { func TestRepository_GetTag(t *testing.T) { bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") - clonedPath, err := cloneRepo(bareRepo1Path, testReposDir, "repo1_TestRepository_GetTag") - assert.NoError(t, err) + clonedPath, err := cloneRepo(bareRepo1Path, "TestRepository_GetTag") + if err != nil { + assert.NoError(t, err) + return + } defer util.RemoveAll(clonedPath) bareRepo1, err := OpenRepository(clonedPath) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } defer bareRepo1.Close() + // LIGHTWEIGHT TAGS lTagCommitID := "6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1" lTagName := "lightweightTag" - bareRepo1.CreateTag(lTagName, lTagCommitID) - aTagCommitID := "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0" - aTagName := "annotatedTag" - aTagMessage := "my annotated message \n - test two line" - bareRepo1.CreateAnnotatedTag(aTagName, aTagMessage, aTagCommitID) - aTagID, _ := bareRepo1.GetTagID(aTagName) + // Create the lightweight tag + err = bareRepo1.CreateTag(lTagName, lTagCommitID) + if err != nil { + assert.NoError(t, err, "Unable to create the lightweight tag: %s for ID: %s. Error: %v", lTagName, lTagCommitID, err) + return + } + // and try to get the Tag for lightweight tag lTag, err := bareRepo1.GetTag(lTagName) - assert.NoError(t, err) - assert.NotNil(t, lTag) + if err != nil { + assert.NoError(t, err) + return + } if lTag == nil { + assert.NotNil(t, lTag) assert.FailNow(t, "nil lTag: %s", lTagName) + return } assert.EqualValues(t, lTagName, lTag.Name) assert.EqualValues(t, lTagCommitID, lTag.ID.String()) assert.EqualValues(t, lTagCommitID, lTag.Object.String()) assert.EqualValues(t, "commit", lTag.Type) + // ANNOTATED TAGS + aTagCommitID := "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0" + aTagName := "annotatedTag" + aTagMessage := "my annotated message \n - test two line" + + // Create the annotated tag + err = bareRepo1.CreateAnnotatedTag(aTagName, aTagMessage, aTagCommitID) + if err != nil { + assert.NoError(t, err, "Unable to create the annotated tag: %s for ID: %s. Error: %v", aTagName, aTagCommitID, err) + return + } + + // Now try to get the tag for the annotated Tag + aTagID, err := bareRepo1.GetTagID(aTagName) + if err != nil { + assert.NoError(t, err) + return + } + aTag, err := bareRepo1.GetTag(aTagName) - assert.NoError(t, err) - assert.NotNil(t, aTag) + if err != nil { + assert.NoError(t, err) + return + } if aTag == nil { + assert.NotNil(t, aTag) assert.FailNow(t, "nil aTag: %s", aTagName) + return } assert.EqualValues(t, aTagName, aTag.Name) assert.EqualValues(t, aTagID, aTag.ID.String()) @@ -72,26 +113,47 @@ func TestRepository_GetTag(t *testing.T) { assert.EqualValues(t, aTagCommitID, aTag.Object.String()) assert.EqualValues(t, "tag", aTag.Type) + // RELEASE TAGS + rTagCommitID := "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0" rTagName := "release/" + lTagName - bareRepo1.CreateTag(rTagName, rTagCommitID) + + err = bareRepo1.CreateTag(rTagName, rTagCommitID) + if err != nil { + assert.NoError(t, err, "Unable to create the tag: %s for ID: %s. Error: %v", rTagName, rTagCommitID, err) + return + } + rTagID, err := bareRepo1.GetTagID(rTagName) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } assert.EqualValues(t, rTagCommitID, rTagID) + oTagID, err := bareRepo1.GetTagID(lTagName) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } assert.EqualValues(t, lTagCommitID, oTagID) } func TestRepository_GetAnnotatedTag(t *testing.T) { bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") - clonedPath, err := cloneRepo(bareRepo1Path, testReposDir, "repo1_TestRepository_GetTag") - assert.NoError(t, err) + clonedPath, err := cloneRepo(bareRepo1Path, "TestRepository_GetAnnotatedTag") + if err != nil { + assert.NoError(t, err) + return + } defer util.RemoveAll(clonedPath) bareRepo1, err := OpenRepository(clonedPath) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } defer bareRepo1.Close() lTagCommitID := "6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1" @@ -106,7 +168,10 @@ func TestRepository_GetAnnotatedTag(t *testing.T) { // Try an annotated tag tag, err := bareRepo1.GetAnnotatedTag(aTagID) - assert.NoError(t, err) + if err != nil { + assert.NoError(t, err) + return + } assert.NotNil(t, tag) assert.EqualValues(t, aTagName, tag.Name) assert.EqualValues(t, aTagID, tag.ID.String()) diff --git a/modules/gitgraph/graph_models.go b/modules/gitgraph/graph_models.go index 44773a3b9a..653384252d 100644 --- a/modules/gitgraph/graph_models.go +++ b/modules/gitgraph/graph_models.go @@ -117,7 +117,7 @@ func (graph *Graph) LoadAndProcessCommits(repository *repo_model.Repository, git c.Verification = asymkey_model.ParseCommitWithSignature(c.Commit) _ = asymkey_model.CalculateTrustStatus(c.Verification, repository.GetTrustModel(), func(user *user_model.User) (bool, error) { - return models.IsUserRepoAdmin(repository, user) + return models.IsOwnerMemberCollaborator(repository, user.ID) }, &keyMap) statuses, _, err := models.GetLatestCommitStatus(repository.ID, c.Commit.ID.String(), db.ListOptions{}) diff --git a/modules/graceful/manager.go b/modules/graceful/manager.go index 8c3b95c4aa..fd8c878349 100644 --- a/modules/graceful/manager.go +++ b/modules/graceful/manager.go @@ -192,6 +192,7 @@ func (g *Manager) RunAtHammer(hammer func()) { } func (g *Manager) doShutdown() { if !g.setStateTransition(stateRunning, stateShuttingDown) { + g.DoImmediateHammer() return } g.lock.Lock() diff --git a/modules/graceful/manager_unix.go b/modules/graceful/manager_unix.go index fcbb16a3bb..99e84d73e8 100644 --- a/modules/graceful/manager_unix.go +++ b/modules/graceful/manager_unix.go @@ -168,8 +168,12 @@ func (g *Manager) DoGracefulRestart() { if setting.GracefulRestartable { log.Info("PID: %d. Forking...", os.Getpid()) err := g.doFork() - if err != nil && err.Error() != "another process already forked. Ignoring this one" { - log.Error("Error whilst forking from PID: %d : %v", os.Getpid(), err) + if err != nil { + if err.Error() == "another process already forked. Ignoring this one" { + g.DoImmediateHammer() + } else { + log.Error("Error whilst forking from PID: %d : %v", os.Getpid(), err) + } } } else { log.Info("PID: %d. Not set restartable. Shutting down...", os.Getpid()) diff --git a/modules/highlight/highlight_test.go b/modules/highlight/highlight_test.go index 3f47b6a48f..2f305bb589 100644 --- a/modules/highlight/highlight_test.go +++ b/modules/highlight/highlight_test.go @@ -40,20 +40,19 @@ steps: - go test -v -race -coverprofile=coverage.txt -covermode=atomic `, want: []string{ - `kind: pipeline`, - `name: default`, - ` -`, - `steps:`, - `- name: test`, - ` image: golang:1.13`, - ` environment:`, - ` GOPROXY: https://goproxy.cn`, - ` commands:`, - ` - go get -u`, - ` - go build -v`, - ` - go test -v -race -coverprofile=coverage.txt -covermode=atomic -`, + `kind: pipeline`, + `name: default`, + ``, + `steps:`, + `- name: test`, + ` image: golang:1.13`, + ` environment:`, + ` GOPROXY: https://goproxy.cn`, + ` commands:`, + ` - go get -u`, + ` - go build -v`, + ` - go test -v -race -coverprofile=coverage.txt -covermode=atomic +`, ` `, }, @@ -76,20 +75,19 @@ steps: - go test -v -race -coverprofile=coverage.txt -covermode=atomic `, want: []string{ - `kind: pipeline`, - `name: default `, - ` -`, - `steps:`, - `- name: test`, - ` image: golang:1.13`, - ` environment:`, - ` GOPROXY: https://goproxy.cn`, - ` commands:`, - ` - go get -u`, - ` - go build -v`, - ` - go test -v -race -coverprofile=coverage.txt -covermode=atomic`, - ` `, + `kind: pipeline`, + `name: default `, + ``, + `steps:`, + `- name: test`, + ` image: golang:1.13`, + ` environment:`, + ` GOPROXY: https://goproxy.cn`, + ` commands:`, + ` - go get -u`, + ` - go build -v`, + ` - go test -v -race -coverprofile=coverage.txt -covermode=atomic`, + ` `, }, }, } diff --git a/modules/hostmatcher/hostmatcher.go b/modules/hostmatcher/hostmatcher.go index 9492a479f1..744c5060a3 100644 --- a/modules/hostmatcher/hostmatcher.go +++ b/modules/hostmatcher/hostmatcher.go @@ -127,13 +127,18 @@ func (hl *HostMatchList) checkIP(ip net.IP) bool { // MatchHostName checks if the host matches an allow/deny(block) list func (hl *HostMatchList) MatchHostName(host string) bool { + hostname, _, err := net.SplitHostPort(host) + if err != nil { + hostname = host + } + if hl == nil { return false } - if hl.checkPattern(host) { + if hl.checkPattern(hostname) { return true } - if ip := net.ParseIP(host); ip != nil { + if ip := net.ParseIP(hostname); ip != nil { return hl.checkIP(ip) } return false diff --git a/modules/hostmatcher/hostmatcher_test.go b/modules/hostmatcher/hostmatcher_test.go index 66030a32f1..b93976df6a 100644 --- a/modules/hostmatcher/hostmatcher_test.go +++ b/modules/hostmatcher/hostmatcher_test.go @@ -38,6 +38,7 @@ func TestHostOrIPMatchesList(t *testing.T) { {"", net.ParseIP("10.0.1.1"), true}, {"10.0.1.1", nil, true}, + {"10.0.1.1:8080", nil, true}, {"", net.ParseIP("192.168.1.1"), true}, {"192.168.1.1", nil, true}, {"", net.ParseIP("fd00::1"), true}, @@ -48,6 +49,7 @@ func TestHostOrIPMatchesList(t *testing.T) { {"mydomain.com", net.IPv4zero, false}, {"sub.mydomain.com", net.IPv4zero, true}, + {"sub.mydomain.com:8080", net.IPv4zero, true}, {"", net.ParseIP("169.254.1.1"), true}, {"169.254.1.1", nil, true}, diff --git a/modules/indexer/code/indexer.go b/modules/indexer/code/indexer.go index a616d0e662..983f4843a6 100644 --- a/modules/indexer/code/indexer.go +++ b/modules/indexer/code/indexer.go @@ -130,7 +130,7 @@ func Init() { log.Info("PID: %d Repository Indexer closed", os.Getpid()) }) - waitChannel := make(chan time.Duration) + waitChannel := make(chan time.Duration, 1) // Create the Queue switch setting.Indexer.RepoType { diff --git a/modules/indexer/issues/indexer.go b/modules/indexer/issues/indexer.go index 4db5091762..d7f7386524 100644 --- a/modules/indexer/issues/indexer.go +++ b/modules/indexer/issues/indexer.go @@ -98,7 +98,7 @@ var ( // InitIssueIndexer initialize issue indexer, syncReindex is true then reindex until // all issue index done. func InitIssueIndexer(syncReindex bool) { - waitChannel := make(chan time.Duration) + waitChannel := make(chan time.Duration, 1) // Create the Queue switch setting.Indexer.IssueType { @@ -272,7 +272,7 @@ func populateIssueIndexer(ctx context.Context) { // UpdateRepoIndexer add/update all issues of the repositories func UpdateRepoIndexer(repo *repo_model.Repository) { is, err := models.Issues(&models.IssuesOptions{ - RepoIDs: []int64{repo.ID}, + RepoID: repo.ID, IsClosed: util.OptionalBoolNone, IsPull: util.OptionalBoolNone, }) diff --git a/modules/indexer/stats/indexer_test.go b/modules/indexer/stats/indexer_test.go index 50c6cc38e9..b5c58ab25a 100644 --- a/modules/indexer/stats/indexer_test.go +++ b/modules/indexer/stats/indexer_test.go @@ -5,12 +5,15 @@ package stats import ( + "context" "path/filepath" "testing" "time" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" _ "code.gitea.io/gitea/models" @@ -24,6 +27,10 @@ func TestMain(m *testing.M) { } func TestRepoStatsIndex(t *testing.T) { + if err := git.Init(context.Background()); !assert.NoError(t, err) { + return + } + assert.NoError(t, unittest.PrepareTestDatabase()) setting.Cfg = ini.Empty() @@ -32,10 +39,14 @@ func TestRepoStatsIndex(t *testing.T) { err := Init() assert.NoError(t, err) - time.Sleep(5 * time.Second) - repo, err := repo_model.GetRepositoryByID(1) assert.NoError(t, err) + + err = UpdateRepoIndexer(repo) + assert.NoError(t, err) + + queue.GetManager().FlushAll(context.Background(), 5*time.Second) + status, err := repo_model.GetIndexerStatus(repo, repo_model.RepoIndexerTypeStats) assert.NoError(t, err) assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", status.CommitSha) diff --git a/modules/lfs/pointer.go b/modules/lfs/pointer.go index 975b5e7dc6..2a3a2116b4 100644 --- a/modules/lfs/pointer.go +++ b/modules/lfs/pointer.go @@ -14,6 +14,8 @@ import ( "regexp" "strconv" "strings" + + "code.gitea.io/gitea/modules/log" ) const ( @@ -111,6 +113,17 @@ func (p Pointer) RelativePath() string { return path.Join(p.Oid[0:2], p.Oid[2:4], p.Oid[4:]) } +// ColorFormat provides a basic color format for a Team +func (p Pointer) ColorFormat(s fmt.State) { + if p.Oid == "" && p.Size == 0 { + log.ColorFprintf(s, "") + return + } + log.ColorFprintf(s, "%s:%d", + log.NewColoredIDValue(p.Oid), + p.Size) +} + // GeneratePointer generates a pointer for arbitrary content func GeneratePointer(content io.Reader) (Pointer, error) { h := sha256.New() diff --git a/modules/markup/common/footnote.go b/modules/markup/common/footnote.go index 92a54101f0..1621c7f15f 100644 --- a/modules/markup/common/footnote.go +++ b/modules/markup/common/footnote.go @@ -205,7 +205,7 @@ func (b *footnoteBlockParser) Open(parent ast.Node, reader text.Reader, pc parse } open := pos + 1 closes := 0 - closure := util.FindClosure(line[pos+1:], '[', ']', false, false) + closure := util.FindClosure(line[pos+1:], '[', ']', false, false) //nolint closes = pos + 1 + closure next := closes + 1 if closure > -1 { @@ -296,7 +296,7 @@ func (s *footnoteParser) Parse(parent ast.Node, block text.Reader, pc parser.Con return nil } open := pos - closure := util.FindClosure(line[pos:], '[', ']', false, false) + closure := util.FindClosure(line[pos:], '[', ']', false, false) //nolint if closure < 0 { return nil } diff --git a/modules/markup/external/external.go b/modules/markup/external/external.go index 3acb601067..0f9d7935d3 100644 --- a/modules/markup/external/external.go +++ b/modules/markup/external/external.go @@ -119,6 +119,8 @@ func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io. cmd.Stdin = input } cmd.Stdout = output + process.SetSysProcAttribute(cmd) + if err := cmd.Run(); err != nil { return fmt.Errorf("%s render run command %s %v failed: %v", p.Name(), commands[0], args, err) } diff --git a/modules/markup/html.go b/modules/markup/html.go index 827be1a9af..52430a83e4 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -55,7 +55,7 @@ var ( anySHA1Pattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40})(/[-+~_%.a-zA-Z0-9/]+)?(#[-+~_%.a-zA-Z0-9]+)?`) // comparePattern matches "http://domain/org/repo/compare/COMMIT1...COMMIT2#hash" - comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40})(\.\.\.?)([0-9a-f]{40})?(#[-+~_%.a-zA-Z0-9]+)?`) + comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,40})(\.\.\.?)([0-9a-f]{7,40})?(#[-+~_%.a-zA-Z0-9]+)?`) validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`) @@ -99,7 +99,7 @@ var issueFullPatternOnce sync.Once func getIssueFullPattern() *regexp.Regexp { issueFullPatternOnce.Do(func() { issueFullPattern = regexp.MustCompile(regexp.QuoteMeta(setting.AppURL) + - `\w+/\w+/(?:issues|pulls)/((?:\w{1,10}-)?[1-9][0-9]*)([\?|#](\S+)?)?\b`) + `[\w_.-]+/[\w_.-]+/(?:issues|pulls)/((?:\w{1,10}-)?[1-9][0-9]*)([\?|#](\S+)?)?\b`) }) return issueFullPattern } @@ -944,6 +944,13 @@ func comparePatternProcessor(ctx *RenderContext, node *html.Node) { return } + // Ensure that every group (m[0]...m[7]) has a match + for i := 0; i < 8; i++ { + if m[i] == -1 { + return + } + } + urlFull := node.Data[m[0]:m[1]] text1 := base.ShortSha(node.Data[m[2]:m[3]]) textDots := base.ShortSha(node.Data[m[4]:m[5]]) diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 3fd9ef9f83..879e69fc0e 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -95,6 +95,15 @@ func TestRender_CrossReferences(t *testing.T) { test( "/home/gitea/go-gitea/gitea#12345", `

/home/gitea/go-gitea/gitea#12345

`) + test( + util.URLJoin(TestAppURL, "gogitea", "gitea", "issues", "12345"), + `

gogitea/gitea#12345

`) + test( + util.URLJoin(TestAppURL, "go-gitea", "gitea", "issues", "12345"), + `

go-gitea/gitea#12345

`) + test( + util.URLJoin(TestAppURL, "gogitea", "some-repo-name", "issues", "12345"), + `

gogitea/some-repo-name#12345

`) } func TestMisc_IsSameDomain(t *testing.T) { @@ -546,3 +555,16 @@ func TestFuzz(t *testing.T) { assert.NoError(t, err) } + +func TestIssue18471(t *testing.T) { + data := `http://domain/org/repo/compare/783b039...da951ce` + + var res strings.Builder + err := PostProcess(&RenderContext{ + URLPrefix: "https://example.com", + Metas: localMetas, + }, strings.NewReader(data), &res) + + assert.NoError(t, err) + assert.Equal(t, res.String(), "783b039...da951ce") +} diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 083484813a..3aa433a1f2 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -197,6 +197,11 @@ func testAnswers(baseURLContent, baseURLImages string) []string { +`, `
    +
  • If you want to rebase/retry this PR, click this checkbox.
  • +
+
+

This PR has been generated by Renovate Bot.

`, } } @@ -269,6 +274,14 @@ Here is a simple footnote,[^1] and here is a longer one.[^bignote] Add as many paragraphs as you like. `, + ` +- [ ] If you want to rebase/retry this PR, click this checkbox. + +--- + +This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). + +`, } func TestTotal_RenderWiki(t *testing.T) { diff --git a/modules/markup/orgmode/orgmode_test.go b/modules/markup/orgmode/orgmode_test.go index 81d0d66a76..38c010ef68 100644 --- a/modules/markup/orgmode/orgmode_test.go +++ b/modules/markup/orgmode/orgmode_test.go @@ -77,9 +77,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/nosql/manager_leveldb.go b/modules/nosql/manager_leveldb.go index eeb0cf74d9..97f917af78 100644 --- a/modules/nosql/manager_leveldb.go +++ b/modules/nosql/manager_leveldb.go @@ -5,10 +5,12 @@ package nosql import ( + "fmt" "path" "strconv" "strings" + "code.gitea.io/gitea/modules/log" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/errors" "github.com/syndtr/goleveldb/leveldb/opt" @@ -20,8 +22,16 @@ func (m *Manager) CloseLevelDB(connection string) error { defer m.mutex.Unlock() db, ok := m.LevelDBConnections[connection] if !ok { - connection = ToLevelDBURI(connection).String() - db, ok = m.LevelDBConnections[connection] + // Try the full URI + uri := ToLevelDBURI(connection) + db, ok = m.LevelDBConnections[uri.String()] + + if !ok { + // Try the datadir directly + dataDir := path.Join(uri.Host, uri.Path) + + db, ok = m.LevelDBConnections[dataDir] + } } if !ok { return nil @@ -40,6 +50,12 @@ func (m *Manager) CloseLevelDB(connection string) error { // GetLevelDB gets a levelDB for a particular connection func (m *Manager) GetLevelDB(connection string) (*leveldb.DB, error) { + // Convert the provided connection description to the common format + uri := ToLevelDBURI(connection) + + // Get the datadir + dataDir := path.Join(uri.Host, uri.Path) + m.mutex.Lock() defer m.mutex.Unlock() db, ok := m.LevelDBConnections[connection] @@ -48,12 +64,28 @@ func (m *Manager) GetLevelDB(connection string) (*leveldb.DB, error) { return db.db, nil } - uri := ToLevelDBURI(connection) - db = &levelDBHolder{ - name: []string{connection, uri.String()}, + + db, ok = m.LevelDBConnections[uri.String()] + if ok { + db.count++ + + return db.db, nil + } + + // if there is already a connection to this leveldb reuse that + // NOTE: if there differing options then only the first leveldb connection will be used + db, ok = m.LevelDBConnections[dataDir] + if ok { + db.count++ + log.Warn("Duplicate connnection to level db: %s with different connection strings. Initial connection: %s. This connection: %s", dataDir, db.name[0], connection) + db.name = append(db.name, connection) + m.LevelDBConnections[connection] = db + return db.db, nil + } + db = &levelDBHolder{ + name: []string{connection, uri.String(), dataDir}, } - dataDir := path.Join(uri.Host, uri.Path) opts := &opt.Options{} for k, v := range uri.Query() { switch replacer.Replace(strings.ToLower(k)) { @@ -134,7 +166,11 @@ func (m *Manager) GetLevelDB(connection string) (*leveldb.DB, error) { db.db, err = leveldb.OpenFile(dataDir, opts) if err != nil { if !errors.IsCorrupted(err) { - return nil, err + if strings.Contains(err.Error(), "resource temporarily unavailable") { + return nil, fmt.Errorf("unable to lock level db at %s: %w", dataDir, err) + } + + return nil, fmt.Errorf("unable to open level db at %s: %w", dataDir, err) } db.db, err = leveldb.RecoverFile(dataDir, opts) if err != nil { diff --git a/modules/notification/mail/mail.go b/modules/notification/mail/mail.go index 6ad0ca0d85..4609e513a5 100644 --- a/modules/notification/mail/mail.go +++ b/modules/notification/mail/mail.go @@ -115,7 +115,7 @@ func (m *mailNotifier) NotifyPullRequestCodeComment(pr *models.PullRequest, comm func (m *mailNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) { // mail only sent to added assignees and not self-assignee - if !removed && doer.ID != assignee.ID && assignee.EmailNotifications() == user_model.EmailNotificationsEnabled { + if !removed && doer.ID != assignee.ID && (assignee.EmailNotifications() == user_model.EmailNotificationsEnabled || assignee.EmailNotifications() == user_model.EmailNotificationsOnMention) { ct := fmt.Sprintf("Assigned #%d.", issue.Index) if err := mailer.SendIssueAssignedMail(issue, doer, ct, comment, []*user_model.User{assignee}); err != nil { log.Error("Error in SendIssueAssignedMail for issue[%d] to assignee[%d]: %v", issue.ID, assignee.ID, err) @@ -124,7 +124,7 @@ func (m *mailNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *m } func (m *mailNotifier) NotifyPullReviewRequest(doer *user_model.User, issue *models.Issue, reviewer *user_model.User, isRequest bool, comment *models.Comment) { - if isRequest && doer.ID != reviewer.ID && reviewer.EmailNotifications() == user_model.EmailNotificationsEnabled { + if isRequest && doer.ID != reviewer.ID && (reviewer.EmailNotifications() == user_model.EmailNotificationsEnabled || reviewer.EmailNotifications() == user_model.EmailNotificationsOnMention) { ct := fmt.Sprintf("Requested to review %s.", issue.HTMLURL()) if err := mailer.SendIssueAssignedMail(issue, doer, ct, comment, []*user_model.User{reviewer}); err != nil { log.Error("Error in SendIssueAssignedMail for issue[%d] to reviewer[%d]: %v", issue.ID, reviewer.ID, err) diff --git a/modules/notification/ui/ui.go b/modules/notification/ui/ui.go index fd44cd15fd..8461707120 100644 --- a/modules/notification/ui/ui.go +++ b/modules/notification/ui/ui.go @@ -204,7 +204,7 @@ func (ns *notificationService) NotifyPullRevieweDismiss(doer *user_model.User, r } func (ns *notificationService) NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) { - if !removed { + if !removed && doer.ID != assignee.ID { var opts = issueNotificationOpts{ IssueID: issue.ID, NotificationAuthorID: doer.ID, diff --git a/modules/private/hook.go b/modules/private/hook.go index fd864b1e6b..559019344e 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -56,7 +56,7 @@ type HookOptions struct { GitQuarantinePath string GitPushOptions GitPushOptions PullRequestID int64 - IsDeployKey bool + DeployKeyID int64 // if the pusher is a DeployKey, then UserID is the repo's org user. IsWiki bool } diff --git a/modules/private/serv.go b/modules/private/serv.go index a7a56df7b3..2b52215573 100644 --- a/modules/private/serv.go +++ b/modules/private/serv.go @@ -46,9 +46,9 @@ func ServNoCommand(ctx context.Context, keyID int64) (*asymkey_model.PublicKey, // ServCommandResults are the results of a call to the private route serv type ServCommandResults struct { IsWiki bool - IsDeployKey bool - KeyID int64 - KeyName string + DeployKeyID int64 + KeyID int64 // public key + KeyName string // this field is ambiguous, it can be the name of DeployKey, or the name of the PublicKey UserName string UserEmail string UserID int64 diff --git a/modules/process/manager.go b/modules/process/manager.go index 7cde9f9451..0522b2f5d9 100644 --- a/modules/process/manager.go +++ b/modules/process/manager.go @@ -254,13 +254,13 @@ func (pm *Manager) ExecDirEnvStdIn(timeout time.Duration, dir, desc string, env if stdIn != nil { cmd.Stdin = stdIn } + SetSysProcAttribute(cmd) if err := cmd.Start(); err != nil { return "", "", err } err := cmd.Wait() - if err != nil { err = &Error{ PID: GetPID(ctx), diff --git a/modules/process/manager_unix.go b/modules/process/manager_unix.go new file mode 100644 index 0000000000..2ed8009eec --- /dev/null +++ b/modules/process/manager_unix.go @@ -0,0 +1,19 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +//go:build !windows +// +build !windows + +package process + +import ( + "os/exec" + "syscall" +) + +// SetSysProcAttribute sets the common SysProcAttrs for commands +func SetSysProcAttribute(cmd *exec.Cmd) { + // When Gitea runs SubProcessA -> SubProcessB and SubProcessA gets killed by context timeout, use setpgid to make sure the sub processes can be reaped instead of leaving defunct(zombie) processes. + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} +} diff --git a/modules/process/manager_windows.go b/modules/process/manager_windows.go new file mode 100644 index 0000000000..892275382a --- /dev/null +++ b/modules/process/manager_windows.go @@ -0,0 +1,17 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +//go:build windows +// +build windows + +package process + +import ( + "os/exec" +) + +// SetSysProcAttribute sets the common SysProcAttrs for commands +func SetSysProcAttribute(cmd *exec.Cmd) { + // Do nothing +} diff --git a/modules/public/mime_types.go b/modules/public/mime_types.go new file mode 100644 index 0000000000..f8c92e824f --- /dev/null +++ b/modules/public/mime_types.go @@ -0,0 +1,41 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package public + +import "strings" + +// wellKnownMimeTypesLower comes from Golang's builtin mime package: `builtinTypesLower`, see the comment of detectWellKnownMimeType +var wellKnownMimeTypesLower = map[string]string{ + ".avif": "image/avif", + ".css": "text/css; charset=utf-8", + ".gif": "image/gif", + ".htm": "text/html; charset=utf-8", + ".html": "text/html; charset=utf-8", + ".jpeg": "image/jpeg", + ".jpg": "image/jpeg", + ".js": "text/javascript; charset=utf-8", + ".json": "application/json", + ".mjs": "text/javascript; charset=utf-8", + ".pdf": "application/pdf", + ".png": "image/png", + ".svg": "image/svg+xml", + ".wasm": "application/wasm", + ".webp": "image/webp", + ".xml": "text/xml; charset=utf-8", + + // well, there are some types missing from the builtin list + ".txt": "text/plain; charset=utf-8", +} + +// detectWellKnownMimeType will return the mime-type for a well-known file ext name +// The purpose of this function is to bypass the unstable behavior of Golang's mime.TypeByExtension +// mime.TypeByExtension would use OS's mime-type config to overwrite the well-known types (see its document). +// If the user's OS has incorrect mime-type config, it would make Gitea can not respond a correct Content-Type to browsers. +// For example, if Gitea returns `text/plain` for a `.js` file, the browser couldn't run the JS due to security reasons. +// detectWellKnownMimeType makes the Content-Type for well-known files stable. +func detectWellKnownMimeType(ext string) string { + ext = strings.ToLower(ext) + return wellKnownMimeTypesLower[ext] +} diff --git a/modules/public/public.go b/modules/public/public.go index a58709d86f..6dd9b54e64 100644 --- a/modules/public/public.go +++ b/modules/public/public.go @@ -95,6 +95,15 @@ func parseAcceptEncoding(val string) map[string]bool { return types } +// setWellKnownContentType will set the Content-Type if the file is a well-known type. +// See the comments of detectWellKnownMimeType +func setWellKnownContentType(w http.ResponseWriter, file string) { + mimeType := detectWellKnownMimeType(filepath.Ext(file)) + if mimeType != "" { + w.Header().Set("Content-Type", mimeType) + } +} + func (opts *Options) handle(w http.ResponseWriter, req *http.Request, fs http.FileSystem, file string) bool { // use clean to keep the file is a valid path with no . or .. f, err := fs.Open(path.Clean(file)) @@ -125,6 +134,8 @@ func (opts *Options) handle(w http.ResponseWriter, req *http.Request, fs http.Fi return true } + setWellKnownContentType(w, file) + serveContent(w, req, fi, fi.ModTime(), f) return true } diff --git a/modules/public/dynamic.go b/modules/public/serve_dynamic.go similarity index 100% rename from modules/public/dynamic.go rename to modules/public/serve_dynamic.go diff --git a/modules/public/static.go b/modules/public/serve_static.go similarity index 68% rename from modules/public/static.go rename to modules/public/serve_static.go index a81efacfa4..28975ec6c3 100644 --- a/modules/public/static.go +++ b/modules/public/serve_static.go @@ -9,15 +9,12 @@ package public import ( "bytes" - "compress/gzip" "io" - "mime" "net/http" "os" "path/filepath" "time" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" ) @@ -66,24 +63,16 @@ func serveContent(w http.ResponseWriter, req *http.Request, fi os.FileInfo, modt encodings := parseAcceptEncoding(req.Header.Get("Accept-Encoding")) if encodings["gzip"] { if cf, ok := fi.(*vfsgen۰CompressedFileInfo); ok { - rd := bytes.NewReader(cf.GzipBytes()) - w.Header().Set("Content-Encoding", "gzip") - ctype := mime.TypeByExtension(filepath.Ext(fi.Name())) - if ctype == "" { - // read a chunk to decide between utf-8 text and binary - var buf [512]byte - grd, _ := gzip.NewReader(rd) - n, _ := io.ReadFull(grd, buf[:]) - ctype = http.DetectContentType(buf[:n]) - _, err := rd.Seek(0, io.SeekStart) // rewind to output whole file - if err != nil { - log.Error("rd.Seek error: %v", err) - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - return - } + rdGzip := bytes.NewReader(cf.GzipBytes()) + // all static files are managed by Gitea, so we can make sure every file has the correct ext name + // then we can get the correct Content-Type, we do not need to do http.DetectContentType on the decompressed data + mimeType := detectWellKnownMimeType(filepath.Ext(fi.Name())) + if mimeType == "" { + mimeType = "application/octet-stream" } - w.Header().Set("Content-Type", ctype) - http.ServeContent(w, req, fi.Name(), modtime, rd) + w.Header().Set("Content-Type", mimeType) + w.Header().Set("Content-Encoding", "gzip") + http.ServeContent(w, req, fi.Name(), modtime, rdGzip) return } } diff --git a/modules/queue/manager.go b/modules/queue/manager.go index 23e96155a9..310f3cd4e1 100644 --- a/modules/queue/manager.go +++ b/modules/queue/manager.go @@ -72,6 +72,8 @@ type ManagedPool interface { BoostWorkers() int // SetPoolSettings sets the user updatable settings for the pool SetPoolSettings(maxNumberOfWorkers, boostWorkers int, timeout time.Duration) + // Done returns a channel that will be closed when the Pool's baseCtx is closed + Done() <-chan struct{} } // ManagedQueueList implements the sort.Interface @@ -141,7 +143,6 @@ func (m *Manager) Remove(qid int64) { delete(m.Queues, qid) m.mutex.Unlock() log.Trace("Queue Manager removed: QID: %d", qid) - } // GetManagedQueue by qid @@ -193,6 +194,17 @@ func (m *Manager) FlushAll(baseCtx context.Context, timeout time.Duration) error wg.Done() continue } + + if pool, ok := mq.Managed.(ManagedPool); ok { + // No point into flushing pools when their base's ctx is already done. + select { + case <-pool.Done(): + wg.Done() + continue + default: + } + } + allEmpty = false if flushable, ok := mq.Managed.(Flushable); ok { log.Debug("Flushing (flushable) queue: %s", mq.Name) @@ -225,7 +237,6 @@ func (m *Manager) FlushAll(baseCtx context.Context, timeout time.Duration) error wg.Wait() } return nil - } // ManagedQueues returns the managed queues diff --git a/modules/queue/queue_bytefifo.go b/modules/queue/queue_bytefifo.go index edde47a62d..c4d5d20a89 100644 --- a/modules/queue/queue_bytefifo.go +++ b/modules/queue/queue_bytefifo.go @@ -195,9 +195,11 @@ loop: } } -var errQueueEmpty = fmt.Errorf("empty queue") -var errEmptyBytes = fmt.Errorf("empty bytes") -var errUnmarshal = fmt.Errorf("failed to unmarshal") +var ( + errQueueEmpty = fmt.Errorf("empty queue") + errEmptyBytes = fmt.Errorf("empty bytes") + errUnmarshal = fmt.Errorf("failed to unmarshal") +) func (q *ByteFIFOQueue) doPop() error { q.lock.Lock() diff --git a/modules/queue/queue_disk_channel.go b/modules/queue/queue_disk_channel.go index c3a1c5781e..199f958bc3 100644 --- a/modules/queue/queue_disk_channel.go +++ b/modules/queue/queue_disk_channel.go @@ -173,7 +173,6 @@ func (q *PersistableChannelQueue) Run(atShutdown, atTerminate func(func())) { q.internal.(*LevelQueue).Shutdown() GetManager().Remove(q.internal.(*LevelQueue).qid) } - } // Flush flushes the queue and blocks till the queue is empty @@ -252,14 +251,13 @@ func (q *PersistableChannelQueue) Shutdown() { q.channelQueue.Wait() q.internal.(*LevelQueue).Wait() // Redirect all remaining data in the chan to the internal channel - go func() { - log.Trace("PersistableChannelQueue: %s Redirecting remaining data", q.delayedStarter.name) - for data := range q.channelQueue.dataChan { - _ = q.internal.Push(data) - atomic.AddInt64(&q.channelQueue.numInQueue, -1) - } - log.Trace("PersistableChannelQueue: %s Done Redirecting remaining data", q.delayedStarter.name) - }() + log.Trace("PersistableChannelQueue: %s Redirecting remaining data", q.delayedStarter.name) + close(q.channelQueue.dataChan) + for data := range q.channelQueue.dataChan { + _ = q.internal.Push(data) + atomic.AddInt64(&q.channelQueue.numInQueue, -1) + } + log.Trace("PersistableChannelQueue: %s Done Redirecting remaining data", q.delayedStarter.name) log.Debug("PersistableChannelQueue: %s Shutdown", q.delayedStarter.name) } diff --git a/modules/queue/queue_disk_channel_test.go b/modules/queue/queue_disk_channel_test.go index c90d715a73..db12d9575c 100644 --- a/modules/queue/queue_disk_channel_test.go +++ b/modules/queue/queue_disk_channel_test.go @@ -188,5 +188,4 @@ func TestPersistableChannelQueue(t *testing.T) { for _, callback := range callbacks { callback() } - } diff --git a/modules/queue/unique_queue_disk_channel.go b/modules/queue/unique_queue_disk_channel.go index af42c0913d..975421a339 100644 --- a/modules/queue/unique_queue_disk_channel.go +++ b/modules/queue/unique_queue_disk_channel.go @@ -238,13 +238,12 @@ func (q *PersistableChannelUniqueQueue) Shutdown() { q.channelQueue.Wait() q.internal.(*LevelUniqueQueue).Wait() // Redirect all remaining data in the chan to the internal channel - go func() { - log.Trace("PersistableChannelUniqueQueue: %s Redirecting remaining data", q.delayedStarter.name) - for data := range q.channelQueue.dataChan { - _ = q.internal.Push(data) - } - log.Trace("PersistableChannelUniqueQueue: %s Done Redirecting remaining data", q.delayedStarter.name) - }() + close(q.channelQueue.dataChan) + log.Trace("PersistableChannelUniqueQueue: %s Redirecting remaining data", q.delayedStarter.name) + for data := range q.channelQueue.dataChan { + _ = q.internal.Push(data) + } + log.Trace("PersistableChannelUniqueQueue: %s Done Redirecting remaining data", q.delayedStarter.name) log.Debug("PersistableChannelUniqueQueue: %s Shutdown", q.delayedStarter.name) } diff --git a/modules/queue/workerpool.go b/modules/queue/workerpool.go index 0176e2e0b2..5f52fef588 100644 --- a/modules/queue/workerpool.go +++ b/modules/queue/workerpool.go @@ -19,6 +19,10 @@ import ( // they use to detect if there is a block and will grow and shrink in // response to demand as per configuration. type WorkerPool struct { + // This field requires to be the first one in the struct. + // This is to allow 64 bit atomic operations on 32-bit machines. + // See: https://pkg.go.dev/sync/atomic#pkg-note-BUG & Gitea issue 19518 + numInQueue int64 lock sync.Mutex baseCtx context.Context baseCtxCancel context.CancelFunc @@ -32,7 +36,6 @@ type WorkerPool struct { blockTimeout time.Duration boostTimeout time.Duration boostWorkers int - numInQueue int64 } // WorkerPoolConfiguration is the basic configuration for a WorkerPool @@ -65,6 +68,11 @@ func NewWorkerPool(handle HandlerFunc, config WorkerPoolConfiguration) *WorkerPo return pool } +// Done returns when this worker pool's base context has been cancelled +func (p *WorkerPool) Done() <-chan struct{} { + return p.baseCtx.Done() +} + // Push pushes the data to the internal channel func (p *WorkerPool) Push(data Data) { atomic.AddInt64(&p.numInQueue, 1) @@ -82,6 +90,20 @@ func (p *WorkerPool) Push(data Data) { } } +// HasNoWorkerScaling will return true if the queue has no workers, and has no worker boosting +func (p *WorkerPool) HasNoWorkerScaling() bool { + p.lock.Lock() + defer p.lock.Unlock() + return p.hasNoWorkerScaling() +} + +func (p *WorkerPool) hasNoWorkerScaling() bool { + return p.numberOfWorkers == 0 && (p.boostTimeout == 0 || p.boostWorkers == 0 || p.maxNumberOfWorkers == 0) +} + +// zeroBoost will add a temporary boost worker for a no worker queue +// p.lock must be locked at the start of this function BUT it will be unlocked by the end of this function +// (This is because addWorkers has to be called whilst unlocked) func (p *WorkerPool) zeroBoost() { ctx, cancel := context.WithTimeout(p.baseCtx, p.boostTimeout) mq := GetManager().GetManagedQueue(p.qid) @@ -90,7 +112,7 @@ func (p *WorkerPool) zeroBoost() { boost = p.maxNumberOfWorkers - p.numberOfWorkers } if mq != nil { - log.Warn("WorkerPool: %d (for %s) has zero workers - adding %d temporary workers for %s", p.qid, mq.Name, boost, p.boostTimeout) + log.Debug("WorkerPool: %d (for %s) has zero workers - adding %d temporary workers for %s", p.qid, mq.Name, boost, p.boostTimeout) start := time.Now() pid := mq.RegisterWorkers(boost, start, true, start.Add(p.boostTimeout), cancel, false) @@ -98,7 +120,7 @@ func (p *WorkerPool) zeroBoost() { mq.RemoveWorkers(pid) } } else { - log.Warn("WorkerPool: %d has zero workers - adding %d temporary workers for %s", p.qid, p.boostWorkers, p.boostTimeout) + log.Debug("WorkerPool: %d has zero workers - adding %d temporary workers for %s", p.qid, p.boostWorkers, p.boostTimeout) } p.lock.Unlock() p.addWorkers(ctx, cancel, boost) @@ -272,6 +294,21 @@ func (p *WorkerPool) addWorkers(ctx context.Context, cancel context.CancelFunc, p.cond.Broadcast() cancel() } + + select { + case <-p.baseCtx.Done(): + // Don't warn if the baseCtx is shutdown + default: + if p.hasNoWorkerScaling() { + log.Warn( + "Queue: %d is configured to be non-scaling and has no workers - this configuration is likely incorrect.", p.qid) + } else if p.numberOfWorkers == 0 && atomic.LoadInt64(&p.numInQueue) > 0 { + // OK there are no workers but... there's still work to be done -> Reboost + p.zeroBoost() + // p.lock will be unlocked by zeroBoost + return + } + } p.lock.Unlock() }() } @@ -326,7 +363,10 @@ func (p *WorkerPool) FlushWithContext(ctx context.Context) error { log.Trace("WorkerPool: %d Flush", p.qid) for { select { - case data := <-p.dataChan: + case data, ok := <-p.dataChan: + if !ok { + return nil + } p.handle(data) atomic.AddInt64(&p.numInQueue, -1) case <-p.baseCtx.Done(): @@ -341,7 +381,7 @@ func (p *WorkerPool) FlushWithContext(ctx context.Context) error { func (p *WorkerPool) doWork(ctx context.Context) { delay := time.Millisecond * 300 - var data = make([]Data, 0, p.batchLength) + data := make([]Data, 0, p.batchLength) for { select { case <-ctx.Done(): diff --git a/modules/repository/create_test.go b/modules/repository/create_test.go index ed890ace43..4e232a8609 100644 --- a/modules/repository/create_test.go +++ b/modules/repository/create_test.go @@ -23,7 +23,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { testTeamRepositories := func(teamID int64, repoIds []int64) { team := unittest.AssertExistsAndLoadBean(t, &models.Team{ID: teamID}).(*models.Team) - assert.NoError(t, team.GetRepositories(&models.SearchTeamOptions{}), "%s: GetRepositories", team.Name) + assert.NoError(t, team.GetRepositories(&models.SearchOrgTeamOptions{}), "%s: GetRepositories", team.Name) assert.Len(t, team.Repos, team.NumRepos, "%s: len repo", team.Name) assert.Len(t, team.Repos, len(repoIds), "%s: repo count", team.Name) for i, rid := range repoIds { diff --git a/modules/repository/generate.go b/modules/repository/generate.go index 3f83f51bb7..413c629a05 100644 --- a/modules/repository/generate.go +++ b/modules/repository/generate.go @@ -43,7 +43,7 @@ var defaultTransformers = []transformer{ {Name: "PASCAL", Transform: xstrings.ToCamelCase}, {Name: "LOWER", Transform: strings.ToLower}, {Name: "UPPER", Transform: strings.ToUpper}, - {Name: "TITLE", Transform: strings.Title}, + {Name: "TITLE", Transform: strings.Title}, // nolint } func generateExpansion(src string, templateRepo, generateRepo *repo_model.Repository) string { @@ -62,7 +62,7 @@ func generateExpansion(src string, templateRepo, generateRepo *repo_model.Reposi {Name: "TEMPLATE_SSH_URL", Value: templateRepo.CloneLink().SSH, Transformers: nil}, } - var expansionMap = make(map[string]string) + expansionMap := make(map[string]string) for _, e := range expansions { expansionMap[e.Name] = e.Value for _, tr := range e.Transformers { @@ -159,7 +159,7 @@ func generateRepoCommit(repo, templateRepo, generateRepo *repo_model.Repository, if err := os.WriteFile(path, []byte(generateExpansion(string(content), templateRepo, generateRepo)), - 0644); err != nil { + 0o644); err != nil { return err } break diff --git a/modules/repository/repo.go b/modules/repository/repo.go index eb3f58e937..2735536e74 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -72,13 +72,18 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } if err = git.CloneWithContext(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{ - Mirror: true, - Quiet: true, - Timeout: migrateTimeout, + Mirror: true, + Quiet: true, + Timeout: migrateTimeout, + SkipTLSVerify: setting.Migrations.SkipTLSVerify, }); err != nil { return repo, fmt.Errorf("Clone: %v", err) } + if err := git.WriteCommitGraph(ctx, repoPath); err != nil { + return repo, err + } + if opts.Wiki { wikiPath := repo_model.WikiPath(u.Name, opts.RepoName) wikiRemotePath := WikiRemoteURL(opts.CloneAddr) @@ -87,16 +92,21 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) } - if err = git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{ - Mirror: true, - Quiet: true, - Timeout: migrateTimeout, - Branch: "master", + if err := git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{ + Mirror: true, + Quiet: true, + Timeout: migrateTimeout, + Branch: "master", + SkipTLSVerify: setting.Migrations.SkipTLSVerify, }); err != nil { log.Warn("Clone wiki: %v", err) if err := util.RemoveAll(wikiPath); err != nil { return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) } + } else { + if err := git.WriteCommitGraph(ctx, wikiPath); err != nil { + return repo, err + } } } } @@ -254,7 +264,7 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository) opts.Page = page rels, err := models.GetReleasesByRepoID(repo.ID, opts) if err != nil { - return fmt.Errorf("GetReleasesByRepoID: %v", err) + return fmt.Errorf("unable to GetReleasesByRepoID in Repo[%d:%s/%s]: %w", repo.ID, repo.OwnerName, repo.Name, err) } if len(rels) == 0 { break @@ -265,40 +275,42 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository) } commitID, err := gitRepo.GetTagCommitID(rel.TagName) if err != nil && !git.IsErrNotExist(err) { - return fmt.Errorf("GetTagCommitID: %s: %v", rel.TagName, err) + return fmt.Errorf("unable to GetTagCommitID for %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err) } if git.IsErrNotExist(err) || commitID != rel.Sha1 { if err := models.PushUpdateDeleteTag(repo, rel.TagName); err != nil { - return fmt.Errorf("PushUpdateDeleteTag: %s: %v", rel.TagName, err) + return fmt.Errorf("unable to PushUpdateDeleteTag: %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err) } } else { existingRelTags[strings.ToLower(rel.TagName)] = struct{}{} } } } - tags, err := gitRepo.GetTags(0, 0) - if err != nil { - return fmt.Errorf("GetTags: %v", err) - } - for _, tagName := range tags { - if _, ok := existingRelTags[strings.ToLower(tagName)]; !ok { - if err := PushUpdateAddTag(repo, gitRepo, tagName); err != nil { - return fmt.Errorf("pushUpdateAddTag: %v", err) - } + + _, err := gitRepo.WalkReferences(git.ObjectTag, 0, 0, func(sha1, refname string) error { + tagName := strings.TrimPrefix(refname, git.TagPrefix) + if _, ok := existingRelTags[strings.ToLower(tagName)]; ok { + return nil } - } - return nil + + if err := PushUpdateAddTag(repo, gitRepo, tagName, sha1, refname); err != nil { + return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err) + } + + return nil + }) + return err } // PushUpdateAddTag must be called for any push actions to add tag -func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagName string) error { - tag, err := gitRepo.GetTag(tagName) +func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagName, sha1, refname string) error { + tag, err := gitRepo.GetTagWithID(sha1, tagName) if err != nil { - return fmt.Errorf("GetTag: %v", err) + return fmt.Errorf("unable to GetTag: %w", err) } commit, err := tag.Commit(gitRepo) if err != nil { - return fmt.Errorf("Commit: %v", err) + return fmt.Errorf("unable to get tag Commit: %w", err) } sig := tag.Tagger @@ -310,22 +322,22 @@ func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagN } var author *user_model.User - var createdAt = time.Unix(1, 0) + createdAt := time.Unix(1, 0) if sig != nil { author, err = user_model.GetUserByEmail(sig.Email) if err != nil && !user_model.IsErrUserNotExist(err) { - return fmt.Errorf("GetUserByEmail: %v", err) + return fmt.Errorf("unable to GetUserByEmail for %q: %w", sig.Email, err) } createdAt = sig.When } commitsCount, err := commit.CommitsCount() if err != nil { - return fmt.Errorf("CommitsCount: %v", err) + return fmt.Errorf("unable to get CommitsCount: %w", err) } - var rel = models.Release{ + rel := models.Release{ RepoID: repo.ID, TagName: tagName, LowerTagName: strings.ToLower(tagName), @@ -359,14 +371,14 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re _, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: p, RepositoryID: repo.ID}) if err != nil { - log.Error("Error creating LFS meta object %v: %v", p, err) + log.Error("Repo[%-v]: Error creating LFS meta object %-v: %v", repo, p, err) return err } if err := contentStore.Put(p, content); err != nil { - log.Error("Error storing content for LFS meta object %v: %v", p, err) + log.Error("Repo[%-v]: Error storing content for LFS meta object %-v: %v", repo, p, err) if _, err2 := models.RemoveLFSMetaObjectByOid(repo.ID, p.Oid); err2 != nil { - log.Error("Error removing LFS meta object %v: %v", p, err2) + log.Error("Repo[%-v]: Error removing LFS meta object %-v: %v", repo, p, err2) } return err } @@ -386,32 +398,32 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re for pointerBlob := range pointerChan { meta, err := models.GetLFSMetaObjectByOid(repo.ID, pointerBlob.Oid) if err != nil && err != models.ErrLFSObjectNotExist { - log.Error("Error querying LFS meta object %v: %v", pointerBlob.Pointer, err) + log.Error("Repo[%-v]: Error querying LFS meta object %-v: %v", repo, pointerBlob.Pointer, err) return err } if meta != nil { - log.Trace("Skipping unknown LFS meta object %v", pointerBlob.Pointer) + log.Trace("Repo[%-v]: Skipping unknown LFS meta object %-v", repo, pointerBlob.Pointer) continue } - log.Trace("LFS object %v not present in repository %s", pointerBlob.Pointer, repo.FullName()) + log.Trace("Repo[%-v]: LFS object %-v not present in repository", repo, pointerBlob.Pointer) exist, err := contentStore.Exists(pointerBlob.Pointer) if err != nil { - log.Error("Error checking if LFS object %v exists: %v", pointerBlob.Pointer, err) + log.Error("Repo[%-v]: Error checking if LFS object %-v exists: %v", repo, pointerBlob.Pointer, err) return err } if exist { - log.Trace("LFS object %v already present; creating meta object", pointerBlob.Pointer) + log.Trace("Repo[%-v]: LFS object %-v already present; creating meta object", repo, pointerBlob.Pointer) _, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: pointerBlob.Pointer, RepositoryID: repo.ID}) if err != nil { - log.Error("Error creating LFS meta object %v: %v", pointerBlob.Pointer, err) + log.Error("Repo[%-v]: Error creating LFS meta object %-v: %v", repo, pointerBlob.Pointer, err) return err } } else { if setting.LFS.MaxFileSize > 0 && pointerBlob.Size > setting.LFS.MaxFileSize { - log.Info("LFS object %v download denied because of LFS_MAX_FILE_SIZE=%d < size %d", pointerBlob.Pointer, setting.LFS.MaxFileSize, pointerBlob.Size) + log.Info("Repo[%-v]: LFS object %-v download denied because of LFS_MAX_FILE_SIZE=%d < size %d", repo, pointerBlob.Pointer, setting.LFS.MaxFileSize, pointerBlob.Size) continue } @@ -432,7 +444,7 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re err, has := <-errChan if has { - log.Error("Error enumerating LFS objects for repository: %v", err) + log.Error("Repo[%-v]: Error enumerating LFS objects for repository: %v", repo, err) return err } diff --git a/modules/setting/log.go b/modules/setting/log.go index b0ae5fb646..5b913a8252 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -15,13 +15,17 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" + "golang.org/x/text/cases" + "golang.org/x/text/language" ini "gopkg.in/ini.v1" ) -var filenameSuffix = "" -var descriptionLock = sync.RWMutex{} -var logDescriptions = make(map[string]*LogDescription) +var ( + filenameSuffix = "" + descriptionLock = sync.RWMutex{} + logDescriptions = make(map[string]*LogDescription) +) // GetLogDescriptions returns a race safe set of descriptions func GetLogDescriptions() map[string]*LogDescription { @@ -86,7 +90,7 @@ func RemoveSubLogDescription(key, name string) bool { type defaultLogOptions struct { levelName string // LogLevel flags string - filename string //path.Join(LogRootPath, "gitea.log") + filename string // path.Join(LogRootPath, "gitea.log") bufferLength int64 disableConsole bool } @@ -243,7 +247,7 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription Provider: provider, Config: config, }) - log.Info("%s Log: %s(%s:%s)", strings.Title(key), strings.Title(name), provider, levelName) + log.Info("%s Log: %s(%s:%s)", cases.Title(language.English).String(key), cases.Title(language.English).String(name), provider, levelName) } AddLogDescription(key, &description) @@ -327,7 +331,7 @@ func newLogService() { Provider: provider, Config: config, }) - log.Info("Gitea Log Mode: %s(%s:%s)", strings.Title(name), strings.Title(provider), levelName) + log.Info("Gitea Log Mode: %s(%s:%s)", cases.Title(language.English).String(name), cases.Title(language.English).String(provider), levelName) } AddLogDescription(log.DEFAULT, &description) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index abd6716c74..c3240a1eeb 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -8,7 +8,6 @@ package setting import ( "encoding/base64" "fmt" - "io" "math" "net" "net/url" @@ -30,6 +29,8 @@ import ( "github.com/unknwon/com" gossh "golang.org/x/crypto/ssh" + "golang.org/x/text/cases" + "golang.org/x/text/language" ini "gopkg.in/ini.v1" ) @@ -90,13 +91,15 @@ var ( // AppDataPath is the default path for storing data. // It maps to ini:"APP_DATA_PATH" and defaults to AppWorkPath + "/data" AppDataPath string + // LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix + // It maps to ini:"LOCAL_ROOT_URL" + LocalURL string // Server settings Protocol Scheme Domain string HTTPAddr string HTTPPort string - LocalURL string RedirectOtherPort bool PortToRedirect string OfflineMode bool @@ -637,7 +640,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { } UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666") UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32) - if err != nil || UnixSocketPermissionParsed > 0777 { + if err != nil || UnixSocketPermissionParsed > 0o777 { log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw) } @@ -710,6 +713,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { } } LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL) + LocalURL = strings.TrimRight(LocalURL, "/") + "/" RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false) PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80") OfflineMode = sec.Key("OFFLINE_MODE").MustBool() @@ -793,16 +797,16 @@ func loadFromConf(allowEmpty bool, extraConfig string) { SSH.AuthorizedPrincipalsAllow, SSH.AuthorizedPrincipalsEnabled = parseAuthorizedPrincipalsAllow(sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").Strings(",")) if !SSH.Disabled && !SSH.StartBuiltinServer { - if err := os.MkdirAll(SSH.RootPath, 0700); err != nil { + if err := os.MkdirAll(SSH.RootPath, 0o700); err != nil { log.Fatal("Failed to create '%s': %v", SSH.RootPath, err) - } else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil { + } else if err = os.MkdirAll(SSH.KeyTestPath, 0o644); err != nil { log.Fatal("Failed to create '%s': %v", SSH.KeyTestPath, err) } if len(trustedUserCaKeys) > 0 && SSH.AuthorizedPrincipalsEnabled { fname := sec.Key("SSH_TRUSTED_USER_CA_KEYS_FILENAME").MustString(filepath.Join(SSH.RootPath, "gitea-trusted-user-ca-keys.pem")) if err := os.WriteFile(fname, - []byte(strings.Join(trustedUserCaKeys, "\n")), 0600); err != nil { + []byte(strings.Join(trustedUserCaKeys, "\n")), 0o600); err != nil { log.Fatal("Failed to create '%s': %v", fname, err) } } @@ -943,8 +947,9 @@ func loadFromConf(allowEmpty bool, extraConfig string) { // The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches. // Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly. unsafeAllowRunAsRoot := Cfg.Section("").Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false) - RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod") - IsProd = strings.EqualFold(RunMode, "prod") + RunMode = Cfg.Section("").Key("RUN_MODE").MustString("Prod") + RunMode = cases.Title(language.English).String(strings.ToLower(RunMode)) + IsProd = RunMode == "Prod" // Does not check run user when the install lock is off. if InstallLock { currentUser, match := IsRunUserMatchCurrentUser(RunUser) @@ -1004,7 +1009,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { UI.ShowUserEmail = Cfg.Section("ui").Key("SHOW_USER_EMAIL").MustBool(true) UI.DefaultShowFullName = Cfg.Section("ui").Key("DEFAULT_SHOW_FULL_NAME").MustBool(false) UI.SearchRepoDescription = Cfg.Section("ui").Key("SEARCH_REPO_DESCRIPTION").MustBool(true) - UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(true) + UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(false) HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt")) if err != nil { @@ -1022,8 +1027,13 @@ func loadFromConf(allowEmpty bool, extraConfig string) { UI.CustomEmojisMap[emoji] = ":" + emoji + ":" } - sec = Cfg.Section("U2F") - U2F.AppID = sec.Key("APP_ID").MustString(strings.TrimSuffix(AppURL, "/")) + // FIXME: DEPRECATED to be removed in v1.18.0 + U2F.AppID = strings.TrimSuffix(AppURL, "/") + if Cfg.Section("U2F").HasKey("APP_ID") { + U2F.AppID = Cfg.Section("U2F").Key("APP_ID").MustString(strings.TrimSuffix(AppURL, "/")) + } else if Cfg.Section("u2f").HasKey("APP_ID") { + U2F.AppID = Cfg.Section("u2f").Key("APP_ID").MustString(strings.TrimSuffix(AppURL, "/")) + } } func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) { @@ -1069,28 +1079,22 @@ func loadInternalToken(sec *ini.Section) string { } switch tempURI.Scheme { case "file": - fp, err := os.OpenFile(tempURI.RequestURI(), os.O_RDWR, 0600) - if err != nil { + buf, err := os.ReadFile(tempURI.RequestURI()) + if err != nil && !os.IsNotExist(err) { log.Fatal("Failed to open InternalTokenURI (%s): %v", uri, err) } - defer fp.Close() - - buf, err := io.ReadAll(fp) - if err != nil { - log.Fatal("Failed to read InternalTokenURI (%s): %v", uri, err) - } // No token in the file, generate one and store it. if len(buf) == 0 { token, err := generate.NewInternalToken() if err != nil { log.Fatal("Error generate internal token: %v", err) } - if _, err := io.WriteString(fp, token); err != nil { + err = os.WriteFile(tempURI.RequestURI(), []byte(token), 0o600) + if err != nil { log.Fatal("Error writing to InternalTokenURI (%s): %v", uri, err) } return token } - return strings.TrimSpace(string(buf)) default: log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri) @@ -1162,7 +1166,6 @@ func MakeManifestData(appName, appURL, absoluteAssetURL string) []byte { }, }, }) - if err != nil { log.Error("unable to marshal manifest JSON. Error: %v", err) return make([]byte, 0) diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 4f876ec39a..eb8d333d78 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -24,6 +24,7 @@ import ( asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -100,6 +101,8 @@ func sessionHandler(session ssh.Session) { } defer stdin.Close() + process.SetSysProcAttribute(cmd) + wg := &sync.WaitGroup{} wg.Add(2) @@ -317,64 +320,7 @@ func Listen(host string, port int, ciphers, keyExchanges, macs []string) { } } - // Workaround slightly broken behaviour in x/crypto/ssh/handshake.go:458-463 - // - // Fundamentally the issue here is that HostKeyAlgos make the incorrect assumption - // that the PublicKey().Type() matches the signature algorithm. - // - // Therefore we need to add duplicates for the RSA with different signing algorithms. - signers := make([]ssh.Signer, 0, len(srv.HostSigners)) - for _, signer := range srv.HostSigners { - if signer.PublicKey().Type() == "ssh-rsa" { - signers = append(signers, - &wrapSigner{ - Signer: signer, - algorithm: gossh.SigAlgoRSASHA2512, - }, - &wrapSigner{ - Signer: signer, - algorithm: gossh.SigAlgoRSASHA2256, - }, - ) - } - signers = append(signers, signer) - } - srv.HostSigners = signers - go listen(&srv) - -} - -// wrapSigner wraps a signer and overrides its public key type with the provided algorithm -type wrapSigner struct { - ssh.Signer - algorithm string -} - -// PublicKey returns an associated PublicKey instance. -func (s *wrapSigner) PublicKey() gossh.PublicKey { - return &wrapPublicKey{ - PublicKey: s.Signer.PublicKey(), - algorithm: s.algorithm, - } -} - -// Sign returns raw signature for the given data. This method -// will apply the hash specified for the keytype to the data using -// the algorithm assigned for this key -func (s *wrapSigner) Sign(rand io.Reader, data []byte) (*gossh.Signature, error) { - return s.Signer.(gossh.AlgorithmSigner).SignWithAlgorithm(rand, data, s.algorithm) -} - -// wrapPublicKey wraps a PublicKey and overrides its type -type wrapPublicKey struct { - gossh.PublicKey - algorithm string -} - -// Type returns the algorithm -func (k *wrapPublicKey) Type() string { - return k.algorithm } // GenKeyPair make a pair of public and private keys for SSH access. @@ -387,7 +333,7 @@ func GenKeyPair(keyPath string) error { } privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)} - f, err := os.OpenFile(keyPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + f, err := os.OpenFile(keyPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600) if err != nil { return err } @@ -408,7 +354,7 @@ func GenKeyPair(keyPath string) error { } public := gossh.MarshalAuthorizedKey(pub) - p, err := os.OpenFile(keyPath+".pub", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + p, err := os.OpenFile(keyPath+".pub", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600) if err != nil { return err } diff --git a/modules/storage/local.go b/modules/storage/local.go index 54e0d0563d..701b0b1a9f 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -9,15 +9,15 @@ import ( "io" "net/url" "os" + "path" "path/filepath" + "strings" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" ) -var ( - _ ObjectStorage = &LocalStorage{} -) +var _ ObjectStorage = &LocalStorage{} // LocalStorageType is the type descriptor for local storage const LocalStorageType Type = "local" @@ -59,14 +59,18 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error }, nil } +func (l *LocalStorage) buildLocalPath(p string) string { + return filepath.Join(l.dir, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:]) +} + // Open a file func (l *LocalStorage) Open(path string) (Object, error) { - return os.Open(filepath.Join(l.dir, path)) + return os.Open(l.buildLocalPath(path)) } // Save a file func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) { - p := filepath.Join(l.dir, path) + p := l.buildLocalPath(path) if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil { return 0, err } @@ -106,13 +110,12 @@ func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) // Stat returns the info of the file func (l *LocalStorage) Stat(path string) (os.FileInfo, error) { - return os.Stat(filepath.Join(l.dir, path)) + return os.Stat(l.buildLocalPath(path)) } // Delete delete a file func (l *LocalStorage) Delete(path string) error { - p := filepath.Join(l.dir, path) - return util.Remove(p) + return util.Remove(l.buildLocalPath(path)) } // URL gets the redirect URL to a file diff --git a/modules/storage/local_test.go b/modules/storage/local_test.go new file mode 100644 index 0000000000..0749036cb7 --- /dev/null +++ b/modules/storage/local_test.go @@ -0,0 +1,53 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package storage + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuildLocalPath(t *testing.T) { + kases := []struct { + localDir string + path string + expected string + }{ + { + "a", + "0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", + "a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", + }, + { + "a", + "../0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", + "a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", + }, + { + "a", + "0\\a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", + "a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", + }, + { + "b", + "a/../0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", + "b/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", + }, + { + "b", + "a\\..\\0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", + "b/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", + }, + } + + for _, k := range kases { + t.Run(k.path, func(t *testing.T) { + l := LocalStorage{dir: k.localDir} + + assert.EqualValues(t, k.expected, l.buildLocalPath(k.path)) + }) + } +} diff --git a/modules/storage/minio.go b/modules/storage/minio.go index f78ba6aa27..638b67b761 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -117,7 +117,7 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error } func (m *MinioStorage) buildMinioPath(p string) string { - return strings.TrimPrefix(path.Join(m.basePath, p), "/") + return strings.TrimPrefix(path.Join(m.basePath, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:]), "/") } // Open open a file diff --git a/modules/structs/admin_user.go b/modules/structs/admin_user.go index facf16a395..eccbf29a46 100644 --- a/modules/structs/admin_user.go +++ b/modules/structs/admin_user.go @@ -19,6 +19,7 @@ type CreateUserOption struct { Password string `json:"password" binding:"Required;MaxSize(255)"` MustChangePassword *bool `json:"must_change_password"` SendNotify bool `json:"send_notify"` + Restricted *bool `json:"restricted"` Visibility string `json:"visibility" binding:"In(,public,limited,private)"` } diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 680277ea60..178704ab4f 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -183,6 +183,8 @@ type EditRepoOption struct { Archived *bool `json:"archived,omitempty"` // set to a string like `8h30m0s` to set the mirror interval time MirrorInterval *string `json:"mirror_interval,omitempty"` + // enable prune - remove obsolete remote-tracking references + EnablePrune *bool `json:"enable_prune,omitempty"` } // GenerateRepoOption options when creating repository using a template diff --git a/modules/templates/helper.go b/modules/templates/helper.go index fc07b49c71..1cad541c95 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -38,6 +38,8 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/gitdiff" + "golang.org/x/text/cases" + "golang.org/x/text/language" "github.com/editorconfig/editorconfig-core-go/v2" ) @@ -49,7 +51,7 @@ var mailSubjectSplit = regexp.MustCompile(`(?m)^-{3,}[\s]*$`) func NewFuncMap() []template.FuncMap { return []template.FuncMap{map[string]interface{}{ "GoVer": func() string { - return strings.Title(runtime.Version()) + return cases.Title(language.English).String(runtime.Version()) }, "UseHTTPS": func() bool { return strings.HasPrefix(setting.AppURL, "https") @@ -285,7 +287,7 @@ func NewFuncMap() []template.FuncMap { return util.MergeInto(dict, values...) }, "percentage": func(n int, values ...int) float32 { - var sum = 0 + sum := 0 for i := 0; i < len(values); i++ { sum += values[i] } @@ -378,6 +380,7 @@ func NewFuncMap() []template.FuncMap { }, "Join": strings.Join, "QueryEscape": url.QueryEscape, + "DotEscape": DotEscape, }} } @@ -386,7 +389,7 @@ func NewFuncMap() []template.FuncMap { func NewTextFuncMap() []texttmpl.FuncMap { return []texttmpl.FuncMap{map[string]interface{}{ "GoVer": func() string { - return strings.Title(runtime.Version()) + return cases.Title(language.English).String(runtime.Version()) }, "AppName": func() string { return setting.AppName @@ -477,7 +480,7 @@ func NewTextFuncMap() []texttmpl.FuncMap { return dict, nil }, "percentage": func(n int, values ...int) float32 { - var sum = 0 + sum := 0 for i := 0; i < len(values); i++ { sum += values[i] } @@ -501,8 +504,10 @@ func NewTextFuncMap() []texttmpl.FuncMap { }} } -var widthRe = regexp.MustCompile(`width="[0-9]+?"`) -var heightRe = regexp.MustCompile(`height="[0-9]+?"`) +var ( + widthRe = regexp.MustCompile(`width="[0-9]+?"`) + heightRe = regexp.MustCompile(`height="[0-9]+?"`) +) func parseOthers(defaultSize int, defaultClass string, others ...interface{}) (int, string) { size := defaultSize @@ -629,6 +634,11 @@ func JSEscape(raw string) string { return template.JSEscapeString(raw) } +// DotEscape wraps a dots in names with ZWJ [U+200D] in order to prevent autolinkers from detecting these as urls +func DotEscape(raw string) string { + return strings.ReplaceAll(raw, ".", "\u200d.\u200d") +} + // Sha1 returns sha1 sum of string func Sha1(str string) string { return base.EncodeSha1(str) @@ -736,7 +746,7 @@ func RenderEmoji(text string) template.HTML { return template.HTML(renderedText) } -//ReactionToEmoji renders emoji for use in reactions +// ReactionToEmoji renders emoji for use in reactions func ReactionToEmoji(reaction string) template.HTML { val := emoji.FromCode(reaction) if val != nil { diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index 62ec21f6fe..0009468690 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -39,6 +39,7 @@ func MockContext(t *testing.T, path string) *context.Context { Resp: context.NewResponse(resp), Locale: &mockLocale{}, } + defer ctx.Close() requestURL, err := url.Parse(path) assert.NoError(t, err) diff --git a/modules/typesniffer/typesniffer.go b/modules/typesniffer/typesniffer.go index 9e29b3557c..3cfbd92319 100644 --- a/modules/typesniffer/typesniffer.go +++ b/modules/typesniffer/typesniffer.go @@ -17,8 +17,12 @@ import ( // Use at most this many bytes to determine Content Type. const sniffLen = 1024 -// SvgMimeType MIME type of SVG images. -const SvgMimeType = "image/svg+xml" +const ( + // SvgMimeType MIME type of SVG images. + SvgMimeType = "image/svg+xml" + // ApplicationOctetStream MIME type of binary files. + ApplicationOctetStream = "application/octet-stream" +) var svgTagRegex = regexp.MustCompile(`(?si)\A\s*(?:(||>))\s*)*\/]`) var svgTagInXMLRegex = regexp.MustCompile(`(?si)\A<\?xml\b.*?\?>\s*(?:(||>))\s*)*\/]`) diff --git a/modules/util/net.go b/modules/util/net.go index 54c0a2ca39..e4fbf393b4 100644 --- a/modules/util/net.go +++ b/modules/util/net.go @@ -8,7 +8,7 @@ import ( "net" ) -// IsIPPrivate for net.IP.IsPrivate. TODO: replace with `ip.IsPrivate()` if min go version is bumped to 1.17 +// IsIPPrivate for net.IP.IsPrivate. func IsIPPrivate(ip net.IP) bool { if ip4 := ip.To4(); ip4 != nil { return ip4[0] == 10 || diff --git a/modules/util/slice.go b/modules/util/slice.go new file mode 100644 index 0000000000..552f5b866a --- /dev/null +++ b/modules/util/slice.go @@ -0,0 +1,18 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package util + +// RemoveIDFromList removes the given ID from the slice, if found. +// It does not preserve order, and assumes the ID is unique. +func RemoveIDFromList(list []int64, id int64) ([]int64, bool) { + n := len(list) - 1 + for i, item := range list { + if item == id { + list[i] = list[n] + return list[:n], true + } + } + return list, false +} diff --git a/modules/web/route.go b/modules/web/route.go index 1d9c92bd7a..2ee1f25728 100644 --- a/modules/web/route.go +++ b/modules/web/route.go @@ -42,11 +42,17 @@ func Wrap(handlers ...interface{}) http.HandlerFunc { handler := handlers[i] switch t := handler.(type) { case http.HandlerFunc: + if _, ok := resp.(context.ResponseWriter); !ok { + resp = context.NewResponse(resp) + } t(resp, req) if r, ok := resp.(context.ResponseWriter); ok && r.Status() > 0 { return } case func(http.ResponseWriter, *http.Request): + if _, ok := resp.(context.ResponseWriter); !ok { + resp = context.NewResponse(resp) + } t(resp, req) if r, ok := resp.(context.ResponseWriter); ok && r.Status() > 0 { return @@ -88,7 +94,7 @@ func Wrap(handlers ...interface{}) http.HandlerFunc { return } case func(http.Handler) http.Handler: - var next = http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) + next := http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) if len(handlers) > i+1 { next = Wrap(handlers[i+1:]...) } @@ -148,7 +154,7 @@ func MiddleAPI(f func(ctx *context.APIContext)) func(netx http.Handler) http.Han // Bind binding an obj to a handler func Bind(obj interface{}) http.HandlerFunc { - var tp = reflect.TypeOf(obj) + tp := reflect.TypeOf(obj) if tp.Kind() == reflect.Ptr { tp = tp.Elem() } @@ -156,7 +162,7 @@ func Bind(obj interface{}) http.HandlerFunc { panic("Only structs are allowed to bind") } return Wrap(func(ctx *context.Context) { - var theObj = reflect.New(tp).Interface() // create a new form obj for every request but not use obj directly + theObj := reflect.New(tp).Interface() // create a new form obj for every request but not use obj directly binding.Bind(ctx.Req, theObj) SetForm(ctx, theObj) middleware.AssignForm(theObj, ctx.Data) @@ -214,8 +220,8 @@ func (r *Route) Use(middlewares ...interface{}) { // Group mounts a sub-Router along a `pattern` string. func (r *Route) Group(pattern string, fn func(), middlewares ...interface{}) { - var previousGroupPrefix = r.curGroupPrefix - var previousMiddlewares = r.curMiddlewares + previousGroupPrefix := r.curGroupPrefix + previousMiddlewares := r.curMiddlewares r.curGroupPrefix += pattern r.curMiddlewares = append(r.curMiddlewares, middlewares...) @@ -238,7 +244,7 @@ func (r *Route) getPattern(pattern string) string { // Mount attaches another Route along ./pattern/* func (r *Route) Mount(pattern string, subR *Route) { - var middlewares = make([]interface{}, len(r.curMiddlewares)) + middlewares := make([]interface{}, len(r.curMiddlewares)) copy(middlewares, r.curMiddlewares) subR.Use(middlewares...) r.R.Mount(r.getPattern(pattern), subR.R) @@ -246,7 +252,7 @@ func (r *Route) Mount(pattern string, subR *Route) { // Any delegate requests for all methods func (r *Route) Any(pattern string, h ...interface{}) { - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) r.R.HandleFunc(r.getPattern(pattern), Wrap(middlewares...)) } @@ -254,7 +260,7 @@ func (r *Route) Any(pattern string, h ...interface{}) { func (r *Route) Route(pattern, methods string, h ...interface{}) { p := r.getPattern(pattern) ms := strings.Split(methods, ",") - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) for _, method := range ms { r.R.MethodFunc(strings.TrimSpace(method), p, Wrap(middlewares...)) } @@ -262,12 +268,12 @@ func (r *Route) Route(pattern, methods string, h ...interface{}) { // Delete delegate delete method func (r *Route) Delete(pattern string, h ...interface{}) { - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) r.R.Delete(r.getPattern(pattern), Wrap(middlewares...)) } func (r *Route) getMiddlewares(h []interface{}) []interface{} { - var middlewares = make([]interface{}, len(r.curMiddlewares), len(r.curMiddlewares)+len(h)) + middlewares := make([]interface{}, len(r.curMiddlewares), len(r.curMiddlewares)+len(h)) copy(middlewares, r.curMiddlewares) middlewares = append(middlewares, h...) return middlewares @@ -275,51 +281,51 @@ func (r *Route) getMiddlewares(h []interface{}) []interface{} { // Get delegate get method func (r *Route) Get(pattern string, h ...interface{}) { - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) r.R.Get(r.getPattern(pattern), Wrap(middlewares...)) } // Options delegate options method func (r *Route) Options(pattern string, h ...interface{}) { - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) r.R.Options(r.getPattern(pattern), Wrap(middlewares...)) } // GetOptions delegate get and options method func (r *Route) GetOptions(pattern string, h ...interface{}) { - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) r.R.Get(r.getPattern(pattern), Wrap(middlewares...)) r.R.Options(r.getPattern(pattern), Wrap(middlewares...)) } // PostOptions delegate post and options method func (r *Route) PostOptions(pattern string, h ...interface{}) { - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) r.R.Post(r.getPattern(pattern), Wrap(middlewares...)) r.R.Options(r.getPattern(pattern), Wrap(middlewares...)) } // Head delegate head method func (r *Route) Head(pattern string, h ...interface{}) { - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) r.R.Head(r.getPattern(pattern), Wrap(middlewares...)) } // Post delegate post method func (r *Route) Post(pattern string, h ...interface{}) { - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) r.R.Post(r.getPattern(pattern), Wrap(middlewares...)) } // Put delegate put method func (r *Route) Put(pattern string, h ...interface{}) { - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) r.R.Put(r.getPattern(pattern), Wrap(middlewares...)) } // Patch delegate patch method func (r *Route) Patch(pattern string, h ...interface{}) { - var middlewares = r.getMiddlewares(h) + middlewares := r.getMiddlewares(h) r.R.Patch(r.getPattern(pattern), Wrap(middlewares...)) } diff --git a/modules/web/route_test.go b/modules/web/route_test.go index a8470fec94..df00f074f1 100644 --- a/modules/web/route_test.go +++ b/modules/web/route_test.go @@ -53,6 +53,7 @@ func TestRoute2(t *testing.T) { tp := chi.URLParam(req, "type") assert.EqualValues(t, "issues", tp) route = 0 + resp.WriteHeader(200) }) r.Get("/{type:issues|pulls}/{index}", func(resp http.ResponseWriter, req *http.Request) { @@ -65,9 +66,8 @@ func TestRoute2(t *testing.T) { index := chi.URLParam(req, "index") assert.EqualValues(t, "1", index) route = 1 + resp.WriteHeader(200) }) - }, func(resp http.ResponseWriter, req *http.Request) { - resp.WriteHeader(200) }) r.Group("/issues/{index}", func() { @@ -79,6 +79,7 @@ func TestRoute2(t *testing.T) { index := chi.URLParam(req, "index") assert.EqualValues(t, "1", index) route = 2 + resp.WriteHeader(200) }) }) }) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 4f5a58bf76..9828b1fe3c 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -41,6 +41,7 @@ webauthn_use_twofa=Zwei-Faktor-Authentifizierung via Handy verwenden webauthn_error=Dein Sicherheitsschlüssel konnte nicht gelesen werden. webauthn_unsupported_browser=Dein Browser unterstützt derzeit keinen WebAuthn. webauthn_error_unknown=Ein unbekannter Fehler ist aufgetreten. Bitte versuche es erneut. +webauthn_error_insecure=WebAuthn unterstützt nur sichere Verbindungen. Zum Testen über HTTP kannst du "localhost" oder "127.0.0.1" als Host verwenden webauthn_error_unable_to_process=Der Server konnte deine Anfrage nicht bearbeiten. webauthn_error_duplicated=Für diese Anfrage ist der Sicherheitsschlüssel nicht erlaubt. Bitte stell sicher, dass er nicht bereits registriert ist. webauthn_error_timeout=Das Zeitlimit wurde erreicht, bevor dein Schlüssel gelesen werden konnte. Bitte lade die Seite erneut. @@ -140,6 +141,7 @@ charset=Zeichensatz path=Pfad sqlite_helper=Dateipfad zur SQLite3 Datenbank.
Gebe einen absoluten Pfad an, wenn Gitea als Service gestartet wird. reinstall_error=Du versuchst, in eine bereits existierende Gitea Datenbank zu installieren +reinstall_confirm_message=Eine Neuinstallation mit einer bestehenden Gitea-Datenbank kann mehrere Probleme verursachen. In den meisten FƤllen solltest du deine vorhandene "app.ini" verwenden, um Gitea auszuführen. Wenn du weist, was du tust, bestƤtigen die folgenden Angaben: reinstall_confirm_check_3=Du bestƤtigst, dass du absolut sicher bist, dass diese Gitea mit der richtigen app.ini lƤuft, und du sicher bist, dass du neu installieren musst. Du bestƤtigst, dass du die oben genannten Risiken anerkennst. err_empty_db_path=Der SQLite3 Datenbankpfad darf nicht leer sein. no_admin_and_disable_registration=Du kannst Selbst-Registrierungen nicht deaktivieren, ohne ein Administratorkonto zu erstellen. @@ -2050,8 +2052,8 @@ settings.lfs_pointers.accessible=Nutzer hat Zugriff settings.lfs_pointers.associateAccessible=Ordne %d zugƤngliche OIDs zu settings.rename_branch_failed_exist=Kann den Branch nicht umbenennen, da der Zielbranch %s bereits existiert. settings.rename_branch_failed_not_exist=Kann den Branch %s nicht umbenennen, da er nicht existiert. -settings.rename_branch_success=Zweig %s wurde erfolgreich in %s umbenannt. -settings.rename_branch_from=alter Zweigname +settings.rename_branch_success=Branch %s wurde erfolgreich in %s umbenannt. +settings.rename_branch_from=alter Branchname settings.rename_branch_to=neuer Branchname settings.rename_branch=Branch umbennen diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 6e11388167..35cb042acb 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -34,6 +34,20 @@ twofa=ĪˆĪ»ĪµĪ³Ļ‡ĪæĻ‚ Ī¤Ī±Ļ…Ļ„ĻŒĻ„Ī·Ļ„Ī±Ļ‚ Ī”ĻĪæ Ī Ī±ĻĪ±Ī³ĻŒĪ½Ļ„Ļ‰Ī½ twofa_scratch=ĪšĻ‰Ī“Ī¹ĪŗĻŒĻ‚ ĪœĪÆĪ±Ļ‚ Ī§ĻĪ®ĻƒĪ·Ļ‚ Ī”ĻĪæ Ī Ī±ĻĪ±Ī³ĻŒĪ½Ļ„Ļ‰Ī½ passcode=ĪšĻ‰Ī“Ī¹ĪŗĻŒĻ‚ +webauthn_insert_key=Ī•Ī¹ĻƒĪ¬Ī³ĪµĻ„Īµ το κλειΓί Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚ ĻƒĪ±Ļ‚ +webauthn_sign_in=Ī Ī±Ļ„Ī®ĻƒĻ„Īµ το κουμπί ĻƒĻ„Īæ κλειΓί Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚. Αν το κλειΓί Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚ ĻƒĪ±Ļ‚ Γεν έχει κουμπί, Ļ„ĪæĻ€ĪæĪøĪµĻ„Ī®ĻƒĻ„Īµ το ξανά. +webauthn_press_button=Ī Ī±ĻĪ±ĪŗĪ±Ī»ĻŽ Ļ€Ī±Ļ„Ī®ĻƒĻ„Īµ το κουμπί ĻƒĻ„Īæ κλειΓί Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚ā€¦ +webauthn_use_twofa=Ī§ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹Ī®ĻƒĻ„Īµ έναν ĪŗĻ‰Ī“Ī¹ĪŗĻŒ Ī“ĻĪæ Ļ€Ī±ĻĪ±Ī³ĻŒĪ½Ļ„Ļ‰Ī½ Ī±Ļ€ĻŒ το Ļ„Ī·Ī»Ī­Ļ†Ļ‰Ī½ĻŒ ĻƒĪ±Ļ‚ +webauthn_error=Ī‘Ī“ĻĪ½Ī±Ļ„Ī· Ī· Ī±Ī½Ī¬Ī³Ī½Ļ‰ĻƒĪ· του ĪŗĪ»ĪµĪ¹Ī“Ī¹ĪæĻ Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚. +webauthn_unsupported_browser=Το Ļ€ĻĻŒĪ³ĻĪ±Ī¼Ī¼Ī± Ļ€ĪµĻĪ¹Ī®Ī³Ī·ĻƒĪ®Ļ‚ ĻƒĪ±Ļ‚ Γεν Ļ…Ļ€ĪæĻƒĻ„Ī·ĻĪÆĪ¶ĪµĪ¹ επί του Ļ€Ī±ĻĻŒĪ½Ļ„ĪæĻ‚ WebAuthn. +webauthn_error_unknown=Ī Ī±ĻĪæĻ…ĻƒĪ¹Ī¬ĻƒĻ„Ī·ĪŗĪµ ένα Ī¬Ī³Ī½Ļ‰ĻƒĻ„Īæ ĻƒĻ†Ī¬Ī»Ī¼Ī±. Ī Ī±ĻĪ±ĪŗĪ±Ī»ĻŽ Ļ€ĻĪæĻƒĻ€Ī±ĪøĪ®ĻƒĻ„Īµ ξανά. +webauthn_error_insecure=Το WebAuthn Ļ…Ļ€ĪæĻƒĻ„Ī·ĻĪÆĪ¶ĪµĪ¹ μόνο Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĻ‚ ĻƒĻ…Ī½Ī“Ī­ĻƒĪµĪ¹Ļ‚. Για Γοκιμές πάνω Ī±Ļ€ĻŒ HTTP, μπορείτε να Ļ‡ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹Ī®ĻƒĪµĻ„Īµ την Ļ€ĻĪæĪ­Ī»ĪµĻ…ĻƒĪ· "localhost" Ī® "127.0.0.1" +webauthn_error_unable_to_process=Ο Ī“Ī¹Ī±ĪŗĪæĪ¼Ī¹ĻƒĻ„Ī®Ļ‚ Γεν Ī¼Ļ€ĻŒĻĪµĻƒĪµ να ĪµĻ€ĪµĪ¾ĪµĻĪ³Ī±ĻƒĻ„ĪµĪÆ το αίτημά ĻƒĪ±Ļ‚. +webauthn_error_duplicated=Το κλειΓί Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚ Γεν επιτρέπεται για Ī±Ļ…Ļ„ĻŒ το αίτημα. Βεβαιωθείτε ĻŒĻ„Ī¹ το κλειΓί Γεν έχει ήΓη καταχωρηθεί. +webauthn_error_empty=Πρέπει να ĪæĻĪÆĻƒĪµĻ„Īµ ένα όνομα για Ī±Ļ…Ļ„ĻŒ το κλειΓί. +webauthn_error_timeout=Το Ļ‡ĻĪæĪ½Ī¹ĪŗĻŒ όριο Ī­Ļ†Ļ„Ī±ĻƒĪµ πριν το κλειΓί να Ī“Ī¹Ī±Ī²Ī±ĻƒĻ„ĪµĪÆ. Ī Ī±ĻĪ±ĪŗĪ±Ī»ĻŽ Ī±Ī½Ī±Ī½ĪµĻŽĻƒĻ„Īµ τη σελίΓα και Ļ€ĻĪæĻƒĻ€Ī±ĪøĪ®ĻƒĻ„Īµ ξανά. +webauthn_u2f_deprecated=Το κλειΓί: '%s' Ļ€Ī¹ĻƒĻ„ĪæĻ€ĪæĪ¹ĪµĪÆ Ļ‡ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹ĻŽĪ½Ļ„Ī±Ļ‚ το παρωχημένο Ļ€ĻĻ‰Ļ„ĻŒĪŗĪæĪ»Ī»Īæ U2F. Θα πρέπει να ĪŗĪ±Ļ„Ī±Ļ‡Ļ‰ĻĪ®ĻƒĪµĻ„Īµ ξανά Ī±Ļ…Ļ„ĻŒ το κλειΓί και να ĪŗĪ±Ļ„Ī±ĻĪ³Ī®ĻƒĪµĻ„Īµ την παλιά εγγραφή. +webauthn_reload=Ī‘Ī½Ī±Ī½Ī­Ļ‰ĻƒĪ· repository=Αποθετήριο organization=ĪŸĻĪ³Ī±Ī½Ī¹ĻƒĪ¼ĻŒĻ‚ @@ -305,6 +319,9 @@ oauth_signup_submit=ĪŸĪ»ĪæĪŗĪ»Ī·ĻĻ‰Ī¼Ī­Ī½ĪæĻ‚ Ī›ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚ oauth_signin_tab=Ī£ĻĪ½Ī“ĪµĻƒĪ· με υπάρχων λογαριασμό oauth_signin_title=ΣυνΓεθείτε για να εγκρίνετε τον ΣυνΓεΓεμένο Ī›ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒ oauth_signin_submit=Ī£ĻĪ½Ī“ĪµĻƒĪ· Ī›ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ +oauth.signin.error=Ī Ī±ĻĪæĻ…ĻƒĪ¹Ī¬ĻƒĻ„Ī·ĪŗĪµ ĻƒĻ†Ī¬Ī»Ī¼Ī± κατά την ĪµĻ€ĪµĪ¾ĪµĻĪ³Ī±ĻƒĪÆĪ± του αιτήματος ĪµĪ¾ĪæĻ…ĻƒĪ¹ĪæĪ“ĻŒĻ„Ī·ĻƒĪ·Ļ‚. Εάν Ī±Ļ…Ļ„ĻŒ το ĻƒĻ†Ī¬Ī»Ī¼Ī± επιμένει, Ļ€Ī±ĻĪ±ĪŗĪ±Ī»ĪæĻĪ¼Īµ ĪµĻ€Ī¹ĪŗĪæĪ¹Ī½Ļ‰Ī½Ī®ĻƒĻ„Īµ με το Ī“Ī¹Ī±Ļ‡ĪµĪ¹ĻĪ¹ĻƒĻ„Ī® του Ī¹ĻƒĻ„ĪæĻ„ĻŒĻ€ĪæĻ…. +oauth.signin.error.access_denied=Ī— Ī±ĪÆĻ„Ī·ĻƒĪ· ĪµĪ¾ĪæĻ…ĻƒĪ¹ĪæĪ“ĻŒĻ„Ī·ĻƒĪ·Ļ‚ απορρίφθηκε. +oauth.signin.error.temporarily_unavailable=Ī— ĪµĪ¾ĪæĻ…ĻƒĪ¹ĪæĪ“ĻŒĻ„Ī·ĻƒĪ· απέτυχε επειΓή Īæ Ī“Ī¹Ī±ĪŗĪæĪ¼Ī¹ĻƒĻ„Ī®Ļ‚ Ļ„Ī±Ļ…Ļ„ĪæĻ€ĪæĪÆĪ·ĻƒĪ·Ļ‚ Γεν είναι Ī“Ī¹Ī±ĪøĪ­ĻƒĪ¹Ī¼ĪæĻ‚ Ļ€ĻĪæĻƒĻ‰ĻĪ¹Ī½Ī¬. Ī Ī±ĻĪ±ĪŗĪ±Ī»ĻŽ Ļ€ĻĪæĻƒĻ€Ī±ĪøĪ®ĻƒĻ„Īµ ξανά Ī±ĻĪ³ĻŒĻ„ĪµĻĪ±. openid_connect_submit=Ī£ĻĪ½Ī“ĪµĻƒĪ· openid_connect_title=Ī£ĻĪ½Ī“ĪµĻƒĪ· σε υπάρχων λογαριασμό openid_connect_desc=Το επιλεγμένο OpenID URI είναι Ī¬Ī³Ī½Ļ‰ĻƒĻ„Īæ. Ī£Ļ…Ī½Ī“Ī­ĻƒĻ„Īµ το με ένα νέο λογαριασμό ĪµĪ“ĻŽ. @@ -510,6 +527,7 @@ twofa=ĪˆĪ»ĪµĪ³Ļ‡ĪæĻ‚ Ī¤Ī±Ļ…Ļ„ĻŒĻ„Ī·Ļ„Ī±Ļ‚ Ī”ĻĪæ Ī Ī±ĻĪ±Ī³ĻŒĪ½Ļ„Ļ‰Ī½ account_link=ΣυνΓεΓεμένοι Ī›ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĪÆ organization=Οργανισμοί uid=Uid +webauthn=ΚλειΓιά Ī‘ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚ public_profile=Ī”Ī·Ī¼ĻŒĻƒĪ¹Īæ Προφίλ biography_placeholder=Πείτε μας λίγο για τον ĪµĪ±Ļ…Ļ„ĻŒ ĻƒĪ±Ļ‚ @@ -531,6 +549,7 @@ continue=Συνέχεια cancel=Ī‘ĪŗĻĻĻ‰ĻƒĪ· language=Ī“Ī»ĻŽĻƒĻƒĪ± ui=Θέμα Διεπαφής +saved_successfully=Οι ĻĻ…ĪøĪ¼ĪÆĻƒĪµĪ¹Ļ‚ ĻƒĪ±Ļ‚ Ī±Ļ€ĪæĪøĪ·ĪŗĪµĻĻ„Ī·ĪŗĪ±Ī½ ĪµĻ€Ī¹Ļ„Ļ…Ļ‡ĻŽĻ‚. privacy=Ī‘Ļ€ĻŒĻĻĪ·Ļ„Īæ keep_activity_private=Ī‘Ļ€ĻŒĪŗĻĻ…ĻˆĪ· της Ī“ĻĪ±ĻƒĻ„Ī·ĻĪ¹ĻŒĻ„Ī·Ļ„Ī±Ļ‚ ĻƒĪ±Ļ‚ Ī±Ļ€ĻŒ τη σελίΓα προφίλ keep_activity_private_popup=Με αυτή την επιλογή Ī· Ī“ĻĪ±ĻƒĻ„Ī·ĻĪ¹ĻŒĻ„Ī·Ļ„Ī± ĻƒĪ±Ļ‚ είναι ορατή μόνο σε ĪµĻƒĪ¬Ļ‚ και τους Ī“Ī¹Ī±Ļ‡ĪµĪ¹ĻĪ¹ĻƒĻ„Ī­Ļ‚ @@ -730,6 +749,11 @@ passcode_invalid=Ο ĪŗĻ‰Ī“Ī¹ĪŗĻŒĻ‚ είναι λάθος. Ī”ĪæĪŗĪ¹Ī¼Ī¬ĻƒĻ„Īµ ξ twofa_enrolled=Ο Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚ ĻƒĪ±Ļ‚ έχει εγγραφεί σε Ļ„Ī±Ļ…Ļ„ĪæĻ€ĪæĪÆĪ·ĻƒĪ· Ī“ĻĪæ Ļ€Ī±ĻĪ±Ī³ĻŒĪ½Ļ„Ļ‰Ī½. Ī‘Ļ€ĪæĪøĪ·ĪŗĪµĻĻƒĻ„Īµ το Ī“Ī¹Ī±ĪŗĻĪ¹Ļ„Ī¹ĪŗĻŒ μιας Ļ‡ĻĪ®ĻƒĪ·Ļ‚ (%s) σε Ī±ĻƒĻ†Ī±Ī»Ī­Ļ‚ μέρος ĪŗĪ±ĪøĻŽĻ‚ εμφανίζεται μόνο μία φορά! twofa_failed_get_secret=Αποτυχία Ī»Ī®ĻˆĪ·Ļ‚ Ī¼Ļ…ĻƒĻ„Ī¹ĪŗĪæĻ. +webauthn_desc=Τα κλειΓιά Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚ είναι ĻƒĻ…ĻƒĪŗĪµĻ…Ī­Ļ‚ που περιέχουν κρυπτογραφικά κλειΓιά. ĪœĻ€ĪæĻĪæĻĪ½ να Ļ‡ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹Ī·ĪøĪæĻĪ½ για έλεγχο Ļ„Ī±Ļ…Ļ„ĻŒĻ„Ī·Ļ„Ī±Ļ‚ Ī“ĻĪæ Ļ€Ī±ĻĪ±Ī³ĻŒĪ½Ļ„Ļ‰Ī½. Τα κλειΓιά Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚ πρέπει να Ļ…Ļ€ĪæĻƒĻ„Ī·ĻĪÆĪ¶ĪæĻ…Ī½ το Ļ€ĻĻŒĻ„Ļ…Ļ€Īæ WebAuthn Authn Authenticator. +webauthn_register_key=Προσθήκη ĪšĪ»ĪµĪ¹Ī“Ī¹ĪæĻ Ī‘ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚ +webauthn_nickname=ĪØĪµĻ…Ī“ĻŽĪ½Ļ…Ī¼Īæ +webauthn_delete_key=Ī‘Ļ†Ī±ĪÆĻĪµĻƒĪ· ĪšĪ»ĪµĪ¹Ī“Ī¹ĪæĻ Ī‘ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚ +webauthn_delete_key_desc=Αν Ī±Ļ†Ī±Ī¹ĻĪ­ĻƒĪµĻ„Īµ ένα κλειΓί Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĪ±Ļ‚ Γεν μπορείτε πλέον να ĻƒĻ…Ī½Ī“ĪµĪøĪµĪÆĻ„Īµ με Ī±Ļ…Ļ„ĻŒ. Συνέχεια; manage_account_links=Ī”Ī¹Ī±Ļ‡ĪµĪÆĻĪ¹ĻƒĪ· ΣυνΓεΓεμένων Ī›ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŽĪ½ manage_account_links_desc=Αυτοί οι εξωτερικοί λογαριασμοί είναι ĻƒĻ…Ī½Ī“ĪµĪ“ĪµĪ¼Ī­Ī½ĪæĪ¹ ĻƒĻ„ĪæĪ½ Gitea λογαριασμό ĻƒĪ±Ļ‚. @@ -986,7 +1010,16 @@ file_view_rendered=Προβολή Ī‘Ļ€ĻŒĪ“ĪæĻƒĪ·Ļ‚ file_view_raw=Προβολή Ī‘ĪŗĪ±Ļ„Ī­ĻĪ³Ī±ĻƒĻ„ĪæĻ… file_permalink=Permalink file_too_large=Το αρχείο είναι Ļ€ĪæĪ»Ļ μεγάλο για να ĪµĪ¼Ļ†Ī±Ī½Ī¹ĻƒĻ„ĪµĪÆ. +bidi_bad_header=`Ī‘Ļ…Ļ„ĻŒ το αρχείο περιέχει μη Ī±Ī½Ī±Ī¼ĪµĪ½ĻŒĪ¼ĪµĪ½ĪæĻ…Ļ‚ χαρακτήρες Unicode!` +bidi_bad_description=`Ī‘Ļ…Ļ„ĻŒ το αρχείο περιέχει μη Ī±Ī½Ī±Ī¼ĪµĪ½ĻŒĪ¼ĪµĪ½ĪæĻ…Ļ‚ χαρακτήρες Bidirectional Unicode που ĪÆĻƒĻ‰Ļ‚ να επεξεργάζονται Γιαφορετικά Ī±Ļ€ĻŒ ĻŒĻ„Ī¹ εμφανίζεται παρακάτω. Αν Ī· Ļ‡ĻĪ®ĻƒĪ· αυτή είναι ĻƒĪŗĻŒĻ€Ī¹Ī¼Ī· και νόμιμη, μπορείτε να Ī±Ī³Ī½ĪæĪ®ĻƒĪµĻ„Īµ με Ī±ĻƒĻ†Ī¬Ī»ĪµĪ¹Ī± αυτή την Ļ€ĻĪæĪµĪ¹Ī“ĪæĻ€ĪæĪÆĪ·ĻƒĪ·. Ī§ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹Ī®ĻƒĻ„Īµ το κουμπί Escape για να Ī±Ļ€ĪæĪŗĪ±Ī»ĻĻˆĪµĻ„Īµ κρυμμένους χαρακτήρες.` +bidi_bad_description_escaped=`Ī‘Ļ…Ļ„ĻŒ το αρχείο περιέχει μη Ī±Ī½Ī±Ī¼ĪµĪ½ĻŒĪ¼ĪµĪ½ĪæĻ…Ļ‚ χαρακτήρες Bidirectional Unicode. Οι κρυμμένοι χαρακτήρες unicode εμφανίζονται κωΓικοποιημένοι παρακάτω. Ī§ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹Ī®ĻƒĻ„Īµ το κουμπί Unescape για να Γείτε Ļ€ĻŽĻ‚ αποΓίΓονται.` +unicode_header=`Ī‘Ļ…Ļ„ĻŒ το αρχείο περιέχει ĪŗĻĻ…Ļ†ĪæĻĻ‚ χαρακτήρες Unicode!` +unicode_description=`Ī‘Ļ…Ļ„ĻŒ το αρχείο περιέχει ĪŗĻĻ…Ļ†ĪæĻĻ‚ χαρακτήρες Unicode που μπορεί να επεξεργάζονται Γιαφορετικά Ī±Ļ€ĻŒ ĻŒĻ€Ļ‰Ļ‚ εμφανίζονται παρακάτω. Αν Ī· Ļ‡ĻĪ®ĻƒĪ· είναι ĻƒĪŗĻŒĻ€Ī¹Ī¼Ī· και νόμιμη, μπορείτε να Ī±Ī³Ī½ĪæĪ®ĻƒĪµĻ„Īµ με Ī±ĻƒĻ†Ī¬Ī»ĪµĪ¹Ī± αυτή την Ļ€ĻĪæĪµĪ¹Ī“ĪæĻ€ĪæĪÆĪ·ĻƒĪ·. Ī§ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹Ī®ĻƒĻ„Īµ το κουμπί Escape για να Ī±Ļ€ĪæĪŗĪ±Ī»ĻĻˆĪµĻ„Īµ τους ĪŗĻĻ…Ļ†ĪæĻĻ‚ χαρακτήρες.` +unicode_description_escaped=`Ī‘Ļ…Ļ„ĻŒ το αρχείο περιέχει ĪŗĻĻ…Ļ†ĪæĻĻ‚ χαρακτήρες Unicode. Οι κρυφοί χαρακτήρες unicode εμφανίζονται κωΓικοποιημένοι παρακάτω. Ī§ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹Ī®ĻƒĻ„Īµ το κουμπί Unescape για να Γείτε Ļ€ĻŽĻ‚ αποΓίΓονται.` +line_unicode=`Αυτή Ī· γραμμή έχει ĪŗĻĻ…Ļ†ĪæĻĻ‚ χαρακτήρες unicode` +escape_control_characters=Escape +unescape_control_characters=Unescape file_copy_permalink=Αντιγραφή Permalink video_not_supported_in_browser=Το Ļ€ĻĻŒĪ³ĻĪ±Ī¼Ī¼Ī± Ļ€ĪµĻĪ¹Ī®Ī³Ī·ĻƒĪ®Ļ‚ ĻƒĪ±Ļ‚ Γεν Ļ…Ļ€ĪæĻƒĻ„Ī·ĻĪÆĪ¶ĪµĪ¹ την ετικέτα HTML5 'video'. audio_not_supported_in_browser=Το Ļ€ĻĻŒĪ³ĻĪ±Ī¼Ī¼Ī± Ļ€ĪµĻĪ¹Ī®Ī³Ī·ĻƒĪ®Ļ‚ ĻƒĪ±Ļ‚ Γεν Ļ…Ļ€ĪæĻƒĻ„Ī·ĻĪÆĪ¶ĪµĪ¹ την ετικέτα HTML5 'audio'. @@ -1081,6 +1114,8 @@ commits.signed_by_untrusted_user_unmatched=΄πογράφηκε Ī±Ļ€ĻŒ ένα μ commits.gpg_key_id=ID ĪšĪ»ĪµĪ¹Ī“Ī¹ĪæĻ GPG commits.ssh_key_fingerprint=Ī‘Ļ€ĪæĻ„ĻĻ€Ļ‰Ī¼Ī± ĪšĪ»ĪµĪ¹Ī“Ī¹ĪæĻ SSH + +ext_issues=Πρόσβαση ĻƒĻ„Ī± Εξωτερικά Ζητήματα ext_issues.desc=Ī£ĻĪ½Ī“ĪµĻƒĪ· σε ĪµĪ¾Ļ‰Ļ„ĪµĻĪ¹ĪŗĻŒ εφαρμογή ζητημάτων. projects=Έργα @@ -1560,6 +1595,7 @@ signing.wont_sign.commitssigned=Ī— ĻƒĻ…Ī³Ļ‡ĻŽĪ½ĪµĻ…ĻƒĪ· Γεν θα υπογρα signing.wont_sign.approved=Ī— ĻƒĻ…Ī³Ļ‡ĻŽĪ½ĪµĻ…ĻƒĪ· Γεν θα υπογραφεί ĪŗĪ±ĪøĻŽĻ‚ το PR Γεν εγκρίνεται signing.wont_sign.not_signed_in=Δεν ĪµĪÆĻƒĻ„Īµ ĻƒĻ…Ī½Ī“ĪµĪ“ĪµĪ¼Ī­Ī½ĪæĪ¹ +ext_wiki=Πρόσβαση ĻƒĻ„Īæ Ī•Ī¾Ļ‰Ļ„ĪµĻĪ¹ĪŗĻŒ Wiki ext_wiki.desc=Ī£ĻĪ½Ī“ĪµĻƒĪ· σε ένα ĪµĪ¾Ļ‰Ļ„ĪµĻĪ¹ĪŗĻŒ wiki. wiki=Wiki @@ -1816,6 +1852,8 @@ settings.webhook.response=Ī‘Ļ€Ī¬Ī½Ļ„Ī·ĻƒĪ· settings.webhook.headers=ĪšĪµĻ†Ī±Ī»ĪÆĪ“ĪµĻ‚ settings.webhook.payload=Ī ĪµĻĪ¹ĪµĻ‡ĻŒĪ¼ĪµĪ½Īæ settings.webhook.body=Ī£ĻŽĪ¼Ī± +settings.webhook.replay.description=Ī•Ļ€Ī±Ī½Ī¬Ī»Ī·ĻˆĪ· Ī±Ļ…Ļ„ĪæĻ του webhook. +settings.webhook.delivery.success=Ένα Ī³ĪµĪ³ĪæĪ½ĻŒĻ‚ έχει Ļ€ĻĪæĻƒĻ„ĪµĪøĪµĪÆ ĻƒĻ„Ī·Ī½ ουρά Ļ€Ī±ĻĪ¬Ī“ĪæĻƒĪ·Ļ‚. ĪœĻ€ĪæĻĪµĪÆ να Ļ‡ĻĪµĪ¹Ī±ĻƒĻ„ĪæĻĪ½ λίγα Ī“ĪµĻ…Ļ„ĪµĻĻŒĪ»ĪµĻ€Ļ„Ī± μέχρι να ĪµĪ¼Ļ†Ī±Ī½Ī¹ĻƒĻ„ĪµĪÆ ĻƒĻ„Īæ Ī¹ĻƒĻ„ĪæĻĪ¹ĪŗĻŒ. settings.githooks_desc=Τα Ī†Ī³ĪŗĪ¹ĻƒĻ„ĻĪ± Git παρέχονται Ī±Ļ€ĻŒ το ίΓιο το Git. ĪœĻ€ĪæĻĪµĪÆĻ„Īµ να ĪµĻ€ĪµĪ¾ĪµĻĪ³Ī±ĻƒĻ„ĪµĪÆĻ„Īµ τα αρχεία Ī±Ī³ĪŗĪÆĻƒĻ„ĻĻ‰Ī½ παρακάτω για να ĻĻ…ĪøĪ¼ĪÆĻƒĪµĻ„Īµ Ļ€ĻĪæĻƒĪ±ĻĪ¼ĪæĻƒĪ¼Ī­Ī½ĪµĻ‚ λειτουργίες. settings.githook_edit_desc=Αν το hook είναι ανενεργό, θα Ļ€Ī±ĻĪæĻ…ĻƒĪ¹Ī±ĻƒĻ„ĪµĪÆ ένα παράΓειγμα. Αφήνοντας το Ļ€ĪµĻĪ¹ĪµĻ‡ĻŒĪ¼ĪµĪ½Īæ του hook κενό θα το Ī±Ļ€ĪµĪ½ĪµĻĪ³ĪæĻ€ĪæĪ¹Ī®ĻƒĪµĻ„Īµ. settings.githook_name=Όνομα Hook @@ -2079,6 +2117,7 @@ diff.protected=Ī ĻĪæĻƒĻ„Ī±Ļ„ĪµĻ…Ī¼Ī­Ī½Īæ diff.image.side_by_side=Δίπλα Δίπλα diff.image.swipe=Ī£ĻĻĻƒĪ¹Ī¼Īæ diff.image.overlay=Ī•Ļ€Ī¹ĪŗĪ¬Ī»Ļ…ĻˆĪ· +diff.has_escaped=Αυτή Ī· γραμμή έχει ĪŗĻĻ…Ļ†ĪæĻĻ‚ χαρακτήρες Unicode releases.desc=Ī Ī±ĻĪ±ĪŗĪæĪ»ĪæĻĪøĪ·ĻƒĪ· ĪµĪŗĪ“ĻŒĻƒĪµĻ‰Ī½ έργου και Ī»Ī®ĻˆĪµĻ‰Ī½. release.releases=ĪšĻ…ĪŗĪ»ĪæĻ†ĪæĻĪÆĪµĻ‚ @@ -2154,6 +2193,7 @@ branch.new_branch_from=Δημιουργία νέου κλάΓου Ī±Ļ€ĻŒ '%s' branch.renamed=Ο κλάΓος %s Ī¼ĪµĻ„ĪæĪ½ĪæĪ¼Ī¬ĻƒĻ„Ī·ĪŗĪµ σε %s. tag.create_tag=Δημιουργία ετικέτας %s + tag.create_success=Ī— ετικέτα '%s' έχει Γημιουργηθεί. topic.manage_topics=Ī”Ī¹Ī±Ļ‡ĪµĪÆĻĪ¹ĻƒĪ· Ī˜ĪµĪ¼Ī¬Ļ„Ļ‰Ī½ @@ -2240,7 +2280,13 @@ teams.leave=Ī‘Ļ€ĪæĻ‡ĻŽĻĪ·ĻƒĪ· teams.leave.detail=Ī‘Ļ€ĪæĻ‡ĻŽĻĪ·ĻƒĪ· Ī±Ļ€ĻŒ %s; teams.can_create_org_repo=Δημιουργία αποθετηρίων teams.can_create_org_repo_helper=Τα μέλη Ī¼Ļ€ĪæĻĪæĻĪ½ να Ī“Ī·Ī¼Ī¹ĪæĻ…ĻĪ³Ī®ĻƒĪæĻ…Ī½ νέα αποθετήρια ĻƒĻ„ĪæĪ½ οργανισμό. Ο Ī“Ī·Ī¼Ī¹ĪæĻ…ĻĪ³ĻŒĻ‚ θα Ī±Ļ€ĪæĪŗĻ„Ī®ĻƒĪµĪ¹ Ļ€ĻĻŒĻƒĪ²Ī±ĻƒĪ· Ī“Ī¹Ī±Ļ‡ĪµĪ¹ĻĪ¹ĻƒĻ„Ī® ĻƒĻ„Īæ νέο αποθετήριο. +teams.none_access=Καμία Πρόσβαση +teams.none_access_helper=Τα μέλη Γεν Ī¼Ļ€ĪæĻĪæĻĪ½ να Γουν Ī® να κάνουν οποιαΓήποτε άλλη ενέργεια σε αυτή τη μονάΓα. +teams.general_access=Γενική Πρόσβαση +teams.general_access_helper=Τα Ī“Ī¹ĪŗĪ±Ī¹ĻŽĪ¼Ī±Ļ„Ī± των Ī¼ĪµĪ»ĻŽĪ½ Ī±Ļ€ĪæĻ†Ī±ĻƒĪÆĪ¶ĪæĪ½Ļ„Ī±Ī¹ Ī±Ļ€ĻŒ το παρακάτω πίνακα Ī±Ī“ĪµĪ¹ĻŽĪ½. +teams.read_access=Ī‘Ī½Ī¬Ī³Ī½Ļ‰ĻƒĪ· teams.read_access_helper=Τα μέλη Ī¼Ļ€ĪæĻĪæĻĪ½ να Γουν και να ĪŗĪ»Ļ‰Ī½ĪæĻ€ĪæĪ¹Ī®ĻƒĪæĻ…Ī½ τα αποθετήρια της ομάΓας. +teams.write_access=Εγγραφή teams.write_access_helper=Τα μέλη Ī¼Ļ€ĪæĻĪæĻĪ½ να Γουν και να ĪŗĪ»Ļ‰Ī½ĪæĻ€ĪæĪ¹Ī®ĻƒĪæĻ…Ī½ τα αποθετήρια της ομάΓας. teams.admin_access=Πρόσβαση Ī”Ī¹Ī±Ļ‡ĪµĪ¹ĻĪ¹ĻƒĻ„Ī® teams.admin_access_helper=Τα μέλη Ī¼Ļ€ĪæĻĪæĻĪ½ να κάνουν push και pull ĻƒĻ„Ī± αποθετήρια της ομάΓας ĻŒĻ€Ļ‰Ļ‚ και να Ļ€ĻĪæĻƒĪøĪ­ĻƒĪæĻ…Ī½ ĻƒĻ…Ī½ĪµĻĪ³Ī¬Ļ„ĪµĻ‚ σε αυτά. @@ -2869,6 +2915,7 @@ error.probable_bad_signature=Ī Ī”ĪŸĪ£ĪŸĪ§Ī—! Αν και υπάρχει ένα error.probable_bad_default_signature=Ī Ī”ĪŸĪ£ĪŸĪ§Ī—! Αν και το προεπιλεγμένο κλειΓί έχει Ī±Ļ…Ļ„ĻŒ το ID, Γεν ĪµĻ€Ī±Ī»Ī·ĪøĪµĻĪµĪ¹ αυτή την υποβολή! Αυτή Ī· υποβολή είναι Ī„Ī ĪŸĪ Ī¤Ī—. [units] +unit=ΜονάΓα error.no_unit_allowed_repo=Δεν ĻƒĪ±Ļ‚ επιτρέπεται να έχετε Ļ€ĻĻŒĻƒĪ²Ī±ĻƒĪ· σε οποιαΓήποτε ĪµĪ½ĻŒĻ„Ī·Ļ„Ī± Ī±Ļ…Ļ„ĪæĻ του αποθετηρίου. error.unit_not_allowed=Δεν ĻƒĪ±Ļ‚ επιτρέπεται να έχετε Ļ€ĻĻŒĻƒĪ²Ī±ĻƒĪ· σε αυτήν την ĪµĪ½ĻŒĻ„Ī·Ļ„Ī± αποθετηρίου. diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index d8398f6d9f..2fbf7e79bc 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2334,6 +2334,7 @@ first_page = First last_page = Last total = Total: %d +dashboard.new_version_hint = Gitea %s is now available, you are running %s. Check the blog for more details. dashboard.statistic = Summary dashboard.operations = Maintenance Operations dashboard.system_status = System Status @@ -2407,6 +2408,7 @@ dashboard.last_gc_pause = Last GC Pause dashboard.gc_times = GC Times dashboard.delete_old_actions = Delete all old actions from database dashboard.delete_old_actions.started = Delete all old actions from database started. +dashboard.update_checker = Update checker users.user_manage_panel = User Account Management users.new_account = Create User Account diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index fcfb2dcb76..36746ad04c 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -34,6 +34,20 @@ twofa=2č¦ē“ čŖčØ¼ twofa_scratch=2č¦ē“ čŖčØ¼ć‚¹ć‚Æćƒ©ćƒƒćƒć‚³ćƒ¼ćƒ‰ passcode=ćƒ‘ć‚¹ć‚³ćƒ¼ćƒ‰ +webauthn_insert_key=ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ć‚’ęŒæå…„ +webauthn_sign_in=ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ć®ćƒœć‚æćƒ³ć‚’ęŠ¼ć—ć¦ćć ć•ć„ć€‚ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ć«ćƒœć‚æćƒ³ćŒē„”ć„å “åˆćÆć€ęŒæå…„ć—ćŖćŠć—ć¦ćć ć•ć„ć€‚ +webauthn_press_button=ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ć®ćƒœć‚æćƒ³ć‚’ęŠ¼ć—ć¦ćć ć•ć„... +webauthn_use_twofa=携帯電話から2č¦ē“ čŖčØ¼ć‚³ćƒ¼ćƒ‰ć‚’ä½æē”Øć™ć‚‹ +webauthn_error=ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ć‚’čŖ­ćæå–ć‚‹ć“ćØćŒć§ćć¾ć›ć‚“ć€‚ +webauthn_unsupported_browser=ćŠä½æć„ć®ćƒ–ćƒ©ć‚¦ć‚¶ćÆē¾åœØ WebAuthn ć‚’ć‚µćƒćƒ¼ćƒˆć—ć¦ć„ć¾ć›ć‚“ć€‚ +webauthn_error_unknown=äøę˜ŽćŖć‚Øćƒ©ćƒ¼ćŒē™ŗē”Ÿć—ć¾ć—ćŸć€‚ ć‚‚ć†äø€åŗ¦ć‚„ć‚Šē›“ć—ć¦ćć ć•ć„ć€‚ +webauthn_error_insecure=WebAuthn ćÆć‚»ć‚­ćƒ„ć‚¢ćŖęŽ„ē¶šć®ćæć‚’ć‚µćƒćƒ¼ćƒˆć—ć¦ć„ć¾ć™ć€‚HTTP ēµŒē”±ć§ćƒ†ć‚¹ćƒˆć™ć‚‹å “åˆćÆć€"localhost" または "127.0.0.1" ć®ć‚ŖćƒŖć‚øćƒ³ćŒä½æē”Øć§ćć¾ć™ć€‚ +webauthn_error_unable_to_process=ć‚µćƒ¼ćƒćƒ¼ćŒćƒŖć‚Æć‚Øć‚¹ćƒˆć‚’å‡¦ē†ć§ćć¾ć›ć‚“ć§ć—ćŸć€‚ +webauthn_error_duplicated=ć“ć®ćƒŖć‚Æć‚Øć‚¹ćƒˆć«åÆ¾ć—ć¦ćÆć€čØ±åÆć•ć‚Œć¦ć„ćŖć„ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ć§ć™ć€‚ ć‚­ćƒ¼ćŒęœŖē™»éŒ²ć§ć‚ć‚‹ć“ćØć‚’ē¢ŗčŖć—ć¦ćć ć•ć„ć€‚ +webauthn_error_empty=ć“ć®ć‚­ćƒ¼ć«åå‰ć‚’čØ­å®šć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚ +webauthn_error_timeout=ć‚­ćƒ¼ć‚’čŖ­ćæå–ć‚‹å‰ć«ć‚æć‚¤ćƒ ć‚¢ć‚¦ćƒˆć«ćŖć‚Šć¾ć—ćŸć€‚ ć“ć®ćƒšćƒ¼ć‚øć‚’ćƒŖćƒ­ćƒ¼ćƒ‰ć—ć¦ć‚‚ć†äø€åŗ¦ć‚„ć‚Šē›“ć—ć¦ćć ć•ć„ć€‚ +webauthn_u2f_deprecated=ć‚­ćƒ¼: '%s' ćÆéžęŽØå„Øć®U2Fćƒ—ćƒ­ć‚»ć‚¹ć‚’ä½æē”Øć—ć¦čŖčØ¼ć—ć¦ć„ć¾ć™ć€‚ć“ć®ć‚­ćƒ¼ć‚’å†ē™»éŒ²ć—ć¦å¤ć„ē™»éŒ²ć‚’å‰Šé™¤ć—ćŸć»ć†ćŒč‰Æć„ć§ć—ć‚‡ć†ć€‚ +webauthn_reload=ćƒŖćƒ­ćƒ¼ćƒ‰ repository=ćƒŖćƒć‚øćƒˆćƒŖ organization=組織 @@ -513,6 +527,7 @@ twofa=2č¦ē“ čŖčØ¼ account_link=é€£ęŗć‚¢ć‚«ć‚¦ćƒ³ćƒˆ organization=組織 uid=Uid +webauthn=ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ public_profile=å…¬é–‹ćƒ—ćƒ­ćƒ•ć‚£ćƒ¼ćƒ« biography_placeholder=自己瓹介を少しだけ @@ -534,6 +549,8 @@ continue=続蔌 cancel=ć‚­ćƒ£ćƒ³ć‚»ćƒ« language=čØ€čŖž ui=ćƒ†ćƒ¼ćƒž +hidden_comment_types=éžč”Øē¤ŗć«ć™ć‚‹ć‚³ćƒ”ćƒ³ćƒˆć®ēØ®é”ž +saved_successfully=čØ­å®šćÆę­£åøøć«äæå­˜ć•ć‚Œć¾ć—ćŸć€‚ privacy=ćƒ—ćƒ©ć‚¤ćƒć‚·ćƒ¼ keep_activity_private=ćƒ—ćƒ­ćƒ•ć‚£ćƒ¼ćƒ«ćƒšćƒ¼ć‚øć®ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£č”Øē¤ŗć‚’éš ć™ keep_activity_private_popup=ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£ć‚’ć€ć‚ćŖćŸćØē®”ē†č€…ć«ć®ćæč”Øē¤ŗć—ć¾ć™ @@ -733,6 +750,11 @@ passcode_invalid=ćƒ‘ć‚¹ć‚³ćƒ¼ćƒ‰ćŒé–“é•ć£ć¦ć„ć¾ć™ć€‚ å†åŗ¦ćŠč©¦ć—ć twofa_enrolled=ć‚ćŖćŸć®ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć«2č¦ē“ čŖčØ¼ćŒčØ­å®šć•ć‚Œć¾ć—ćŸć€‚ ć‚¹ć‚Æćƒ©ćƒƒćƒćƒˆćƒ¼ć‚Æćƒ³ (%s) ćÆäø€åŗ¦ć—ć‹č”Øē¤ŗć—ć¾ć›ć‚“ć®ć§å®‰å…ØćŖå “ę‰€ć«äæå­˜ć—ć¦ćć ć•ć„ļ¼ twofa_failed_get_secret=ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćŒå–å¾—ć§ćć¾ć›ć‚“ć€‚ +webauthn_desc=ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ćÆęš—å·åŒ–ć‚­ćƒ¼ć‚’å†…č”µć™ć‚‹ćƒćƒ¼ćƒ‰ć‚¦ć‚§ć‚¢ 惻 ćƒ‡ćƒć‚¤ć‚¹ć§ć™ć€‚ 2č¦ē“ čŖčØ¼ć«ä½æē”Øć§ćć¾ć™ć€‚ ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ćÆWebAuthn Authenticatorč¦ę ¼ć‚’ć‚µćƒćƒ¼ćƒˆć—ć¦ć„ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚ +webauthn_register_key=ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ć‚’čæ½åŠ  +webauthn_nickname=ćƒ‹ćƒƒć‚Æćƒćƒ¼ćƒ  +webauthn_delete_key=ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ć®ē™»éŒ²č§£é™¤ +webauthn_delete_key_desc=ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ć®ē™»éŒ²ć‚’č§£é™¤ć™ć‚‹ćØć€ä»Šå¾Œćć®ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć‚­ćƒ¼ć§ć‚µć‚¤ćƒ³ć‚¤ćƒ³ć™ć‚‹ć“ćØćÆć§ććŖććŖć‚Šć¾ć™ć€‚ ē¶šč”Œć—ć¾ć™ć‹ļ¼Ÿ manage_account_links=é€£ęŗć‚¢ć‚«ć‚¦ćƒ³ćƒˆć®ē®”ē† manage_account_links_desc=ć“ć‚Œć‚‰ć®å¤–éƒØć‚¢ć‚«ć‚¦ćƒ³ćƒˆćŒGiteać‚¢ć‚«ć‚¦ćƒ³ćƒˆćØé€£ęŗć•ć‚Œć¦ć„ć¾ć™ć€‚ @@ -1038,6 +1060,10 @@ editor.add_tmpl='<ćƒ•ć‚”ć‚¤ćƒ«å>' ć‚’čæ½åŠ  editor.add='%s' ć‚’čæ½åŠ  editor.update='%s' 悒ꛓꖰ editor.delete='%s' ć‚’å‰Šé™¤ +editor.patch=ćƒ‘ćƒƒćƒć®é©ē”Ø +editor.patching=惑惃惁: +editor.fail_to_apply_patch=ćƒ‘ćƒƒćƒć‚’é©ē”Øć§ćć¾ć›ć‚“ '%s' +editor.new_patch=ꖰ恗恄惑惃惁 editor.commit_message_desc=č©³ē“°ćŖčŖ¬ę˜Žć‚’čæ½åŠ ā€¦ editor.signoff_desc=ć‚³ćƒŸćƒƒćƒˆćƒ­ć‚°ćƒ”ćƒƒć‚»ćƒ¼ć‚øć®ęœ€å¾Œć«ć‚³ćƒŸćƒƒć‚æćƒ¼ć® Signed-off-by č”Œć‚’čæ½åŠ  editor.commit_directly_to_this_branch=ćƒ–ćƒ©ćƒ³ćƒ%sćøē›“ęŽ„ć‚³ćƒŸćƒƒćƒˆć™ć‚‹ć€‚ @@ -1073,6 +1099,8 @@ editor.cannot_commit_to_protected_branch=äæč­·ć•ć‚ŒćŸćƒ–ćƒ©ćƒ³ćƒ '%s' にコ editor.no_commit_to_branch=ćƒ–ćƒ©ćƒ³ćƒć«ē›“ęŽ„ć‚³ćƒŸćƒƒćƒˆć™ć‚‹ć“ćØćÆć§ćć¾ć›ć‚“ć€ćŖćœćŖć‚‰: editor.user_no_push_to_branch=ćƒ¦ćƒ¼ć‚¶ćƒ¼ćÆćƒ–ćƒ©ćƒ³ćƒć«ćƒ—ćƒƒć‚·ćƒ„ć§ćć¾ć›ć‚“ editor.require_signed_commit=ćƒ–ćƒ©ćƒ³ćƒć§ćÆē½²åć•ć‚ŒćŸć‚³ćƒŸćƒƒćƒˆćŒåæ…é ˆć§ć™ +editor.cherry_pick=ćƒć‚§ćƒŖćƒ¼ćƒ”ćƒƒć‚Æ %s: +editor.revert=リバート %s: commits.desc=ć‚½ćƒ¼ć‚¹ć‚³ćƒ¼ćƒ‰ć®å¤‰ę›“å±„ę­“ć‚’å‚ē…§ć—ć¾ć™ć€‚ commits.commits=ć‚³ćƒŸćƒƒćƒˆ @@ -1093,6 +1121,7 @@ commits.signed_by_untrusted_user_unmatched=ć‚³ćƒŸćƒƒć‚æćƒ¼ćØäø€č‡“ć—ćŖć„äæ” commits.gpg_key_id=GPGć‚­ćƒ¼ID commits.ssh_key_fingerprint=SSHéµć®ćƒ•ć‚£ćƒ³ć‚¬ćƒ¼ćƒ—ćƒŖćƒ³ćƒˆ + ext_issues=å¤–éƒØć‚¤ć‚·ćƒ„ćƒ¼ćøć®ć‚¢ć‚Æć‚»ć‚¹ ext_issues.desc=å¤–éƒØć®ć‚¤ć‚·ćƒ„ćƒ¼ćƒˆćƒ©ćƒƒć‚«ćƒ¼ćøć®ćƒŖćƒ³ć‚Æć€‚ @@ -2314,6 +2343,7 @@ first_page=ęœ€åˆ last_page=ęœ€å¾Œ total=合計: %d +dashboard.new_version_hint=Gitea %s ćŒå…„ę‰‹åÆčƒ½ć«ćŖć‚Šć¾ć—ćŸć€‚ ē¾åœØå®Ÿč”Œć—ć¦ć„ć‚‹ć®ćÆ %s 恧恙怂 詳瓰は 惖惭悰 ć‚’ē¢ŗčŖć—ć¦ćć ć•ć„ć€‚ dashboard.statistic=ć‚µćƒžćƒŖćƒ¼ dashboard.operations=ćƒ”ćƒ³ćƒ†ćƒŠćƒ³ć‚¹ę“ä½œ dashboard.system_status=ć‚·ć‚¹ćƒ†ćƒ ēŠ¶ę³ @@ -2387,6 +2417,7 @@ dashboard.last_gc_pause=å‰å›žć®GCåœę­¢ę™‚é–“ dashboard.gc_times=GCå®Ÿč”Œå›žę•° dashboard.delete_old_actions=ćƒ‡ćƒ¼ć‚æćƒ™ćƒ¼ć‚¹ć‹ć‚‰å¤ć„ę“ä½œå±„ę­“ć‚’ć™ć¹ć¦å‰Šé™¤ dashboard.delete_old_actions.started=ćƒ‡ćƒ¼ć‚æćƒ™ćƒ¼ć‚¹ć‹ć‚‰ć®å¤ć„ę“ä½œå±„ę­“ć®å‰Šé™¤ć‚’é–‹å§‹ć—ć¾ć—ćŸć€‚ +dashboard.update_checker=ę›“ę–°ćƒć‚§ćƒƒć‚Æ users.user_manage_panel=ćƒ¦ćƒ¼ć‚¶ćƒ¼ć‚¢ć‚«ć‚¦ćƒ³ćƒˆē®”ē† users.new_account=ćƒ¦ćƒ¼ć‚¶ćƒ¼ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’ä½œęˆ diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 6688d99c77..8a04cc0e9a 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -837,7 +837,7 @@ default_branch=Ramo principal default_branch_helper=O ramo principal Ć© o ramo base para pedidos de integração e cometimentos. mirror_prune=Podar mirror_prune_desc=Remover referĆŖncias obsoletas de seguimento remoto -mirror_interval=Intervalo de espelhamento (as unidade de tempo vĆ”lidas sĆ£o 'h', 'm' e 's'). O valor zero desabilita a sincronização automĆ”tica. +mirror_interval=Intervalo de espelhamento (as unidades de tempo vĆ”lidas sĆ£o 'h', 'm' e 's'). O valor zero desabilita a sincronização automĆ”tica. mirror_interval_invalid=O intervalo do espelhamento nĆ£o Ć© vĆ”lido. mirror_address=Clonar a partir do URL mirror_address_desc=Coloque, na secção de Autorização, as credenciais que, eventualmente, sejam necessĆ”rias. @@ -2334,6 +2334,7 @@ first_page=Primeira last_page=Última total=total: %d +dashboard.new_version_hint=O Gitea %s estĆ” agora disponĆ­vel, vocĆŖ estĆ” a correr a versĆ£o %s. Verifique o blog para mais detalhes. dashboard.statistic=Resumo dashboard.operations=OperaƧƵes de manutenção dashboard.system_status=Estado do sistema @@ -2407,6 +2408,7 @@ dashboard.last_gc_pause=Última pausa da recolha de lixo dashboard.gc_times=Tempos da recolha de lixo dashboard.delete_old_actions=Eliminar todas as operaƧƵes antigas da base de dados dashboard.delete_old_actions.started=Foi iniciado o processo de eliminação de todas as operaƧƵes antigas da base de dados. +dashboard.update_checker=Verificador de novas versƵes users.user_manage_panel=GestĆ£o das contas de utilizadores users.new_account=Criar conta de utilizador diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index d0d500f069..0111dfe434 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -781,7 +781,7 @@ template_helper=Š”Š“ŠµŠ»Š°Ń‚ŃŒ репозиторий шаблоном template_description=Шаблонные репозитории Š“Š°ŃŽŃ‚ Š²Š¾Š·Š¼Š¾Š¶Š½Š¾ŃŃ‚ŃŒ ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŃŠ¼ ŃŠ¾Š·Š“Š°Š²Š°Ń‚ŃŒ новые репозитории с той же ŃŃ‚Ń€ŃƒŠŗŃ‚ŃƒŃ€Š¾Š¹ каталогов, файлами Šø Š“Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Š¼Šø настройками. visibility=Š’ŠøŠ“ŠøŠ¼Š¾ŃŃ‚ŃŒ visibility_description=Только влаГелец или члены организации, при наличии прав, ŃŠ¼Š¾Š³ŃƒŃ‚ ŃƒŠ²ŠøŠ“ŠµŃ‚ŃŒ ŃŃ‚Š¾. -visibility_helper=Š”Š“ŠµŠ»Š°Ń‚ŃŒ репозиторий приватным +visibility_helper=Š”Š“ŠµŠ»Š°Ń‚ŃŒ репозиторий частным visibility_helper_forced=АГминистратор сайта настроил параметр виГимости новых репозиториев. Репозиторий приватный по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ. visibility_fork_helper=(Изменение ŃŃ‚Š¾Š³Š¾ ŠæŠ¾Š²Š»ŠøŃŠµŃ‚ на все форки.) clone_helper=ŠŃƒŠ¶Š½Š° ŠæŠ¾Š¼Š¾Ń‰ŃŒ в клонировании? ŠŸŠ¾ŃŠµŃ‚ŠøŃ‚Šµ ŃŃ‚Ń€Š°Š½ŠøŃ†Ńƒ помощи. @@ -1435,7 +1435,7 @@ pulls.manually_merged=Длито Š²Ń€ŃƒŃ‡Š½ŃƒŃŽ pulls.manually_merged_as=Запрос на ŃŠ»ŠøŃŠ½ŠøŠµ был Š¾Š±ŃŠŠµŠ“инён Š²Ń€ŃƒŃ‡Š½ŃƒŃŽ, как %[2]s. pulls.is_closed=Запрос на ŃŠ»ŠøŃŠ½ŠøŠµ был закрыт. pulls.has_merged=Š”Š»ŠøŃŠ½ŠøŠµ ŃŃ‚Š¾Š³Š¾ запроса успешно Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š¾. -pulls.title_wip_desc=`Š”Š¾Š±Š°Š²ŃŒŃ‚Šµ %s в начало заголовка Š“Š»Ń защиты от ŃŠ»ŃƒŃ‡Š°Š¹Š½Š¾Š³Š¾ Госрочного ŠæŃ€ŠøŠ½ŃŃ‚ŠøŃ запроса на ŃŠ»ŠøŃŠ½ŠøŠµ +pulls.title_wip_desc=`Š”Š¾Š±Š°Š²ŃŒŃ‚Šµ %s в начало заголовка Š“Š»Ń защиты от ŃŠ»ŃƒŃ‡Š°Š¹Š½Š¾Š³Š¾ Госрочного ŠæŃ€ŠøŠ½ŃŃ‚ŠøŃ запроса на ŃŠ»ŠøŃŠ½ŠøŠµ` pulls.cannot_merge_work_in_progress=Этот запрос на ŃŠ»ŠøŃŠ½ŠøŠµ помечен как в процессе работы. pulls.still_in_progress=Всё ещё в процессе? pulls.add_prefix=Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ %s префикс diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 25eb059ca4..9aca8c8126 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -34,6 +34,7 @@ twofa=Двофакторна Š°Š²Ń‚Š¾Ń€ŠøŠ·Š°Ń†Ń–Ń twofa_scratch=Двофакторний оГноразовий ŠæŠ°Ń€Š¾Š»ŃŒ passcode=КоГ Š“Š¾ŃŃ‚ŃƒŠæŃƒ +webauthn_reload=ŠžŠ½Š¾Š²ŠøŃ‚Šø repository=Репозиторій organization=ŠžŃ€Š³Š°Š½Ń–Š·Š°Ń†Ń–Ń @@ -61,7 +62,7 @@ forks=Форки activities=Дії pull_requests=Запити на Š·Š»ŠøŃ‚Ń‚Ń -issues=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Šø +issues=ЗаГачі milestones=Етапи ok=OK @@ -92,7 +93,9 @@ error404=Дторінка, Го ŃŠŗŠ¾Ń— ви Š½Š°Š¼Š°Š³Š°Ń”Ń‚ŠµŃŃ зверн never=ŠŃ–ŠŗŠ¾Š»Šø [error] +occurred=Š”Ń‚Š°Š»Š°ŃŃ помилка missing_csrf=ŠŠµŠŗŠ¾Ń€ŠµŠŗŃ‚Š½ŠøŠ¹ запит: токен CSRF не заГано +network_error=Помилка мережі [startpage] app_desc=Š—Ń€ŃƒŃ‡Š½ŠøŠ¹ власний сервіс Ń…Š¾ŃŃ‚ŠøŠ½Š³Ńƒ репозиторіїв Git @@ -346,7 +349,7 @@ reset_password.text=ŠŸŠµŃ€ŠµŠ¹Š“Ń–Ń‚ŃŒ за цим ŠæŠ¾ŃŠøŠ»Š°Š½Š½ŃŠ¼, щоб register_success=Š ŠµŃ”ŃŃ‚Ń€Š°Ń†Ń–Ń ŃƒŃŠæŃ–ŃˆŠ½Š° issue_assigned.pull=@%[1]s призначив вам запит Š·Š»ŠøŃ‚Ń‚Ń %[2]s в репозиторії %[3]s. -issue_assigned.issue=@%[1]s призначив вам Š·Š°Š²Š“Š°Š½Š½Ń %[2]s у репозиторії %[3]s. +issue_assigned.issue=@%[1]s призначив вам Š·Š°Š“Š°Ń‡Ńƒ %[2]s у репозиторії %[3]s. issue.x_mentioned_you=@%s згаГав вас: issue.action.force_push=%[1]s force-pushed %[2]s Š· %[3]s в %[4]s. @@ -474,7 +477,7 @@ activity=ŠŸŃƒŠ±Š»Ń–Ń‡Š½Š° Š°ŠŗŃ‚ŠøŠ²Š½Ń–ŃŃ‚ŃŒ followers=Читачі starred=ŠžŠ±Ń€Š°Š½Ń– Репозиторії watched=Š’Ń–Š“ŃŃ‚ŠµŠ¶ŃƒŠ²Š°Š½Ń– репозиторії -projects=ŠŸŃ€Š¾ŠµŠŗŃ‚Šø +projects=ŠŸŃ€Š¾Ń”ŠŗŃ‚ following=Читає follow=ŠŸŃ–Š“ŠæŠøŃŠ°Ń‚ŠøŃŃ unfollow=Š’Ń–Š“ŠæŠøŃŠ°Ń‚ŠøŃŃ @@ -611,6 +614,7 @@ gpg_token_help=Š’Šø можете створити піГпис за Гопомо gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Текстовий (armored) піГпис GPG key_signature_gpg_placeholder=ŠŸŠ¾Ń‡ŠøŠ½Š°Ń”Ń‚ŃŒŃŃ Š· "-----BEGIN PGP SIGNATURE-----" +ssh_token=Токен subkeys=ŠŸŃ–Š“ŠŗŠ»ŃŽŃ‡Ń– key_id=ID ŠŗŠ»ŃŽŃ‡Š° key_name=Ім'я ŠŗŠ»ŃŽŃ‡Š° @@ -743,7 +747,7 @@ visibility.private=ŠŸŃ€ŠøŠ²Š°Ń‚Š½ŠøŠ¹ visibility.private_tooltip=ВиГимий лише членам організації [repo] -new_repo_helper=Репозиторій Š¼Ń–ŃŃ‚ŠøŃ‚ŃŒ усі файли ŠæŃ€Š¾ŠµŠŗŃ‚Ńƒ, Š²ŠŗŠ»ŃŽŃ‡Š°ŃŽŃ‡Šø Ń–ŃŃ‚Š¾Ń€Ń–ŃŽ ревізій. Ще Гесь є? ŠœŃ–Š³Ń€ŃƒŠ²Š°Ń‚Šø репозиторій. +new_repo_helper=Репозиторій Š¼Ń–ŃŃ‚ŠøŃ‚ŃŒ усі файли ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ, Š²ŠŗŠ»ŃŽŃ‡Š°ŃŽŃ‡Šø Ń–ŃŃ‚Š¾Ń€Ń–ŃŽ ревізій. Ще Гесь є? ŠœŃ–Š³Ń€ŃƒŠ²Š°Ń‚Šø репозиторій. owner=Власник owner_helper=Š”ŠµŃŠŗŃ– організації Š¼Š¾Š¶ŃƒŃ‚ŃŒ не Š²Ń–Š“Š¾Š±Ń€Š°Š¶Š°Ń‚ŠøŃŃ у Š²ŠøŠæŠ°Š“Š°ŃŽŃ‡Š¾Š¼Ńƒ списку через максимальну ŠŗŃ–Š»ŃŒŠŗŃ–ŃŃ‚ŃŒ репозиторііїв. repo_name=ŠŠ°Š·Š²Š° Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ @@ -774,14 +778,14 @@ repo_desc_helper=Š’Š²ŠµŠ“Ń–Ń‚ŃŒ короткий опис (Š¾ŠæŃ†Ń–Š¾Š½Š°Š»ŃŒŠ½ repo_lang=Мова repo_gitignore_helper=Š’ŠøŠ±ŠµŃ€Ń–Ń‚ŃŒ шаблон .gitignore. repo_gitignore_helper_desc=ŠžŠ±ŠµŃ€Ń–Ń‚ŃŒ Š· списку мовних ŃˆŠ°Š±Š»Š¾Š½Ń–Š² файли, ŃŠŗŃ– не Š±ŃƒŠ“ŃƒŃ‚ŃŒ Š²Ń–Š“ŃŃ‚ŠµŠ¶ŃƒŠ²Š°Ń‚ŠøŃŃŒ. Типові артефакти, ŃŠŗŃ– Š³ŠµŠ½ŠµŃ€ŃƒŃŽŃ‚ŃŒŃŃ за Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾ŃŽ Ń–Š½ŃŃ‚Ń€ŃƒŠ¼ŠµŠ½Ń‚Ń–Š² побуГови кожної мови, за Š·Š°Š¼Š¾Š²Ń‡ŃƒŠ²Š°Š½Š½ŃŠ¼ Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Ń– Го .gitignor. -issue_labels=ŠœŃ–Ń‚ŠŗŠø проблем -issue_labels_helper=Вибрати Š¼Ń–Ń‚ŠŗŃƒ Š“Š»Ń проблеми. +issue_labels=ŠœŃ–Ń‚ŠŗŠø заГачі +issue_labels_helper=Вибрати Š¼Ń–Ń‚ŠŗŃƒ Š“Š»Ń заГачі. license=Š›Ń–Ń†ŠµŠ½Š·Ń–Ń license_helper=Š’ŠøŠ±ŠµŃ€Ń–Ń‚ŃŒ ліцензійний файл. -license_helper_desc=Š›Ń–Ń†ŠµŠ½Š·Ń–Ń Ń€ŠµŠ³ŃƒŠ»ŃŽŃ” те, що Ń–Š½ŃˆŃ– Š¼Š¾Š¶ŃƒŃ‚ŃŒ і не Š¼Š¾Š¶ŃƒŃ‚ŃŒ робити Š· вашим коГом. ŠŠµ впевнені, що саме ŠæŃ–Š“Ń…Š¾Š“ŠøŃ‚ŃŒ Š“Š»Ń вашого ŠæŃ€Š¾ŠµŠŗŃ‚Ńƒ? Š”ŠøŠ²Ń–Ń‚ŃŒŃŃ Š’ŠøŠ±ŠµŃ€Ń–Ń‚ŃŒ Š»Ń–Ń†ŠµŠ½Š·Ń–ŃŽ. +license_helper_desc=Š›Ń–Ń†ŠµŠ½Š·Ń–Ń Ń€ŠµŠ³ŃƒŠ»ŃŽŃ” те, що Ń–Š½ŃˆŃ– Š¼Š¾Š¶ŃƒŃ‚ŃŒ і не Š¼Š¾Š¶ŃƒŃ‚ŃŒ робити Š· вашим коГом. ŠŠµ впевнені, що саме ŠæŃ–Š“Ń…Š¾Š“ŠøŃ‚ŃŒ Š“Š»Ń вашого ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ? Š”ŠøŠ²Ń–Ń‚ŃŒŃŃ Š’ŠøŠ±ŠµŃ€Ń–Ń‚ŃŒ Š»Ń–Ń†ŠµŠ½Š·Ń–ŃŽ. readme=README readme_helper=Š’ŠøŠ±ŠµŃ€Ń–Ń‚ŃŒ шаблон README. -readme_helper_desc=Це місце, Ге ви можете написати повний опис вашого ŠæŃ€Š¾ŠµŠŗŃ‚Ńƒ. +readme_helper_desc=Це місце, Ге ви можете написати повний опис вашого ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ. auto_init=Š†Š½Ń–Ń†Ń–Š°Š»Ń–Š·ŃƒŠ²Š°Ń‚Šø репозиторій (ДоГає .gitignore, LICENSE та README) trust_model_helper=Š’ŠøŠ±ŠµŃ€Ń–Ń‚ŃŒ моГель Говіри Š“Š»Ń ŠæŃ–Š“Ń‚Š²ŠµŃ€Š“Š¶ŠµŠ½Š½Ń ŠæŃ–Š“ŠæŠøŃŃƒ. ŠœŠ¾Š¶Š»ŠøŠ²Ń– варіанти: trust_model_helper_collaborator=Дпівавтор: піГписи Говіри віГ співавторів @@ -846,12 +850,12 @@ template.git_hooks=ŠŸŠµŃ€ŠµŃ…Š¾ŠæŠ»ŃŽŠ²Š°Ń‡Ń– Git template.webhooks=Webhook'Šø template.topics=Теми template.avatar=Аватар -template.issue_labels=ŠœŃ–Ń‚ŠŗŠø проблем +template.issue_labels=ŠœŃ–Ń‚ŠŗŠø заГачі template.one_item=ДліГ обрати хоча б оГин елемент шаблону template.invalid=ДліГ обрати шаблонний репозиторій -archive.title=Це архівний репозитарій. Š’Šø можете ŠæŠµŃ€ŠµŠ³Š»ŃŠ“Š°Ń‚Šø і ŠŗŠ»Š¾Š½ŃƒŠ²Š°Ń‚Šø файли, але не можете робити пуш або віГкривати ŠæŠøŃ‚Š°Š½Š½Ń/запити. -archive.issue.nocomment=Це архівний репозитарій. Š’Šø не можете ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Ń‚Šø запити. +archive.title=Цей репозиторій архівовано. Š’Šø можете ŠæŠµŃ€ŠµŠ³Š»ŃŠ“Š°Ń‚Šø файли та ŠŗŠ»Š¾Š½ŃƒŠ²Š°Ń‚Šø його, але не можете Š²ŠøŠŗŠ¾Š½ŃƒŠ²Š°Ń‚Šø push чи віГкривати заГачі та запити Š·Š»ŠøŃ‚Ń‚Ń. +archive.issue.nocomment=Цей репозиторій архівовано. Š’Šø не можете ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Ń‚Šø заГачі. archive.pull.nocomment=Це архівний репозитарій. Š’Šø не можете ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Ń‚Šø пулл-реквести. form.reach_limit_of_creation_1=Š’Šø вже Š“Š¾ŃŃŠ³Š»Šø Š»Ń–Š¼Ń–Ń‚Ńƒ в %d репозиторіїв. @@ -873,7 +877,7 @@ migrate_items=Деталі міграції migrate_items_wiki=Š’Ń–ŠŗŃ– migrate_items_milestones=Етапи migrate_items_labels=ŠœŃ–Ń‚ŠŗŠø -migrate_items_issues=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Šø +migrate_items_issues=ЗаГачі migrate_items_pullrequests=Запити на Š·Š»ŠøŃ‚Ń‚Ń migrate_items_merge_requests=Запити на Š·Š»ŠøŃ‚Ń‚Ń migrate_items_releases=Релізи @@ -906,7 +910,7 @@ migrate.migrating_topics=ŠœŃ–Š³Ń€Š°Ń†Ń–Ń тем migrate.migrating_milestones=ŠœŃ–Š³Ń€Š°Ń†Ń–Ń етапів migrate.migrating_labels=ŠœŃ–Š³Ń€Š°Ń†Ń–Ń міток migrate.migrating_releases=ŠœŃ–Š³Ń€Š°Ń†Ń–Ń релізів -migrate.migrating_issues=ŠœŃ–Š³Ń€Š°Ń†Ń–Ń проблем +migrate.migrating_issues=ŠœŃ–Š³Ń€Š°Ń†Ń–Ń заГач migrate.migrating_pulls=ŠœŃ–Š³Ń€Š°Ń†Ń–Ń запитів на Š·Š»ŠøŃ‚Ń‚Ń mirror_from=Гзеркало @@ -939,7 +943,7 @@ filter_branch_and_tag=Š¤Ń–Š»ŃŒŃ‚Ń€ŃƒŠ²Š°Ń‚Šø Š³Ń–Š»ŠŗŃƒ або тег find_tag=Знайти тег branches=Гілки tags=Теги -issues=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Šø +issues=ЗаГачі pulls=Запити на Š·Š»ŠøŃ‚Ń‚Ń project_board=ŠŸŃ€Š¾Ń”ŠŗŃ‚Šø labels=ŠœŃ–Ń‚ŠŗŠø @@ -1053,10 +1057,12 @@ commits.signed_by_untrusted_user=ŠŸŃ–Š“ŠæŠøŃŠ°Š½ŠøŠ¹ неГовіреним Šŗ commits.signed_by_untrusted_user_unmatched=ŠŸŃ–Š“ŠæŠøŃŠ°Š½ŠøŠ¹ неГовіреним ŠŗŠ¾Ń€ŠøŃŃ‚ŃƒŠ²Š°Ń‡ŠµŠ¼, ŃŠŗŠøŠ¹ не віГповіГає ŠŗŠ¾Š¼Ń–Ń‚ŠµŃ€Ńƒ commits.gpg_key_id=ІГентифікатор GPG ŠŗŠ»ŃŽŃ‡Š° -ext_issues.desc=ŠŸŠ¾ŃŠøŠ»Š°Š½Š½Ń на Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŽ ŃŠøŃŃ‚ŠµŠ¼Ńƒ Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń проблем. + +ext_issues=Š”Š¾ŃŃ‚ŃƒŠæ Го Š·Š¾Š²Š½Ń–ŃˆŠ½Ń–Ń… заГач +ext_issues.desc=ŠŸŠ¾ŃŠøŠ»Š°Š½Š½Ń на Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŽ ŃŠøŃŃ‚ŠµŠ¼Ńƒ Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń заГач. projects=ŠŸŃ€Š¾Ń”ŠŗŃ‚Šø -projects.desc=ŠšŠµŃ€ŃƒŠ¹Ń‚Šµ проблемами та запитами Š·Š»ŠøŃ‚Ń‚Ń на Š“Š¾ŃˆŠŗŠ°Ń… ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ. +projects.desc=ŠšŠµŃ€ŃƒŠ¹Ń‚Šµ заГачами та запитами Š·Š»ŠøŃ‚Ń‚Ń на Š“Š¾ŃˆŠŗŠ°Ń… ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ. projects.description=ŠžŠæŠøŃ (необов'ŃŠ·ŠŗŠ¾Š²Š¾) projects.description_placeholder=ŠžŠæŠøŃ projects.create=Дтворити проєкт @@ -1065,10 +1071,10 @@ projects.new=ŠŠ¾Š²ŠøŠ¹ проєкт projects.new_subheader=ŠšŠ¾Š¾Ń€Š“ŠøŠ½ŃƒŠ¹Ń‚Šµ, Š²Ń–Š“ŃŃ‚ŠµŠ¶ŃƒŠ¹Ń‚Šµ та Š¾Š½Š¾Š²Š»ŃŽŠ¹Ń‚е Ń–Š½Ń„Š¾Ń€Š¼Š°Ń†Ń–ŃŽ про виконувану Ń€Š¾Š±Š¾Ń‚Ńƒ в оГному місці, аби проєкти Š·Š°Š»ŠøŃˆŠ°Š»ŠøŃŃ прозорими та за розклаГом. projects.create_success=ŠŸŃ€Š¾Ń”ŠŗŃ‚ '%s' створено. projects.deletion=ВиГалити проєкт -projects.deletion_desc=Š’ŠøŠ“Š°Š»ŠµŠ½Š½Ń ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ Š²ŠøŠ“Š°Š»ŃŃ” його Š· усіх пов'ŃŠ·Š°Š½ŠøŃ… проблем. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? +projects.deletion_desc=Š’ŠøŠ“Š°Š»ŠµŠ½Š½Ń ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ Š²ŠøŠ“Š°Š»ŃŃ” його Š· усіх пов'ŃŠ·Š°Š½ŠøŃ… заГач. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? projects.deletion_success=ŠŸŃ€Š¾Ń”ŠŗŃ‚ виГалено. projects.edit=Š ŠµŠ“Š°Š³ŃƒŠ²Š°Ń‚Šø проєкти -projects.edit_subheader=ŠŸŃ€Š¾Ń”ŠŗŃ‚Šø призначені Š“Š»Ń організації проблем та Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń ŠæŠ¾ŃŃ‚ŃƒŠæŃƒ. +projects.edit_subheader=ŠŸŃ€Š¾Ń”ŠŗŃ‚Šø Š¾Ń€Š³Š°Š½Ń–Š·Š¾Š²ŃƒŃŽŃ‚ŃŒ заГачі та Š²Ń–Š“ŃŃ‚ŠµŠ¶ŃƒŃŽŃ‚ŃŒ прогрес. projects.modify=ŠžŠ½Š¾Š²ŠøŃ‚Šø проєкт projects.edit_success=ŠŸŃ€Š¾Ń”ŠŗŃ‚ '%s' оновлено. projects.type.none=Š’Ń–Š“ŃŃƒŃ‚Š½Ń–Š¹ @@ -1083,9 +1089,9 @@ projects.board.new_title=ŠŠ°Š·Š²Š° нової Гошки projects.board.new_submit=Дтворити projects.board.new=ŠŠ¾Š²Š° Гошка projects.board.set_default=Встановити за Š·Š°Š¼Š¾Š²Ń‡ŃƒŠ²Š°Š½Š½ŃŠ¼ -projects.board.set_default_desc=Встановити цю Гошку за Š·Š°Š¼Š¾Š²Ń‡ŃƒŠ²Š°Š½Š½ŃŠ¼ Š“Š»Ń проблем без категорії та Š²ŠøŃ‚ŃŠ³ŃƒŠ²Š°Š½ŃŒ +projects.board.set_default_desc=Встановити цю Гошку за Š·Š°Š¼Š¾Š²Ń‡ŃƒŠ²Š°Š½Š½ŃŠ¼ Š“Š»Ń заГач без категорії та Š²ŠøŃ‚ŃŠ³ŃƒŠ²Š°Š½ŃŒ projects.board.delete=ВиГалити Гошку -projects.board.deletion_desc=Š’ŠøŠ“Š°Š»ŠµŠ½Š½Ń Гошки ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ перенесе всі пов'ŃŠ·Š°Š½Ń– проблеми в Гошку 'Без категорії'. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? +projects.board.deletion_desc=Š’ŠøŠ“Š°Š»ŠµŠ½Š½Ń Гошки ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ перенесе всі пов'ŃŠ·Š°Š½Ń– заГачі в Гошку 'Без категорії'. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? projects.board.color=ŠšŠ¾Š»Ń–Ń€ projects.open=ВіГкрити projects.close=Закрити @@ -1096,7 +1102,7 @@ issues.filter_milestones=Š¤Ń–Š»ŃŒŃ‚Ń€ етапів issues.filter_projects=Š¤Ń–Š»ŃŒŃ‚Ń€ проєктів issues.filter_labels=Š¤Ń–Š»ŃŒŃ‚Ń€ міток issues.filter_reviewers=Š¤Ń–Š»ŃŒŃ‚Ń€ рецензентів -issues.new=ŠŠ¾Š²Š° проблема +issues.new=ŠŠ¾Š²Š° заГача issues.new.title_empty=Заголовок не може Š±ŃƒŃ‚Šø ŠæŃƒŃŃ‚ŠøŠ¼ issues.new.labels=ŠœŃ–Ń‚ŠŗŠø issues.new.add_labels_title=Š—Š°ŃŃ‚Š¾ŃŃƒŠ²Š°Ń‚Šø мітки @@ -1125,7 +1131,7 @@ issues.choose.get_started=ŠŸŠ¾Ń‡Š°Ń‚Š¾Šŗ роботи issues.choose.blank=Типово issues.choose.blank_about=Дтворити Š·Š°Š“Š°Ń‡Ńƒ Ń–Š· шаблону за Š·Š°Š¼Š¾Š²Ń‡ŃƒŠ²Š°Š½Š½ŃŠ¼. issues.no_ref=ŠŠµ вказана гілка або тег -issues.create=Дтворити ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ +issues.create=Дтворити Š·Š°Š“Š°Ń‡Ńƒ issues.new_label=ŠŠ¾Š²Š° мітка issues.new_label_placeholder=ŠŠ°Š·Š²Š° мітки issues.new_label_desc_placeholder=ŠžŠæŠøŃ @@ -1167,7 +1173,7 @@ issues.filter_milestone_no_select=Всі етапи issues.filter_assignee=Š’ŠøŠŗŠ¾Š½Š°Š²ŠµŃ†ŃŒ issues.filter_assginee_no_select=Всі виконавці issues.filter_type=Тип -issues.filter_type.all_issues=Всі проблеми +issues.filter_type.all_issues=Всі заГачі issues.filter_type.assigned_to_you=ŠŸŃ€ŠøŠ·Š½Š°Ń‡ŠµŠ½Šµ вам issues.filter_type.created_by_you=Дтворено вами issues.filter_type.mentioning_you=Вас згаГано @@ -1203,7 +1209,7 @@ issues.commented_at=`ŠæŃ€Š¾ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Š²(ла) %s` issues.delete_comment_confirm=Š’Šø впевнені, що хочете виГалити цей коментар? issues.context.copy_link=Š”ŠŗŠ¾ŠæŃ–ŃŽŠ²Š°Ń‚Šø ŠæŠ¾ŃŠøŠ»Š°Š½Š½Ń issues.context.quote_reply=Š¦ŠøŃ‚ŃƒŠ²Š°Ń‚Šø Š²Ń–Š“ŠæŠ¾Š²Ń–Š“ŃŒ -issues.context.reference_issue=ŠŸŠ¾ŃŠøŠ»Š°Š½Š½Ń в новій проблемі +issues.context.reference_issue=ŠŸŠ¾ŃŠøŠ»Š°Š½Š½Ń в новій заГачі issues.context.edit=Š ŠµŠ“Š°Š³ŃƒŠ²Š°Ń‚Šø issues.context.delete=ВиГалити issues.no_content=Š¢ŃƒŃ‚ ще немає жоГного Š·Š¼Ń–ŃŃ‚Ńƒ. @@ -1214,15 +1220,15 @@ issues.close_comment_issue=ŠŸŃ€Š¾ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Ń‚Šø і закрити issues.reopen_issue=ВіГкрити знову issues.reopen_comment_issue=ŠŸŃ€Š¾ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Ń‚Šø та віГкрити знову issues.create_comment=ŠšŠ¾Š¼ŠµŠ½Ń‚Š°Ń€ -issues.closed_at=`закрив цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[2]s` -issues.reopened_at=`повторно віГкрив цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[2]s` -issues.commit_ref_at=`згаГано цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ в коміті %[2]s` -issues.ref_issue_from=`ŠæŠ¾ŃŠ»Š°Š²ŃŃ на цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[4]s %[2]s` +issues.closed_at=`закрив цю Š·Š°Š“Š°Ń‡Ńƒ %[2]s` +issues.reopened_at=`повторно віГкрив цю Š·Š°Š“Š°Ń‡Ńƒ %[2]s` +issues.commit_ref_at=`згаГано цю Š·Š°Š“Š°Ń‡Ńƒ в коміті %[2]s` +issues.ref_issue_from=`ŠæŠ¾ŃŠøŠ»Š°Š½Š½Ń на цю Š·Š°Š“Š°Ń‡Ńƒ %[4] %[2]s` issues.ref_pull_from=`ŠæŠ¾ŃŠ»Š°Š²ŃŃ на цей запит Š·Š»ŠøŃ‚Ń‚Ń %[4]s %[2]s` -issues.ref_closing_from=`ŠæŠ¾ŃŠ»Š°Š²ŃŃ на запит Š·Š»ŠøŃ‚Ń‚Ń %[4]s, ŃŠŗŠøŠ¹ закриває цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[2]s` -issues.ref_reopening_from=`ŠæŠ¾ŃŠ»Š°Š²ŃŃ на запит Š·Š»ŠøŃ‚Ń‚Ń %[4]s, ŃŠŗŠøŠ¹ повторно віГкриває цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[2]s` -issues.ref_closed_from=`закрив цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[4]s %[2]s` -issues.ref_reopened_from=`повторно віГкрив цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[4]s %[2]s` +issues.ref_closing_from=`згаГав запит на Š·Š»ŠøŃ‚Ń‚Ń %[4]с, ŃŠŗŃ– Š·Š°ŠŗŃ€ŠøŃŽŃ‚ŃŒ цю Š·Š°Š“Š°Ń‡Ńƒ %[2]s` +issues.ref_reopening_from=`згаГав запит на Š·Š»ŠøŃ‚Ń‚Ń %[4]с, ŃŠŗŃ– повторно Š²Ń–Š“ŠŗŃ€ŠøŃŽŃ‚ŃŒ цю Š·Š°Š“Š°Ń‡Ńƒ %[2]s` +issues.ref_closed_from=`закрив цю Š·Š°Š“Š°Ń‡Ńƒ %[4]s %[2]s` +issues.ref_reopened_from=`повторно віГкрито цю Š·Š°Š“Š°Ń‡Ńƒ %[4]s %[2]s` issues.ref_from=`Ń–Š· %[1]s` issues.poster=Автор issues.collaborator=Дпівавтор @@ -1241,12 +1247,12 @@ issues.label_title=ŠŠ°Š·Š²Š° мітки issues.label_description=ŠžŠæŠøŃ мітки issues.label_color=ŠšŠ¾Š»Ń–Ń€ мітки issues.label_count=%d міток -issues.label_open_issues=%d віГкритих проблем +issues.label_open_issues=%d віГкритих заГач issues.label_edit=Š ŠµŠ“Š°Š³ŃƒŠ²Š°Ń‚Šø issues.label_delete=ВиГалити issues.label_modify=Š ŠµŠ“Š°Š³ŃƒŠ²Š°Ń‚Šø Š¼Ń–Ń‚ŠŗŃƒ issues.label_deletion=ВиГалити Š¼Ń–Ń‚ŠŗŃƒ -issues.label_deletion_desc=Š’ŠøŠ“Š°Š»ŠµŠ½Š½Ń мітки Š²ŠøŠ“Š°Š»ŃŃ” її Š· усіх Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½ŃŒ. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? +issues.label_deletion_desc=Š’ŠøŠ“Š°Š»ŠµŠ½Š½Ń мітки Š²ŠøŠ“Š°Š»ŃŃ” її Š· усіх заГач. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? issues.label_deletion_success=ŠœŃ–Ń‚ŠŗŃƒ було виГалено. issues.label.filter_sort.alphabetically=За алфавітом issues.label.filter_sort.reverse_alphabetically=Š— ŠŗŃ–Š½Ń†Ń Š°Š»Ń„Š°Š²Ń–Ń‚Ńƒ @@ -1259,29 +1265,29 @@ issues.subscribe=ŠŸŃ–Š“ŠæŠøŃŠ°Ń‚ŠøŃŃ issues.unsubscribe=Š’Ń–Š“ŠæŠøŃŠ°Ń‚ŠøŃŃ issues.lock=Š‘Š»Š¾ŠŗŃƒŠ²Š°Š½Š½Ń Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½Š½Ń issues.unlock=Š Š¾Š·Š±Š»Š¾ŠŗŃƒŠ²Š°Š½Š½Ń Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½Š½Ń -issues.lock.unknown_reason=ŠŠµŠ¼Š¾Š¶Š»ŠøŠ²Š¾ Š·Š°Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ Š· Š½ŠµŠ²Ń–Š“Š¾Š¼Š¾ŃŽ ŠæŃ€ŠøŃ‡ŠøŠ½Š¾ŃŽ. -issues.lock_duplicate=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Š° не може Š±ŃƒŃ‚Šø заблокованим Гвічі. -issues.unlock_error=ŠŠµ можливо Ń€Š¾Š·Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ, ŃŠŗŠ° не заблокована. +issues.lock.unknown_reason=ŠŠµŠ¼Š¾Š¶Š»ŠøŠ²Š¾ Š·Š°Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø Š·Š°Š“Š°Ń‡Ńƒ Š· Š½ŠµŠ²Ń–Š“Š¾Š¼Š¾ŃŽ ŠæŃ€ŠøŃ‡ŠøŠ½Š¾ŃŽ. +issues.lock_duplicate=ЗаГача не може Š±ŃƒŃ‚Šø заблокованим Гвічі. +issues.unlock_error=ŠŠµ можливо Ń€Š¾Š·Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø Š·Š°Š“Š°Ń‡Ńƒ, ŃŠŗŠ° не заблокована. issues.lock_with_reason=заблоковано ŃŠŗ %s та обмежене Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½Š½Ń Š“Š»Ń співавторів %s issues.lock_no_reason=заблоковано та обмежене Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½Š½Ń Š“Š»Ń співавторів %s issues.unlock_comment=розблоковане Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½Š½Ń %s issues.lock_confirm=Š—Š°Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø issues.unlock_confirm=Š Š¾Š·Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø -issues.lock.notice_1=- Š†Š½ŃˆŃ– ŠŗŠ¾Ń€ŠøŃŃ‚ŃƒŠ²Š°Ń‡Ń– не Š¼Š¾Š¶ŃƒŃ‚ŃŒ ГоГавати нові коментарі Го цієї проблеми. +issues.lock.notice_1=- Š†Š½ŃˆŃ– ŠŗŠ¾Ń€ŠøŃŃ‚ŃƒŠ²Š°Ń‡Ń– не Š¼Š¾Š¶ŃƒŃ‚ŃŒ ГоГавати нові коментарі Го цієї заГачі. issues.lock.notice_2=- Š’Šø й Ń–Š½ŃˆŃ– співавтори, ŃŠŗŃ– Š¼Š°ŃŽŃ‚ŃŒ Š“Š¾ŃŃ‚ŃƒŠæ Го Ń†ŃŒŠ¾Š³Š¾ Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ, можете Š·Š°Š»ŠøŃˆŠ°Ń‚Šø коментарі, ŃŠŗŃ– Ń–Š½ŃˆŃ– Š¼Š¾Š¶ŃƒŃ‚ŃŒ бачити. -issues.lock.notice_3=- Š’Šø завжГи зможете Ń€Š¾Š·Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ в Š¼Š°Š¹Š±ŃƒŃ‚Š½ŃŒŠ¾Š¼Ńƒ. -issues.unlock.notice_1=- Кожен зможе ŠæŃ€Š¾ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Ń‚Šø це ŠæŠøŃ‚Š°Š½Š½Ń ще раз. -issues.unlock.notice_2=- Š’Šø завжГи зможете Š·Š°Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ в Š¼Š°Š¹Š±ŃƒŃ‚Š½ŃŒŠ¾Š¼Ńƒ. +issues.lock.notice_3=- Š’Šø завжГи зможете Ń€Š¾Š·Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø цю Š·Š°Š“Š°Ń‡Ńƒ в Š¼Š°Š¹Š±ŃƒŃ‚Š½ŃŒŠ¾Š¼Ńƒ. +issues.unlock.notice_1=- Кожен зможе ŠæŃ€Š¾ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Ń‚Šø цю Š·Š°Š“Š°Ń‡Ńƒ ще раз. +issues.unlock.notice_2=- Š’Šø завжГи зможете Š·Š°Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø цю Š·Š°Š“Š°Ń‡Ńƒ в Š¼Š°Š¹Š±ŃƒŃ‚Š½ŃŒŠ¾Š¼Ńƒ. issues.lock.reason=ŠŸŃ€ŠøŃ‡ŠøŠ½Š° Š±Š»Š¾ŠŗŃƒŠ²Š°Š½Š½Ń -issues.lock.title=Š—Š°Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½Š½Ń цієї проблеми. -issues.unlock.title=Š Š¾Š·Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½Š½Ń цієї проблеми. -issues.comment_on_locked=Š’Šø не можете ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Ń‚Šø заблоковану ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ. +issues.lock.title=Š—Š°Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½Š½Ń цієї заГачі. +issues.unlock.title=Š Š¾Š·Š±Š»Š¾ŠŗŃƒŠ²Š°Ń‚Šø Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½Š½Ń цієї заГачі. +issues.comment_on_locked=Š’Šø не можете ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Ń‚Šø заблоковану Š·Š°Š“Š°Ń‡Ńƒ. issues.tracker=Š’Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń Ń‡Š°ŃŃƒ issues.start_tracking_short=Š—Š°ŠæŃƒŃŃ‚ŠøŃ‚Šø таймер issues.start_tracking=ŠŸŠ¾Ń‡Š°Ń‚Šø Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń Ń‡Š°ŃŃƒ issues.start_tracking_history=`почав ŠæŃ€Š°Ń†ŃŽŠ²Š°Ń‚Šø %s` -issues.tracker_auto_close=Таймер буГе автоматично зупинено, коли ця проблема буГе закрита -issues.tracking_already_started=`Š’Šø вже почали Š²Ń–Š“ŃŃ‚ŠµŠ¶ŃƒŠ²Š°Ń‚Šø час Š“Š»Ń Ń–Š½ŃˆŠ¾Ń— проблеми!` +issues.tracker_auto_close=Таймер буГе автоматично зупинено, коли ця заГача буГе закрита +issues.tracking_already_started=`Š’Šø вже почали Š²Ń–Š“ŃŃ‚ŠµŠ¶ŃƒŠ²Š°Ń‚Šø час Š“Š»Ń Ń–Š½ŃˆŠ¾Ń— заГачі!` issues.stop_tracking=Š—ŃƒŠæŠøŠ½ŠøŃ‚Šø таймер issues.stop_tracking_history=`перестав(-ла) ŠæŃ€Š°Ń†ŃŽŠ²Š°Ń‚Šø %s` issues.cancel_tracking=Š”ŠŗŠ°ŃŃƒŠ²Š°Ń‚Šø @@ -1308,7 +1314,7 @@ issues.due_date_form=рррр-мм-ГГ issues.due_date_form_add=ДоГати Š“Š°Ń‚Ńƒ Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š½Ń issues.due_date_form_edit=Š ŠµŠ“Š°Š³ŃƒŠ²Š°Ń‚Šø issues.due_date_form_remove=ВиГалити -issues.due_date_not_writer=Вам потрібен Š“Š¾ŃŃ‚ŃƒŠæ Го запису в репозиторії, щоб оновити Š“Š°Ń‚Ńƒ Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š½Ń проблем. +issues.due_date_not_writer=Вам потрібен Š“Š¾ŃŃ‚ŃƒŠæ Го запису в репозиторії, щоб оновити Š“Š°Ń‚Ńƒ Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š½Ń заГач. issues.due_date_not_set=Термін Š²ŠøŠŗŠ¾Š½Š°Š½Š½Ń не встановлений. issues.due_date_added=ГоГав(ла) Š“Š°Ń‚Ńƒ Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š½Ń %s %s issues.due_date_modified=термін змінено Š· %s %s на %s @@ -1316,7 +1322,7 @@ issues.due_date_remove=виГалив(ла) Š“Š°Ń‚Ńƒ Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š½Ń %s %s issues.due_date_overdue=ŠŸŃ€Š¾ŃŃ‚Ń€Š¾Ń‡ŠµŠ½Š¾ issues.due_date_invalid=Термін Гії не Гійсний або Š·Š½Š°Ń…Š¾Š“ŠøŃ‚ŃŒŃŃ за межами Š“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Š¾Š³Š¾ Š“Ń–Š°ŠæŠ°Š·Š¾Š½Ńƒ. Š‘ŃƒŠ“ŃŒ ласка Š²ŠøŠŗŠ¾Ń€ŠøŃŃ‚Š¾Š²ŃƒŠ¹Ń‚Šµ формат 'yyyy-mm-dd'. issues.dependency.title=Залежності -issues.dependency.issue_no_dependencies=Š¦Ń проблема в Ганий час не має залежностей. +issues.dependency.issue_no_dependencies=Š¦Ń заГача тепер не має залежностей. issues.dependency.pr_no_dependencies=Цей запит на Š·Š»ŠøŃ‚Ń‚Ń в Ганий час не має залежностей. issues.dependency.add=ДоГати Š·Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒā€¦ issues.dependency.cancel=ВіГмінити @@ -1324,24 +1330,24 @@ issues.dependency.remove=ВиГалити issues.dependency.remove_info=ВиГалити цю Š·Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒ issues.dependency.added_dependency=`ГоГав нову Š·Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒ %s` issues.dependency.removed_dependency=`виГалив Š·Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒ %s` -issues.dependency.pr_closing_blockedby=Š—Š°ŠŗŃ€ŠøŃ‚Ń‚Ń Ń†ŃŒŠ¾Š³Š¾ Š·Š°ŠæŠøŃ‚Ńƒ Š·Š»ŠøŃ‚Ń‚Ń заблоковано Š½Š°ŃŃ‚ŃƒŠæŠ½ŠøŠ¼Šø проблемами -issues.dependency.issue_closing_blockedby=Š—Š°ŠŗŃ€ŠøŃ‚Ń‚Ń цієї проблеми заблоковано Š½Š°ŃŃ‚ŃƒŠæŠ½ŠøŠ¼Šø проблемами -issues.dependency.issue_close_blocks=Š¦Ń проблема Š±Š»Š¾ŠŗŃƒŃ” Š·Š°ŠŗŃ€ŠøŃ‚Ń‚Ń залежних проблем -issues.dependency.pr_close_blocks=Цей пулл-реквест Š±Š»Š¾ŠŗŃƒŃ” Š·Š°ŠŗŃ€ŠøŃ‚Ń‚Ń залежних проблем -issues.dependency.issue_close_blocked=Вам потрібно закрити всі проблеми, що Š±Š»Š¾ŠŗŃƒŃŽŃ‚ŃŒ цю ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ, переГ її Š·Š°ŠŗŃ€ŠøŃ‚Ń‚ŃŠ¼. -issues.dependency.pr_close_blocked=Вам потрібно закрити всі проблеми, що Š±Š»Š¾ŠŗŃƒŃŽŃ‚ŃŒ цей пулл-реквест, переГ його Š·Š»ŠøŃ‚Ń‚ŃŠ¼. +issues.dependency.pr_closing_blockedby=Š—Š°ŠŗŃ€ŠøŃ‚Ń‚Ń Ń†ŃŒŠ¾Š³Š¾ Š·Š°ŠæŠøŃ‚Ńƒ Š·Š»ŠøŃ‚Ń‚Ń заблоковано Š½Š°ŃŃ‚ŃƒŠæŠ½ŠøŠ¼Šø заГачами +issues.dependency.issue_closing_blockedby=Š—Š°ŠŗŃ€ŠøŃ‚Ń‚Ń цієї заГачи заблоковано Š½Š°ŃŃ‚ŃƒŠæŠ½ŠøŠ¼Šø заГачами +issues.dependency.issue_close_blocks=Š¦Ń заГача Š±Š»Š¾ŠŗŃƒŃ” Š·Š°ŠŗŃ€ŠøŃ‚Ń‚Ń залежних заГач +issues.dependency.pr_close_blocks=Цей запит на Š·Š»ŠøŃ‚Ń‚Ń Š±Š»Š¾ŠŗŃƒŃ” Š·Š°ŠŗŃ€ŠøŃ‚Ń‚Ń залежних заГач +issues.dependency.issue_close_blocked=Вам потрібно закрити всі заГачі, що Š±Š»Š¾ŠŗŃƒŃŽŃ‚ŃŒ цю Š·Š°Š“Š°Ń‡Ńƒ, переГ її Š·Š°ŠŗŃ€ŠøŃ‚Ń‚ŃŠ¼. +issues.dependency.pr_close_blocked=Вам потрібно закрити всі заГачі, що Š±Š»Š¾ŠŗŃƒŃŽŃ‚ŃŒ цей запит, переГ його Š·Š»ŠøŃ‚Ń‚ŃŠ¼. issues.dependency.blocks_short=Блоки issues.dependency.blocked_by_short=Š—Š°Š»ŠµŠ¶ŠøŃ‚ŃŒ віГ issues.dependency.remove_header=ВиГалити Š·Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒ -issues.dependency.issue_remove_text=Це призвеГе Го Š²ŠøŠ“Š°Š»ŠµŠ½Š½Ń залежності Š· цієї проблеми. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? +issues.dependency.issue_remove_text=Це призвеГе Го Š²ŠøŠ“Š°Š»ŠµŠ½Š½Ń залежності Š· цієї заГачі. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? issues.dependency.pr_remove_text=Це призвеГе Го Š²ŠøŠ“Š°Š»ŠµŠ½Š½Ń залежності Š· Ń†ŃŒŠ¾Š³Š¾ пулл-Ń€ŠµŠŗŠ²ŠµŃŃ‚Ńƒ. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? -issues.dependency.setting=Š£Š²Ń–Š¼ŠŗŠ½ŃƒŃ‚Šø залежності Š“Š»Ń проблем та пулл-реквестів -issues.dependency.add_error_same_issue=Š’Šø не можете зробити ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ Š·Š°Š»ŠµŠ¶Š½Š¾ŃŽ віГ себе. -issues.dependency.add_error_dep_issue_not_exist=Š—Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒ Š“Š»Ń проблеми не Ń–ŃŠ½ŃƒŃ”. +issues.dependency.setting=Š£Š²Ń–Š¼ŠŗŠ½ŃƒŃ‚Šø залежності Š“Š»Ń заГач та запитів на Š·Š»ŠøŃ‚Ń‚Ń +issues.dependency.add_error_same_issue=Š’Šø не можете зробити Š·Š°Š“Š°Ń‡Ńƒ Š·Š°Š»ŠµŠ¶Š½Š¾ŃŽ віГ себе. +issues.dependency.add_error_dep_issue_not_exist=Š—Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒ Š“Š»Ń заГачі не Ń–ŃŠ½ŃƒŃ”. issues.dependency.add_error_dep_not_exist=Š—Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒ не Ń–ŃŠ½ŃƒŃ”. issues.dependency.add_error_dep_exists=Š—Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒ уже Ń–ŃŠ½ŃƒŃ”. -issues.dependency.add_error_cannot_create_circular=Š’Šø не можете створити Š·Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒ Š· Гвома проблемами, ŃŠŗŃ– Š±Š»Š¾ŠŗŃƒŃŽŃ‚ŃŒ оГна оГну. -issues.dependency.add_error_dep_not_same_repo=ŠžŠ±ŠøŠ“Š²Ń– проблеми повинні Š±ŃƒŃ‚Šø в оГному репозиторії. +issues.dependency.add_error_cannot_create_circular=Š’Šø не можете створити Š·Š°Š»ŠµŠ¶Š½Ń–ŃŃ‚ŃŒ Š· Гвома заГачами, ŃŠŗŃ– Š±Š»Š¾ŠŗŃƒŃŽŃ‚ŃŒ оГна оГну. +issues.dependency.add_error_dep_not_same_repo=ŠžŠ±ŠøŠ“Š²Ń– заГачі повинні Š±ŃƒŃ‚Šø в оГному репозиторії. issues.review.self.approval=Š’Šø не можете схвалити власний пулл-реквест. issues.review.self.rejection=Š’Šø не можете наГіслати запит на Š·Š¼Ń–Š½Ńƒ на власний пулл-реквест. issues.review.approve=зміни затверГжено %s @@ -1475,7 +1481,7 @@ pulls.closed_at=`закрив цей запит на Š·Š»ŠøŃ‚Ń‚Ń %[2]s` pulls.merge_instruction_hint=`Також можна ŠæŠµŃ€ŠµŠ³Š»ŃŠ½ŃƒŃ‚Šø Ń–Š½ŃŃ‚Ń€ŃƒŠŗŃ†Ń–Ń— Š“Š»Ń команГного Ń€ŃŠ“ŠŗŠ°.` -pulls.merge_instruction_step1_desc=Š£ репозиторії вашого ŠæŃ€Š¾ŠµŠŗŃ‚Ńƒ перевірте нову Š³Ń–Š»ŠŗŃƒ і ŠæŃ€Š¾Ń‚ŠµŃŃ‚ŃƒŠ¹Ń‚Šµ зміни. +pulls.merge_instruction_step1_desc=Š£ репозиторії вашого ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ перевірте нову Š³Ń–Š»ŠŗŃƒ і ŠæŃ€Š¾Ń‚ŠµŃŃ‚ŃƒŠ¹Ń‚Šµ зміни. pulls.merge_instruction_step2_desc=ŠžŠ±'єГнати зміни і оновити на Gitea. milestones.new=ŠŠ¾Š²ŠøŠ¹ етап @@ -1486,7 +1492,7 @@ milestones.update_ago=ŠžŠ½Š¾Š²Š»ŠµŠ½Š¾ %s назаГ milestones.no_due_date=ŠŠµŠ¼Š°Ń” Гати Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š½Ń milestones.open=ВіГкрити milestones.close=Закрити -milestones.new_subheader=Š”Ń‚Š²Š¾Ń€ŃŽŠ¹Ń‚Šµ етапи Š“Š»Ń організації Š²Š°ŃˆŠøŃ… завГань. +milestones.new_subheader=Š”Ń‚Š²Š¾Ń€ŃŽŠ¹Ń‚Šµ етапи Š“Š»Ń організації Š²Š°ŃˆŠøŃ… заГач. milestones.completeness=%d%% Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š¾ milestones.create=Дтворити етап milestones.title=Заголовок @@ -1496,19 +1502,19 @@ milestones.clear=ŠžŃ‡ŠøŃŃ‚ŠøŃ‚Šø milestones.invalid_due_date_format=Дата Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š½Ń має Š±ŃƒŃ‚Šø в форматі 'рррр-мм-ГГ'. milestones.create_success=Етап '%s' створений. milestones.edit=Š ŠµŠ“Š°Š³ŃƒŠ²Š°Ń‚Šø етап -milestones.edit_subheader=Š’ŠøŠŗŠ¾Ń€ŠøŃŃ‚Š¾Š²ŃƒŠ¹Ń‚Šµ кращий опис ŠŗŠ¾Š½Ń‚Ń€Š¾Š»ŃŒŠ½Š¾Ń— точки, щоб ŃƒŠ½ŠøŠŗŠ½ŃƒŃ‚Šø Š½ŠµŃ€Š¾Š·ŃƒŠ¼Ń–Š½Š½Ń Š· боку Ń–Š½ŃˆŠøŃ… Š»ŃŽŠ“ŠµŠ¹. +milestones.edit_subheader=Š”Ń‚Š²Š¾Ń€ŃŽŠ¹Ń‚Šµ етапи Š“Š»Ń організації Š²Š°ŃˆŠøŃ… заГач. milestones.cancel=ВіГмінити milestones.modify=ŠžŠ½Š¾Š²ŠøŃ‚Šø етап milestones.edit_success=Етап '%s' був оновлений. milestones.deletion=ВиГалити етап -milestones.deletion_desc=Š’ŠøŠ“Š°Š»ŠµŠ½Š½Ń ŠµŃ‚Š°ŠæŃƒ призвеГе Го його Š²ŠøŠ“Š°Š»ŠµŠ½Š½Ń Š· усіх пов'ŃŠ·Š°Š½ŠøŃ… завГань. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? +milestones.deletion_desc=Š’ŠøŠ“Š°Š»ŠµŠ½Š½Ń ŠµŃ‚Š°ŠæŃƒ призвеГе Го його Š²ŠøŠ“Š°Š»ŠµŠ½Š½Ń Š· усіх пов'ŃŠ·Š°Š½ŠøŃ… заГач. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? milestones.deletion_success=Етап ŃƒŃŠæŃ–ŃˆŠ½Š¾ виГалено. milestones.filter_sort.closest_due_date=ŠŠ°Š¹Š±Š»ŠøŠ¶Ń‡Šµ за Š“Š°Ń‚Š¾ŃŽ milestones.filter_sort.furthest_due_date=Далі за Š“Š°Ń‚Š¾ŃŽ milestones.filter_sort.least_complete=Менш повне milestones.filter_sort.most_complete=Š‘Ń–Š»ŃŒŃˆ повне -milestones.filter_sort.most_issues=ŠŠ°Š¹Š±Ń–Š»ŃŒŃˆ проблем -milestones.filter_sort.least_issues=ŠŠ°Š¹Š¼ŠµŠ½Ńˆ проблем +milestones.filter_sort.most_issues=ŠŠ°Š¹Š±Ń–Š»ŃŒŃˆ заГач +milestones.filter_sort.least_issues=ŠŠ°Š¹Š¼ŠµŠ½Ńˆ заГач signing.will_sign=Цей коміт буГе піГписано ŠŗŠ»ŃŽŃ‡ŠµŠ¼ '%s' signing.wont_sign.error=ŠŸŃ–Š“ час ŠæŃ–Š“ŠæŠøŃŠ°Š½Š½Ń ŠŗŠ¾Š¼Ń–Ń‚Ńƒ, ŃŃ‚Š°Š»Š°ŃŃ помилка @@ -1574,21 +1580,21 @@ activity.title.prs_merged_by=%s злито %s activity.title.prs_opened_by=%s запропоновано %s activity.merged_prs_label=Злито activity.opened_prs_label=Запропоновано -activity.active_issues_count_1=%d Активна проблема -activity.active_issues_count_n=%d Активні проблеми -activity.closed_issues_count_1=Закрита проблема -activity.closed_issues_count_n=Закриті проблеми -activity.title.issues_1=%d ŠŸŃ€Š¾Š±Š»ŠµŠ¼Š° -activity.title.issues_n=%d ŠŸŃ€Š¾Š±Š»ŠµŠ¼Šø +activity.active_issues_count_1=%d Активна заГача +activity.active_issues_count_n=%d Активні заГачі +activity.closed_issues_count_1=Закрита заГача +activity.closed_issues_count_n=Закриті заГачі +activity.title.issues_1=%d ЗаГач +activity.title.issues_n=%d ЗаГач activity.title.issues_closed_from=%s закрито %s activity.title.issues_created_by=%s створена(і) %s activity.closed_issue_label=Закрито -activity.new_issues_count_1=ŠŠ¾Š²Š° ŠŸŃ€Š¾Š±Š»ŠµŠ¼Š° -activity.new_issues_count_n=%d ŠŸŃ€Š¾Š±Š»ŠµŠ¼ +activity.new_issues_count_1=ŠŠ¾Š²Š° заГача +activity.new_issues_count_n=ŠŠ¾Š²Ń– ЗаГачі activity.new_issue_label=ВіГкриті activity.title.unresolved_conv_1=%d ŠŠµŠ·Š°Š²ŠµŃ€ŃˆŠµŠ½Šµ Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½Š½Ń activity.title.unresolved_conv_n=%d ŠŠµŠ·Š°Š²ŠµŃ€ŃˆŠµŠ½ŠøŃ… Š¾Š±Š³Š¾Š²Š¾Ń€ŠµŠ½ŃŒ -activity.unresolved_conv_desc=Дписок всіх старих тікетів і Pull Request'ів Š· Š½ŠµŠ“Š°Š²Š½ŃŒŠ¾Ń— Š°ŠŗŃ‚ŠøŠ²Š½Ń–ŃŃ‚ŃŽ, але ще не закритих або ŠæŃ€ŠøŠ¹Š½ŃŃ‚ŠøŃ…. +activity.unresolved_conv_desc=Дписок всіх старих заГач і Pull Request'ів Š· Š½ŠµŠ“Š°Š²Š½ŃŒŠ¾Ń— Š°ŠŗŃ‚ŠøŠ²Š½Ń–ŃŃ‚ŃŽ, але ще не закритих або ŠæŃ€ŠøŠ¹Š½ŃŃ‚ŠøŃ…. activity.unresolved_conv_label=ВіГкрити activity.title.releases_1=%d Реліз activity.title.releases_n=%d Релізів @@ -1635,7 +1641,7 @@ settings.hooks=Веб-Ń…ŃƒŠŗŠø settings.githooks=Git Ń…ŃƒŠŗŠø settings.basic_settings=Базові Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½Š½Ń settings.mirror_settings=ŠŠ°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½Š½Ń Гзеркала -settings.mirror_settings.docs=ŠŠ°Š»Š°ŃˆŃ‚ŃƒŠ¹Ń‚Šµ свій проект, щоб автоматично Š²Ń–Š“ŠæŃ€Š°Š²Š»ŃŃ‚Šø/Š¾Ń‚Ń€ŠøŠ¼ŃƒŠ²Š°Ń‚Šø зміни Š· Ń–Š½ŃˆŠ¾Š³Š¾ Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ. Гілки, теги і коміти Š±ŃƒŠ“ŃƒŃ‚ŃŒ ŃŠøŠ½Ń…Ń€Š¾Š½Ń–Š·ŃƒŠ²Š°Ń‚ŠøŃŃ автоматично. ŠÆŠŗ я можу віГзеркалити репозиторії? +settings.mirror_settings.docs=ŠŠ°Š»Š°ŃˆŃ‚ŃƒŠ¹Ń‚Šµ свій проєкт, щоб автоматично Š²Ń–Š“ŠæŃ€Š°Š²Š»ŃŃ‚Šø/Š¾Ń‚Ń€ŠøŠ¼ŃƒŠ²Š°Ń‚Šø зміни Š· Ń–Š½ŃˆŠ¾Š³Š¾ Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ. Гілки, теги та коміти Š±ŃƒŠ“ŃƒŃ‚ŃŒ ŃŠøŠ½Ń…Ń€Š¾Š½Ń–Š·ŃƒŠ²Š°Ń‚ŠøŃŃ автоматично. ŠÆŠŗ я можу віГзеркалити репозиторії? settings.mirror_settings.mirrored_repository=ВіГГзеркалений репозиторій settings.mirror_settings.direction=ŠŠ°ŠæŃ€ŃŠ¼Š¾Šŗ settings.mirror_settings.direction.pull=Pull @@ -1660,12 +1666,12 @@ settings.use_external_wiki=Š’ŠøŠŗŠ¾Ń€ŠøŃŃ‚Š¾Š²ŃƒŠ²Š°Ń‚Šø Š·Š¾Š²Š½Ń–ŃˆŠ½Ń– Š’Ń– settings.external_wiki_url=URL Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŒŠ¾Ń— вікі settings.external_wiki_url_error=Š—Š¾Š²Š½Ń–ŃˆŠ½Ń URL-аГреса wiki не є Š“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Š¾ŃŽ URL-Š°Š“Ń€ŠµŃŠ¾ŃŽ. settings.external_wiki_url_desc=Š’Ń–Š“Š²Ń–Š“ŃƒŠ²Š°Ń‡Ń– Š±ŃƒŠ“ŃƒŃ‚ŃŒ перенаправлені на URL-Š°Š“Ń€ŠµŃŃƒ, коли вони ŠŗŠ»Š°Ń†Š°ŃŽŃ‚ŃŒ по вклаГці. -settings.issues_desc=Š£Š²Ń–Š¼ŠŗŠ½ŃƒŃ‚Šø Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń проблем в Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ -settings.use_internal_issue_tracker=Š’ŠøŠŗŠ¾Ń€ŠøŃŃ‚Š¾Š²ŃƒŠ²Š°Ń‚Šø вбуГовану ŃŠøŃŃ‚ŠµŠ¼Ńƒ Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń проблем -settings.use_external_issue_tracker=Š’ŠøŠŗŠ¾Ń€ŠøŃŃ‚Š¾Š²ŃƒŠ²Š°Ń‚Šø Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŽ ŃŠøŃŃ‚ŠµŠ¼Ńƒ Š¾Š±Š»Ń–ŠŗŃƒ завГань -settings.external_tracker_url=URL Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŒŠ¾Ń— системи Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń проблем +settings.issues_desc=Š£Š²Ń–Š¼ŠŗŠ½ŃƒŃ‚Šø Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń заГач в Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ +settings.use_internal_issue_tracker=Š’ŠøŠŗŠ¾Ń€ŠøŃŃ‚Š¾Š²ŃƒŠ²Š°Ń‚Šø вбуГовану ŃŠøŃŃ‚ŠµŠ¼Ńƒ Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń заГач +settings.use_external_issue_tracker=Š’ŠøŠŗŠ¾Ń€ŠøŃŃ‚Š¾Š²ŃƒŠ²Š°Ń‚Šø Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŽ ŃŠøŃŃ‚ŠµŠ¼Ńƒ Š¾Š±Š»Ń–ŠŗŃƒ заГач +settings.external_tracker_url=URL Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŒŠ¾Ń— системи Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń заГач settings.external_tracker_url_error=URL Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŒŠ¾Š³Š¾ баг-трекера не є Š“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Š¾ŃŽ URL-Š°Š“Ń€ŠµŃŠ¾ŃŽ. -settings.external_tracker_url_desc=Š’Ń–Š“Š²Ń–Š“ŃƒŠ²Š°Ń‡Ń– ŠæŠµŃ€ŠµŠ½Š°ŠæŃ€Š°Š²Š»ŃŃŽŃ‚ŃŒŃŃ на Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŽ URL-Š°Š“Ń€ŠµŃŃƒ, коли Š½Š°Ń‚ŠøŃŠŗŠ°ŃŽŃ‚ŃŒ вклаГку 'ŠŸŃ€Š¾Š±Š»ŠµŠ¼Šø'. +settings.external_tracker_url_desc=Š’Ń–Š“Š²Ń–Š“ŃƒŠ²Š°Ń‡Ń– ŠæŠµŃ€ŠµŠ½Š°ŠæŃ€Š°Š²Š»ŃŃŽŃ‚ŃŒŃŃ на Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŽ URL-Š°Š“Ń€ŠµŃŃƒ, коли Š½Š°Ń‚ŠøŃŠŗŠ°ŃŽŃ‚ŃŒ вклаГку 'ЗаГачі'. settings.tracker_url_format=Формат URL Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŒŠ¾Š³Š¾ трекера заГач settings.tracker_url_format_error=ŠŠµŠæŃ€Š°Š²ŠøŠ»ŃŒŠ½ŠøŠ¹ формат URL-аГреси Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŒŠ¾Š³Š¾ баг-трекера. settings.tracker_issue_style=Формат Š½Š¾Š¼ŠµŃ€Ńƒ Š“Š»Ń Š·Š¾Š²Š½Ń–ŃˆŠ½ŃŒŠ¾Ń— системи Š¾Š±Š»Ń–ŠŗŃƒ заГач @@ -1686,7 +1692,7 @@ settings.pulls.default_delete_branch_after_merge=Š’ŠøŠ“Š°Š»ŃŃ‚Šø Š³Ń–Š»ŠŗŃƒ Š· settings.projects_desc=Š£Š²Ń–Š¼ŠŗŠ½ŃƒŃ‚Šø проєкти у репозиторії settings.admin_settings=ŠŠ°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½Š½Ń аГміністратора settings.admin_enable_health_check=Š’ŠŗŠ»ŃŽŃ‡ŠøŃ‚Šø перевірки працезГатності Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ (git fsck) -settings.admin_enable_close_issues_via_commit_in_any_branch=Закрити ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ за Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾ŃŽ коміта, зробленого не головній гілці +settings.admin_enable_close_issues_via_commit_in_any_branch=Закрити Š·Š°Š“Š°Ń‡Ńƒ за Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾ŃŽ коміта, зробленого не в головній гілці settings.danger_zone=ŠŠµŠ±ŠµŠ·ŠæŠµŃ‡Š½Š° зона settings.new_owner_has_same_repo=ŠŠ¾Š²ŠøŠ¹ власник вже має репозиторій Š· Ń‚Š°ŠŗŠ¾ŃŽ Š½Š°Š·Š²Š¾ŃŽ. Š‘ŃƒŠ“ŃŒ ласка, Š²ŠøŠ±ŠµŃ€Ń–Ń‚ŃŒ Ń–Š½ŃˆŠµ ім'я. settings.convert=ŠŸŠµŃ€ŠµŃ‚Š²Š¾Ń€ŠøŃ‚Šø на звичайний репозиторій @@ -1736,7 +1742,7 @@ settings.wiki_deletion_success=Дані wiki були виГалені. settings.delete=ВиГалити цей репозиторій settings.delete_desc=Š‘ŃƒŠ“ŃŒŃ‚Šµ ŃƒŠ²Š°Š¶Š½Ń–! ŠÆŠŗ Ń‚Ń–Š»ŃŒŠŗŠø ви виГалите репозиторій - ŃˆŠ»ŃŃ…Ńƒ назаГ не буГе. settings.delete_notices_1=- Š¦ŃŽ Š¾ŠæŠµŃ€Š°Ń†Ń–ŃŽ ŠŠ• ŠœŠžŠ–ŠŠ віГмінити. -settings.delete_notices_2=- Š¦Ń Š¾ŠæŠµŃ€Š°Ń†Ń–Ń назавжГи Š²ŠøŠ“Š°Š»ŠøŃ‚ŃŒ все Š· Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ %s, Š²ŠŗŠ»ŃŽŃ‡Š°ŃŽŃ‡Šø Гані Git, пов'ŃŠ·Š°Š½Ń– Š· ним Š·Š°Š²Š“Š°Š½Š½Ń, коментарі і права Š“Š¾ŃŃ‚ŃƒŠæŃƒ Š“Š»Ń співробітників. +settings.delete_notices_2=- Š¦Ń Š¾ŠæŠµŃ€Š°Ń†Ń–Ń остаточно Š²ŠøŠ“Š°Š»ŠøŃ‚ŃŒ %s репозиторій, Š²ŠŗŠ»ŃŽŃ‡Š°ŃŽŃ‡Šø коГ, заГачі, коментарі, вікі та Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½Š½Ń співавторів. settings.delete_notices_fork_1=- Всі форки ŃŃ‚Š°Š½ŃƒŃ‚ŃŒ незалежними Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŠ¼Šø ŠæŃ–ŃŠ»Ń Š²ŠøŠ“Š°Š»ŠµŠ½Š½Ń. settings.deletion_success=Репозиторій ŃƒŃŠæŃ–ŃˆŠ½Š¾ виГалено. settings.update_settings_success=ŠŠ°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½Š½Ń Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ було оновлено. @@ -1806,16 +1812,16 @@ settings.event_push_desc=Git push Го Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ. settings.event_repository=Репозиторій settings.event_repository_desc=Репозиторій створений або виГалено. settings.event_header_issue=ŠŸŠ¾Š“Ń–Ń— заГачі -settings.event_issues=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Šø -settings.event_issues_desc=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Š° віГкрита, закрита, повторно віГкрита або віГреГагована. -settings.event_issue_assign=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Š° прив'ŃŠ·Š°Š½Š° -settings.event_issue_assign_desc=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Š° призначена або скасована. -settings.event_issue_label=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Š° Š· Š¼Ń–Ń‚ŠŗŠ¾ŃŽ -settings.event_issue_label_desc=ŠœŃ–Ń‚ŠŗŠø проблем оновлено або виГалено. -settings.event_issue_milestone=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Šø ŠµŃ‚Š°ŠæŃƒ -settings.event_issue_milestone_desc=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Š° призначена на етап або виГалена Š· ŠµŃ‚Š°ŠæŃƒ. -settings.event_issue_comment=ŠšŠ¾Š¼ŠµŠ½Ń‚Š°Ń€ проблеми -settings.event_issue_comment_desc=ŠšŠ¾Š¼ŠµŠ½Ń‚Š°Ń€ проблеми створено, виГалено чи віГреГаговано. +settings.event_issues=ЗаГачі +settings.event_issues_desc=ЗаГача віГкрита, закрита, повторно віГкрита або віГреГагована. +settings.event_issue_assign=ЗаГача прив'ŃŠ·Š°Š½Š° +settings.event_issue_assign_desc=Š—Š°Š“Š°Ń‡Ńƒ призначено або скасовано. +settings.event_issue_label=ЗаГача Š· Š¼Ń–Ń‚ŠŗŠ¾ŃŽ +settings.event_issue_label_desc=ŠœŃ–Ń‚ŠŗŠø заГачі оновлено або виГалено. +settings.event_issue_milestone=ЗаГача Š· етапом +settings.event_issue_milestone_desc=ЗаГача призначена на етап або виГалена Š· ŠµŃ‚Š°ŠæŃƒ. +settings.event_issue_comment=ŠšŠ¾Š¼ŠµŠ½Ń‚Š°Ń€ заГачі +settings.event_issue_comment_desc=ŠšŠ¾Š¼ŠµŠ½Ń‚Š°Ń€ заГачі створено, виГалено чи віГреГаговано. settings.event_header_pull_request=ŠŸŠ¾Š“Ń–Ń— Š·Š°ŠæŠøŃ‚Ńƒ Š·Š»ŠøŃ‚Ń‚Ń settings.event_pull_request=Запити Го Š·Š»ŠøŃ‚Ń‚Ń settings.event_pull_request_desc=Запит Го Š·Š»ŠøŃ‚Ń‚Ń віГкрито, закрито, перевіГкрито або віГреГаговано. @@ -1942,7 +1948,7 @@ settings.matrix.access_token=Токен Š”Š¾ŃŃ‚ŃƒŠæŃƒ settings.matrix.message_type=Тип ŠæŠ¾Š²Ń–Š“Š¾Š¼Š»ŠµŠ½Š½Ń settings.archive.button=Архівний репозиторій settings.archive.header=ВіГправити репозиторій в архів -settings.archive.text=ŠŃ€Ń…Ń–Š²ŃƒŠ²Š°Š½Š½Ń Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–Ń Š·Ń€Š¾Š±ŠøŃ‚ŃŒ його Š“Š¾ŃŃ‚ŃƒŠæŠ½ŠøŠ¼ лише Š“Š»Ń Ń‡ŠøŃ‚Š°Š½Š½Ń. Він не Š²Ń–Š“Š¾Š±Ń€Š°Š¶Š°Ń”Ń‚ŃŒŃŃ на панелі, в нього не Š¼Š¾Š¶ŃƒŃ‚ŃŒ Š²Š½Š¾ŃŠøŃ‚ŠøŃŃŒ зміни і не можна ŃŃ‚Š²Š¾Ń€ŃŽŠ²Š°Ń‚Šø запити Š· проблем та пулл-реквести. +settings.archive.text=ŠŃ€Ń…Ń–Š²ŃƒŠ²Š°Š½Š½Ń Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–Ń Š·Ń€Š¾Š±ŠøŃ‚ŃŒ його Š“Š¾ŃŃ‚ŃƒŠæŠ½ŠøŠ¼ лише Š“Š»Ń Ń‡ŠøŃ‚Š°Š½Š½Ń. Він не Š²Ń–Š“Š¾Š±Ń€Š°Š¶Š°Ń”Ń‚ŃŒŃŃ на панелі, в нього не Š¼Š¾Š¶ŃƒŃ‚ŃŒ Š²Š½Š¾ŃŠøŃ‚ŠøŃŃŒ зміни і не можна ŃŃ‚Š²Š¾Ń€ŃŽŠ²Š°Ń‚Šø запити Š· заГач та пулл-реквести. settings.archive.success=Š ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ ŃƒŃŠæŃ–ŃˆŠ½Š¾ присвоєно ŃŃ‚Š°Ń‚ŃƒŃ архівного. settings.archive.error=Š”Ń‚Š°Š»Š°ŃŃ помилка при спробі Š°Ń€Ń…Ń–Š²ŃƒŠ²Š°Ń‚Šø репозиторій. Š”Š¾ŠŗŠ»Š°Š“Š½Ń–ŃˆŃƒ Ń–Š½Ń„Š¾Ń€Š¼Š°Ń†Ń–ŃŽ Гив. у Š¶ŃƒŃ€Š½Š°Š»Ń–. settings.archive.error_ismirror=ŠŠµŠ¼Š¾Š¶Š»ŠøŠ²Š¾ Š°Ń€Ń…Ń–Š²ŃƒŠ²Š°Ń‚Šø Š“Š·ŠµŃ€ŠŗŠ°Š»ŃŒŠ½ŠøŠ¹ репозиротрій. @@ -1950,7 +1956,7 @@ settings.archive.branchsettings_unavailable=ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Šø гілки не settings.archive.tagsettings_unavailable=ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Šø міток Š½ŠµŠ“Š¾ŃŃ‚ŃƒŠæŠ½Ń–, ŃŠŗŃ‰Š¾ репозиторій архівний. settings.unarchive.button=Š—Š½ŃŃ‚Šø архівний ŃŃ‚Š°Ń‚ŃƒŃ settings.unarchive.header=Š—Š½ŃŃ‚Šø архівний ŃŃ‚Š°Ń‚ŃƒŃ Š“Š»Ń Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–Ń -settings.unarchive.text=Š—Š½ŃŃ‚Ń‚Ń ŃŃ‚Š°Ń‚ŃƒŃŃƒ архівного Š²Ń–Š“Š½Š¾Š²ŠøŃ‚ŃŒ запис в репозиторій, а також віГкриє Š¼Š¾Š¶Š»ŠøŠ²Ń–ŃŃ‚ŃŒ ŃŃ‚Š²Š¾Ń€ŃŽŠ²Š°Ń‚Šø запити Š· нових проблем та пулл-запити. +settings.unarchive.text=Š—Š½ŃŃ‚Ń‚Ń ŃŃ‚Š°Ń‚ŃƒŃŃƒ архівного Š²Ń–Š“Š½Š¾Š²ŠøŃ‚ŃŒ запис в репозиторій, а також віГкриє Š¼Š¾Š¶Š»ŠøŠ²Ń–ŃŃ‚ŃŒ ŃŃ‚Š²Š¾Ń€ŃŽŠ²Š°Ń‚Šø запити Š· нових заГачах та пулл-запити. settings.unarchive.success=Š”Ń‚Š°Ń‚ŃƒŃ архівний ŃƒŃŠæŃ–ŃˆŠ½Š¾ Š·Š½ŃŃ‚Š¾. settings.unarchive.error=Š”Ń‚Š°Š»Š°ŃŃ помилка при спробі ŃŠŗŠ°ŃŃƒŠ²Š°Ń‚Šø архівний ŃŃ‚Š°Ń‚ŃƒŃ Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–Ń. Š”Š¾ŠŗŠ»Š°Š“Š½Ń–ŃˆŃƒ Ń–Š½Ń„Š¾Ń€Š¼Š°Ń†Ń–ŃŽ Гив. у Š¶ŃƒŃ€Š½Š°Š»Ń–. settings.update_avatar_success=Аватар Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€Ń–ŃŽ оновлений. @@ -2037,7 +2043,7 @@ diff.image.side_by_side=ŠŸŠ»Ń–Ń‡-о-пліч diff.image.swipe=Двайп diff.image.overlay=ŠžŠ²ŠµŃ€Š»ŠµŠ¹ -releases.desc=Š’Ń–Š“ŃŠ»Ń–Š“ŠŗŠ¾Š²ŃƒŠ²Š°Ń‚Šø версії ŠæŃ€Š¾ŠµŠŗŃ‚Ńƒ (релізи) та Š·Š°Š²Š°Š½Ń‚Š°Š¶ŠµŠ½Š½Ń. +releases.desc=Š’Ń–Š“ŃŠ»Ń–Š“ŠŗŠ¾Š²ŃƒŠ²Š°Ń‚Šø версії ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ і Š·Š°Š²Š°Š½Ń‚Š°Š¶ŠµŠ½Š½Ń. release.releases=Релізи release.detail=Деталі Ń€ŠµŠ»Ń–Š·Ńƒ release.tags=Теги @@ -2050,8 +2056,8 @@ release.edit=Ń€ŠµŠ“Š°Š³ŃƒŠ²Š°Ń‚Šø release.ahead.commits=%d коміт(ів) release.ahead.target=Го %s Š· Š¼Š¾Š¼ŠµŠ½Ń‚Ńƒ Ń†ŃŒŠ¾Š³Š¾ випуску release.source_code=КоГ -release.new_subheader=ŠŸŃƒŠ±Š»Ń–ŠŗŠ°Ń†Ń–Ń релізів Гопоможе зберігати Ń‡Ń–Ń‚ŠŗŃƒ Ń–ŃŃ‚Š¾Ń€Ń–ŃŽ Ń€Š¾Š·Š²ŠøŃ‚ŠŗŃƒ вашого ŠæŃ€Š¾ŠµŠŗŃ‚Ńƒ. -release.edit_subheader=ŠŸŃƒŠ±Š»Ń–ŠŗŠ°Ń†Ń–Ń релізів Гопоможе зберігати Ń‡Ń–Ń‚ŠŗŃƒ Ń–ŃŃ‚Š¾Ń€Ń–ŃŽ Ń€Š¾Š·Š²ŠøŃ‚ŠŗŃƒ вашого ŠæŃ€Š¾ŠµŠŗŃ‚Ńƒ. +release.new_subheader=ŠŸŃƒŠ±Š»Ń–ŠŗŠ°Ń†Ń–Ń релізів Гопоможе вам Š¾Ń€Š³Š°Š½Ń–Š·ŃƒŠ²Š°Ń‚Šø Š²ŠµŃ€ŃŃ–ŃŽ ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ. +release.edit_subheader=ŠŸŃƒŠ±Š»Ń–ŠŗŠ°Ń†Ń–Ń релізів Гопоможе вам Š¾Ń€Š³Š°Š½Ń–Š·ŃƒŠ²Š°Ń‚Šø Š²ŠµŃ€ŃŃ–ŃŽ ŠæŃ€Š¾Ń”ŠŗŃ‚Ńƒ. release.tag_name=ŠŠ°Š·Š²Š° Ń‚ŠµŠ³Ńƒ release.target=Š¦Ń–Š»ŃŒ release.tag_helper=Š’ŠøŠ±ŠµŃ€Ń–Ń‚ŃŒ Ń–ŃŠ½ŃƒŃŽŃ‡ŠøŠ¹ тег або ŃŃ‚Š²Š¾Ń€Ń–Ń‚ŃŒ новий. @@ -2175,7 +2181,7 @@ settings.delete_org_title=ВиГалити Š¾Ń€Š³Š°Š½Ń–Š·Š°Ń†Ń–ŃŽ settings.delete_org_desc=Š¦Ń Š¾Ń€Š³Š°Š½Ń–Š·Š°Ń†Ń–Ń буГе безповоротно виГалена. ŠŸŃ€Š¾Š“Š¾Š²Š¶ŠøŃ‚Šø? settings.hooks_desc=ДоГайте webhooks, ŃŠŗŠøŠ¹ буГе Š²ŠøŠŗŠ»ŠøŠŗŠ°Ń‚ŠøŃŃ Š“Š»Ń всіх репозиторіїв ŃŠŗŠøŠ¼Šø волоГіє ця Š¾Ń€Š³Š°Š½Ń–Š·Š°Ń†Ń–Ń. -settings.labels_desc=ДоГайте мітки, ŃŠŗŃ– Š¼Š¾Š¶ŃƒŃ‚ŃŒ Š²ŠøŠŗŠ¾Ń€ŠøŃŃ‚Š¾Š²ŃƒŠ²Š°Ń‚ŠøŃŃ Š“Š»Ń всіх репозиторіїв цієї органцізації. +settings.labels_desc=ДоГати мітки, ŃŠŗŃ– Š¼Š¾Š¶ŃƒŃ‚ŃŒ Š±ŃƒŃ‚Šø використані Š“Š»Ń заГач Š“Š»Ń всіх репозиторіїв в цій організації. members.membership_visibility=Š’ŠøŠ“ŠøŠ¼Ń–ŃŃ‚ŃŒ ŃƒŃ‡Š°ŃŠ½ŠøŠŗŠ°: members.public=ŠŸŠ¾ŠŗŠ°Š·ŃƒŠ²Š°Ń‚Šø @@ -2400,7 +2406,7 @@ repos.private=ŠŸŃ€ŠøŠ²Š°Ń‚Š½ŠøŠ¹ repos.watches=Š”Ń‚ŠµŠ¶Š°Ń‚ŃŒ repos.stars=Š’ Š¾Š±Ń€Š°Š½Š¾Š¼Ńƒ repos.forks=Форки -repos.issues=ŠŸŃ€Š¾Š±Š»ŠµŠ¼Šø +repos.issues=ЗаГачі repos.size=Розмір defaulthooks=Веб-Ń…ŃƒŠŗŠø за Š·Š°Š¼Š¾Š²Ń‡ŃƒŠ²Š°Š½Š½ŃŠ¼ @@ -2583,7 +2589,7 @@ config.default_enable_timetracking=Š£Š²Ń–Š¼ŠŗŠ½ŃƒŃ‚Šø Š²Ń–Š“ŃŃ‚ŠµŠ¶ŠµŠ½Š½Ń ч config.default_allow_only_contributors_to_track_time=Š’Ń€Š°Ń…Š¾Š²ŃƒŠ²Š°Ń‚Šø Ń‚Ń–Š»ŃŒŠŗŠø ŃƒŃ‡Š°ŃŠ½ŠøŠŗŃ–Š² розробки в ŠæŃ–Š“Ń€Š°Ń…ŃƒŠ½ŠŗŃƒ Ń‡Š°ŃŃƒ config.no_reply_address=ŠŸŃ€ŠøŃ…Š¾Š²Š°Š½ŠøŠ¹ Гомен електронної ŠæŠ¾ŃˆŃ‚Šø config.default_visibility_organization=Š’ŠøŠ“ŠøŠ¼Ń–ŃŃ‚ŃŒ за Š·Š°Š¼Š¾Š²Ń‡ŃƒŠ²Š°Š½Š½ŃŠ¼ Š“Š»Ń нових організацій -config.default_enable_dependencies=Š£Š²Ń–Š¼ŠŗŠ½ŃƒŃ‚Šø залежності проблем за Š·Š°Š¼Š¾Š²Ń‡ŃƒŠ²Š°Š½Š½ŃŠ¼ +config.default_enable_dependencies=Š£Š²Ń–Š¼ŠŗŠ½ŃƒŃ‚Šø залежності заГачі за Š·Š°Š¼Š¾Š²Ń‡ŃƒŠ²Š°Š½Š½ŃŠ¼ config.webhook_config=ŠšŠ¾Š½Ń„Ń–Š³ŃƒŃ€Š°Ń†Ń–Ń web-Ń…ŃƒŠŗŃ–Š² config.queue_length=Довжина черги @@ -2738,13 +2744,13 @@ notices.delete_success=Š”ŠæŠ¾Š²Ń–Ń‰ŠµŠ½Š½Ń системи були виГале create_repo=створив(ла) репозиторій %s rename_repo=репозиторій перейменовано Š· %[1]s на %[3]s commit_repo=наГіслав зміни (push) Го %[3]s о %[4]s -create_issue=`віГкрив ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[3]s#%[2]s` -close_issue=`закрив ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[3]s#%[2]s` -reopen_issue=`повторно віГкрив ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[3]s#%[2]s` +create_issue=`віГкрив Š·Š°Š“Š°Ń‡Ńƒ %[3]s#%[2]s` +close_issue=`закрив Š·Š°Š“Š°Ń‡Ńƒ %[3]s#%[2]s` +reopen_issue=`повторно віГкрив Š·Š°Š“Š°Ń‡Ńƒ %[3]s#%[2]s` create_pull_request=`створив запит Š·Š»ŠøŃ‚Ń‚Ń %[3]s#%[2]s` close_pull_request=`закрив запит Š·Š»ŠøŃ‚Ń‚Ń %[3]s#%[2]s` reopen_pull_request=`повторно віГкрив запит Š·Š»ŠøŃ‚Ń‚Ń %[3]s#%[2]s` -comment_issue=`ŠæŃ€Š¾ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Š² ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ %[3]s#%[2]s` +comment_issue=`ŠæŃ€Š¾ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Š² Š·Š°Š“Š°Ń‡Ńƒ %[3]s#%[2]s` comment_pull=`ŠæŃ€Š¾ŠŗŠ¾Š¼ŠµŠ½Ń‚ŃƒŠ²Š°Š² запит Š·Š»ŠøŃ‚Ń‚Ń %[3]s#%[2]s` merge_pull_request=`ŠæŃ€ŠøŠ¹Š½ŃŠ² запит Š·Š»ŠøŃ‚Ń‚Ń %[3]s#%[2]s` transfer_repo=перенесено репозиторій %s у %s diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index e78abd05d5..c2c1713883 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -940,14 +940,14 @@ migrate.migrating=ę­£åœØä»Ž %s 迁移... migrate.migrating_failed=从 %s 迁移失蓄。 migrate.migrating_failed.error=é”™čÆÆļ¼š%s migrate.migrating_failed_no_addr=迁移失蓄。 -migrate.github.description=从 github.com ęˆ–å…¶ä»– GitHub å®žä¾‹čæē§»ę•°ę®ć€‚ +migrate.github.description=从 github.com ęˆ–å…¶ä»– GitHub å®žä¾‹čæē§»ę•°ę® migrate.git.description=ä»Žä»»ę„ Git ęœåŠ”čæē§»ä»“åŗ“ć€‚ -migrate.gitlab.description=从 gitlab.com ęˆ–å…¶ä»– GitLab å®žä¾‹čæē§»ę•°ę®ć€‚ -migrate.gitea.description=从 gitea.com ęˆ–å…¶ä»– Gitea å®žä¾‹čæē§»ę•°ę®ć€‚ +migrate.gitlab.description=从 gitlab.com ęˆ–å…¶ä»– GitLab å®žä¾‹čæē§»ę•°ę® +migrate.gitea.description=从 gitea.com ęˆ–å…¶ä»– Gitea å®žä¾‹čæē§»ę•°ę® migrate.gogs.description=从 notabug.org ęˆ–å…¶ä»– Gogs å®žä¾‹čæē§»ę•°ę®ć€‚ -migrate.onedev.description=从 code.onedev.io ęˆ–å…¶ä»– OneDev å®žä¾‹čæē§»ę•°ę®ć€‚ -migrate.codebase.description=从 codebasehq.com čæē§»ę•°ę®ć€‚ -migrate.gitbucket.description=从 GitBucket å®žä¾‹čæē§»ę•°ę®ć€‚ +migrate.onedev.description=从 code.onedev.io ęˆ–å…¶ä»– OneDev å®žä¾‹čæē§»ę•°ę® +migrate.codebase.description=从 codebasehq.com čæē§»ę•°ę® +migrate.gitbucket.description=从 GitBucket å®žä¾‹čæē§»ę•°ę® migrate.migrating_git=迁移Gitę•°ę® migrate.migrating_topics=迁移主题 migrate.migrating_milestones=čæē§»é‡ŒēØ‹ē¢‘ @@ -1729,7 +1729,7 @@ settings.use_internal_wiki=使用内置百科 settings.use_external_wiki=ä½æē”Øå¤–éƒØē™¾ē§‘ settings.external_wiki_url=å¤–éƒØ Wiki é“¾ęŽ„ settings.external_wiki_url_error=å¤–éƒØē™¾ē§‘é“¾ęŽ„ę— ę•ˆ -settings.external_wiki_url_desc=å½“ē‚¹å‡»å·„å•ę ‡ē­¾ę—¶ļ¼Œč®æé—®č€…å°†č¢«é‡å®šå‘åˆ°å¤–éƒØå·„å•ē³»ē»Ÿēš„URL怂 +settings.external_wiki_url_desc=å½“ē‚¹å‡»ē™¾ē§‘ę ‡ē­¾ę—¶ļ¼Œč®æé—®č€…å°†č¢«é‡å®šå‘åˆ°å¤–éƒØē™¾ē§‘ē³»ē»Ÿēš„URL怂 settings.issues_desc=åÆē”Øå·„å•ē³»ē»Ÿ settings.use_internal_issue_tracker=ä½æē”Øå†…ē½®ēš„č½»é‡ēŗ§å·„å•ē®”ē†ē³»ē»Ÿ settings.use_external_issue_tracker=ä½æē”Øå¤–éƒØēš„å·„å•ē®”ē†ē³»ē»Ÿ @@ -2334,6 +2334,7 @@ first_page=首锵 last_page=末锵 total=ę€»č®”ļ¼š%d +dashboard.new_version_hint=Gitea %s ēŽ°å·²åÆē”Øļ¼Œę‚Øę­£åœØčæč”Œ %sć€‚ęŸ„ēœ‹ 博客 äŗ†č§£ę›“å¤ščÆ¦ęƒ…ć€‚ dashboard.statistic=ę‘˜č¦ dashboard.operations=ē»“ęŠ¤ę“ä½œ dashboard.system_status=ē³»ē»ŸēŠ¶ę€ @@ -2407,6 +2408,7 @@ dashboard.last_gc_pause=上欔 GC ęš‚åœę—¶é—“ dashboard.gc_times=GC ę‰§č”Œę¬”ę•° dashboard.delete_old_actions=ä»Žę•°ę®åŗ“äø­åˆ é™¤ę‰€ęœ‰ę—§ę“ä½œč®°å½• dashboard.delete_old_actions.started=å·²å¼€å§‹ä»Žę•°ę®åŗ“äø­åˆ é™¤ę‰€ęœ‰ę—§ę“ä½œč®°å½•ć€‚ +dashboard.update_checker=ę›“ę–°ę£€ęŸ„å™Ø users.user_manage_panel=ē”Øęˆ·åøęˆ·ē®”ē† users.new_account=åˆ›å»ŗę–°åøęˆ· diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index d1a703021a..5b484c758e 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -34,6 +34,20 @@ twofa=å…©ę­„é©Ÿé©—č­‰ twofa_scratch=å…©ę­„é©Ÿé©—č­‰å‚™ē”Øé©—č­‰ē¢¼ passcode=驗證碼 +webauthn_insert_key=ę’å…„ę‚Øēš„å®‰å…Øé‡‘é‘° +webauthn_sign_in=ęŒ‰äø‹ę‚Øå®‰å…Øé‡‘é‘°äøŠēš„ęŒ‰éˆ•ć€‚å¦‚ęžœę‚Øēš„å®‰å…Øé‡‘é‘°ę²’ęœ‰ęŒ‰éˆ•ļ¼Œč«‹é‡ę–°ę’å…„ć€‚ +webauthn_press_button=č«‹ęŒ‰äø‹ę‚Øå®‰å…Øé‡‘é‘°äøŠēš„ęŒ‰éˆ•ā€¦ +webauthn_use_twofa=ä½æē”Øä¾†č‡Ŗę‰‹ę©Ÿēš„å…©ę­„é©Ÿé©—č­‰ē¢¼ +webauthn_error=ē„”ę³•č®€å–ę‚Øēš„å®‰å…Øé‡‘é‘°ć€‚ +webauthn_unsupported_browser=ę‚Øēš„ē€č¦½å™Øé‚„äøę”Æę“ WebAuthn怂 +webauthn_error_unknown=ē™¼ē”ŸęœŖēŸ„ēš„éŒÆčŖ¤ļ¼Œč«‹å†č©¦äø€ę¬”ć€‚ +webauthn_error_insecure=WebAuthn åŖę”Æę“å®‰å…Øé€£ē·šć€‚ęƒ³åœØ HTTP äøŠęø¬č©¦ļ¼Œę‚ØåÆä»„ä½æē”Øć€Œlocalhost怍ꈖ怌127.0.0.1怍 +webauthn_error_unable_to_process=ä¼ŗęœå™Øē„”ę³•åŸ·č”Œę‚Øēš„č«‹ę±‚ć€‚ +webauthn_error_duplicated=ę­¤č«‹ę±‚äøå…čØ±ä½æē”Øé€™å€‹å®‰å…Øé‡‘é‘°ć€‚č«‹ē¢ŗäæč©²é‡‘é‘°å°šęœŖčØ»å†Šć€‚ +webauthn_error_empty=ę‚Øåæ…é ˆå‘½åę­¤é‡‘é‘°ć€‚ +webauthn_error_timeout=åœØęˆåŠŸč®€å–é‡‘é‘°ä¹‹å‰å·²é€¾ę™‚ļ¼Œč«‹é‡ę–°č¼‰å…„ę­¤é é¢äø¦é‡č©¦ć€‚ +webauthn_u2f_deprecated=怌%sć€é‡‘é‘°ä½æē”Øå·²å»¢ę£„ēš„ U2F ęµēØ‹é€²č”Œé©—č­‰ć€‚ę‚Øę‡‰č©²é‡ę–°čØ»å†Šę­¤é‡‘é‘°äø¦å°‡å…ˆå‰čØ»å†Šēš„ē§»é™¤ć€‚ +webauthn_reload=é‡ę–°č¼‰å…„ repository=å„²å­˜åŗ« organization=組織 @@ -389,8 +403,8 @@ repo.collaborator.added.subject=%s ęŠŠę‚ØåŠ å…„åˆ° %s repo.collaborator.added.text=ę‚Øå·²č¢«ę–°å¢žē‚ŗå„²å­˜åŗ«ēš„å”ä½œč€…ļ¼š [modal] -yes=ē¢ŗčŖę“ä½œ -no=å–ę¶ˆę“ä½œ +yes=是 +no=否 modify=ꛓꖰ [form] @@ -513,10 +527,11 @@ twofa=å…©ę­„é©Ÿé©—č­‰ account_link=å·²é€£ēµåø³č™Ÿ organization=組織 uid=ē”Øęˆ¶ ID +webauthn=安全金鑰 public_profile=å…¬é–‹ēš„å€‹äŗŗč³‡ę–™ biography_placeholder=å‘ŠčØ“ęˆ‘å€‘äø€äŗ›é—œę–¼ä½ ēš„äŗ‹ -profile_desc=ę‚Øēš„é›»å­äæ”ē®±å°‡č¢«ē”Øę–¼é€šēŸ„ęé†’å’Œå…¶ä»–ę“ä½œć€‚ +profile_desc=ę‚Øēš„é›»å­äæ”ē®±å°‡č¢«ē”Øę–¼é€šēŸ„ęé†’å’Œå…¶ä»–ä½œę„­ć€‚ password_username_disabled=éžęœ¬åœ°ä½æē”Øč€…äøå…čØ±ę›“ę”¹ä»–å€‘ēš„åø³č™Ÿć€‚č©³ē“°č³‡čØŠč«‹čÆēµ”ę‚Øēš„ē³»ēµ±ē®”ē†å“”ć€‚ full_name=å…Øå website=個人網站 @@ -530,7 +545,7 @@ update_profile_success=å·²ę›“ę–°ę‚Øēš„å€‹äŗŗč³‡ę–™ć€‚ change_username=ę‚Øēš„åø³č™Ÿå·²ę›“ę”¹ć€‚ change_username_prompt=ę³Øę„ļ¼šäæ®ę”¹åø³č™Ÿä¹Ÿęœƒę›“ę”¹ę‚Øēš„åø³ęˆ¶ēš„ URL怂 change_username_redirect_prompt=čˆŠēš„åø³č™Ÿč¢«é ˜ē”Øå‰ļ¼Œęœƒé‡ę–°å°Žå‘ę‚Øēš„ę–°åø³č™Ÿć€‚ -continue=ē¹¼ēŗŒę“ä½œ +continue=繼續 cancel=å–ę¶ˆ language=čŖžčØ€ ui=ä½ˆę™Æäø»é”Œ @@ -561,7 +576,7 @@ emails=電子俔箱 manage_emails=箔理電子俔箱 manage_themes=éøę“‡é čØ­ä½ˆę™Æäø»é”Œ manage_openid=箔理 OpenID 位址 -email_desc=ę‚Øēš„äø»č¦é›»å­äæ”ē®±å°‡č¢«ē”Øę–¼é€šēŸ„ęé†’å’Œå…¶ä»–ę“ä½œć€‚ +email_desc=ę‚Øēš„äø»č¦é›»å­äæ”ē®±å°‡č¢«ē”Øę–¼é€šēŸ„ęé†’å’Œå…¶ä»–ä½œę„­ć€‚ theme_desc=é€™å°‡ę˜Æę‚ØåœØę•“å€‹ē¶²ē«™äøŠēš„é čØ­ä½ˆę™Æäø»é”Œć€‚ primary=主要 activated=å·²å•Ÿē”Ø @@ -706,7 +721,7 @@ oauth2_regenerate_secret_hint=éŗå¤±ę‚Øēš„åÆ†é‘°ļ¼Ÿ oauth2_client_secret_hint=č«‹å‚™ä»½ę‚Øēš„ē„•é‘°ć€‚ē„•é‘°åœØę‚Øé›¢é–‹é€™å€‹é é¢å¾Œå°‡äøęœƒå†é”Æē¤ŗć€‚ oauth2_application_edit=編輯 oauth2_application_create_description=OAuth2 ę‡‰ē”ØēØ‹å¼č®“ę‚Øēš„ē¬¬äø‰ę–¹ę‡‰ē”ØēØ‹å¼åÆä»„å­˜å–ę­¤ Gitea äøŠēš„åø³ęˆ¶ć€‚ -oauth2_application_remove_description=åˆŖé™¤ OAuth2 ę‡‰ē”Øęœƒę‹’ēµ•å®ƒå­˜å–ę­¤ Gitea äøŠå·²ęŽˆę¬Šēš„åø³ęˆ¶ć€‚ę˜Æå¦ē¹¼ēŗŒļ¼Ÿ +oauth2_application_remove_description=åˆŖé™¤ OAuth2 ę‡‰ē”ØēØ‹å¼ęœƒę‹’ēµ•å®ƒå­˜å–ę­¤ Gitea äøŠå·²ęŽˆę¬Šēš„åø³ęˆ¶ć€‚ę˜Æå¦ē¹¼ēŗŒļ¼Ÿ authorized_oauth2_applications=å·²ęŽˆę¬Šēš„ OAuth2 ę‡‰ē”ØēØ‹å¼ authorized_oauth2_applications_description=ę‚Øå·²ęŽˆę¬Šēµ¦é€™äŗ›ē¬¬äø‰ę–¹ę‡‰ē”ØēØ‹å¼å­˜å–ę‚Øå€‹äŗŗ Gitea åø³ęˆ¶ć€‚č«‹å°äøå†éœ€č¦ēš„ę‡‰ē”ØēØ‹å¼ę’¤éŠ·å­˜å–ę¬Šć€‚ @@ -733,6 +748,11 @@ passcode_invalid=ē„”ę•ˆēš„é©—č­‰ē¢¼ļ¼Œč«‹é‡č©¦ć€‚ twofa_enrolled=ę‚Øēš„åø³ęˆ¶å·²ē¶“å•Ÿē”Øäŗ†å…©ę­„é©Ÿé©—č­‰ć€‚č«‹å°‡å‚™ē”Øé©—č­‰ē¢¼ (%s) äæå­˜åˆ°äø€å€‹å®‰å…Øēš„åœ°ę–¹ļ¼Œå®ƒåŖęœƒé”Æē¤ŗé€™éŗ¼äø€ę¬”ļ¼ twofa_failed_get_secret=å–å¾—åÆ†é‘°ļ¼ˆSecret)失敗。 +webauthn_desc=å®‰å…Øé‡‘é‘°ę˜ÆåŒ…å«åŠ åÆ†åÆ†é‘°ēš„ē”¬é«”čØ­å‚™ļ¼Œå®ƒå€‘åÆä»„ē”Øę–¼å…©ę­„é©Ÿé©—č­‰ć€‚å®‰å…Øé‡‘é‘°åæ…é ˆę”Æę“ WebAuthn Authenticator 標準。 +webauthn_register_key=ę–°å¢žå®‰å…Øé‡‘é‘° +webauthn_nickname=暱稱 +webauthn_delete_key=移除安全金鑰 +webauthn_delete_key_desc=å¦‚ęžœę‚Øē§»é™¤å®‰å…Øé‡‘é‘°ļ¼Œå°‡äøčƒ½å†ä½æē”Øå®ƒē™»å…„ć€‚ę˜Æå¦ē¹¼ēŗŒļ¼Ÿ manage_account_links=ē®”ē†å·²é€£ēµēš„åø³ęˆ¶ manage_account_links_desc=é€™äŗ›å¤–éƒØåø³ęˆ¶å·²é€£ēµåˆ°ę‚Øēš„ Gitea åø³ęˆ¶ć€‚ @@ -920,14 +940,14 @@ migrate.migrating=ę­£åœØå¾ž %s 遷移... migrate.migrating_failed=從 %s 遷移失敗 migrate.migrating_failed.error=錯誤:%s migrate.migrating_failed_no_addr=遷移失敗。 -migrate.github.description=從 github.com ęˆ–å…¶ä»– GitHub 實例遷移資料。 +migrate.github.description=從 github.com ęˆ–å…¶ä»– GitHub åŸ·č”Œå€‹é«”é·ē§»č³‡ę–™ć€‚ migrate.git.description=從任何 Git ęœå‹™é·ē§»å„²å­˜åŗ«ć€‚ -migrate.gitlab.description=從 gitlab.com ęˆ–å…¶ä»– GitLab 實例遷移資料。 -migrate.gitea.description=從 gitea.com ęˆ–å…¶ä»– Gitea 實例遷移資料。 -migrate.gogs.description=從 notabug.org ęˆ–å…¶ä»– Gogs 實例遷移資料。 -migrate.onedev.description=從 code.onedev.io ęˆ–å…¶ä»– OneDev 實例遷移資料。 +migrate.gitlab.description=從 gitlab.com ęˆ–å…¶ä»– GitLab åŸ·č”Œå€‹é«”é·ē§»č³‡ę–™ć€‚ +migrate.gitea.description=從 gitea.com ęˆ–å…¶ä»– Gitea åŸ·č”Œå€‹é«”é·ē§»č³‡ę–™ć€‚ +migrate.gogs.description=從 notabug.org ęˆ–å…¶ä»– Gogs åŸ·č”Œå€‹é«”é·ē§»č³‡ę–™ć€‚ +migrate.onedev.description=從 code.onedev.io ęˆ–å…¶ä»– OneDev åŸ·č”Œå€‹é«”é·ē§»č³‡ę–™ć€‚ migrate.codebase.description=從 codebasehq.com 遷移資料。 -migrate.gitbucket.description=從 GitBucket 實例遷移資料。 +migrate.gitbucket.description=從 GitBucket åŸ·č”Œå€‹é«”é·ē§»č³‡ę–™ć€‚ migrate.migrating_git=正在遷移 Git 資料 migrate.migrating_topics=正在遷移主锌 migrate.migrating_milestones=ę­£åœØé·ē§»é‡ŒēØ‹ē¢‘ @@ -956,7 +976,7 @@ clone_this_repo=Clone ę­¤å„²å­˜åŗ« create_new_repo_command=å¾žå‘½ä»¤åˆ—å»ŗē«‹ę–°å„²å­˜åŗ«ć€‚ push_exist_repo=å¾žå‘½ä»¤č”ŒęŽØé€å·²ē¶“å»ŗē«‹ēš„å„²å­˜åŗ« empty_message=ę­¤å„²å­˜åŗ«ęœŖåŒ…å«ä»»ä½•å…§å®¹ć€‚ -broken_message=ē„”ę³•č®€å–ę­¤å„²å­˜åŗ«åŗ•å±¤ēš„ Git 資料。請聯絔此 Gitea åÆ¦ä¾‹ēš„ē®”ē†å“”ęˆ–åˆŖé™¤ę­¤å„²å­˜åŗ«ć€‚ +broken_message=ē„”ę³•č®€å–ę­¤å„²å­˜åŗ«åŗ•å±¤ēš„ Git 資料。請聯絔此 Gitea åŸ·č”Œå€‹é«”ēš„ē®”ē†å“”ęˆ–åˆŖé™¤ę­¤å„²å­˜åŗ«ć€‚ code=ēØ‹å¼ē¢¼ code.desc=å­˜å–åŽŸå§‹ē¢¼ć€ęŖ”ę”ˆć€ęäŗ¤å’Œåˆ†ę”Æć€‚ @@ -1084,7 +1104,7 @@ commits.find=ęœå°‹ commits.search_all=ę‰€ęœ‰åˆ†ę”Æ commits.author=ä½œč€… commits.message=備註 -commits.date=ęäŗ¤ę—„ęœŸ +commits.date=ę—„ęœŸ commits.older=ę›“čˆŠēš„ęäŗ¤ commits.newer=ę›“ę–°ēš„ęäŗ¤ commits.signed_by=簽署人 @@ -1132,7 +1152,7 @@ projects.open=開啟 projects.close=關閉 issues.desc=ē®”ē†éŒÆčŖ¤å ±å‘Šć€ä»»å‹™å’Œé‡ŒēØ‹ē¢‘ć€‚ -issues.filter_assignees=ēÆ©éøęˆå“” +issues.filter_assignees=篩選負責人 issues.filter_milestones=ēÆ©éøé‡ŒēØ‹ē¢‘ issues.filter_projects=篩選專攈 issues.filter_labels=篩選標籤 @@ -1156,10 +1176,10 @@ issues.new.no_milestone=ęœŖéøę“‡é‡ŒēØ‹ē¢‘ issues.new.clear_milestone=ęø…é™¤å·²éøå–é‡ŒēØ‹ē¢‘ issues.new.open_milestone=é–‹ę”¾äø­ēš„é‡ŒēØ‹ē¢‘ issues.new.closed_milestone=å·²é—œé–‰ēš„é‡ŒēØ‹ē¢‘ -issues.new.assignees=ęˆå“” -issues.new.add_assignees_title=ęŒ‡ę“¾ęˆå“” -issues.new.clear_assignees=ęø…é™¤ęˆå“” -issues.new.no_assignees=ę²’ęœ‰ęˆå“” +issues.new.assignees=負責人 +issues.new.add_assignees_title=ęŒ‡ę“¾č² č²¬äŗŗ +issues.new.clear_assignees=清除負責人 +issues.new.no_assignees=ę²’ęœ‰č² č²¬äŗŗ issues.new.no_reviewers=ę²’ęœ‰åÆ©ę øč€… issues.new.add_reviewer_title=請求審核 issues.choose.get_started=開始 @@ -1205,8 +1225,8 @@ issues.filter_label_exclude=`使用 alt + click/enter issues.filter_label_no_select=ę‰€ęœ‰ęØ™ē±¤ issues.filter_milestone=é‡ŒēØ‹ē¢‘ issues.filter_milestone_no_select=ę‰€ęœ‰é‡ŒēØ‹ē¢‘ -issues.filter_assignee=ęˆå“” -issues.filter_assginee_no_select=ę‰€ęœ‰ęˆå“” +issues.filter_assignee=負責人 +issues.filter_assginee_no_select=ę‰€ęœ‰č² č²¬äŗŗ issues.filter_type=锞型 issues.filter_type.all_issues=ę‰€ęœ‰å•é”Œ issues.filter_type.assigned_to_you=ęŒ‡ę“¾ēµ¦ę‚Øēš„ @@ -1231,8 +1251,8 @@ issues.action_close=關閉 issues.action_label=標籤 issues.action_milestone=é‡ŒēØ‹ē¢‘ issues.action_milestone_no_select=ē„”é‡ŒēØ‹ē¢‘ -issues.action_assignee=ęˆå“” -issues.action_assignee_no_select=ę²’ęœ‰ęˆå“” +issues.action_assignee=負責人 +issues.action_assignee_no_select=ę²’ęœ‰č² č²¬äŗŗ issues.opened_by=建立於 %[1]s ē”± %[3]s pulls.merged_by=ē”± %[3]s å»ŗē«‹ļ¼Œåˆä½µę–¼ %[1]s pulls.merged_by_fake=ē”± %[2]s å»ŗē«‹ļ¼Œåˆä½µę–¼ %[1]s @@ -1411,7 +1431,7 @@ issues.review.hide_resolved=éš±č—å·²č§£ę±ŗ issues.review.resolve_conversation=č§£ę±ŗå°č©± issues.review.un_resolve_conversation=å–ę¶ˆč§£ę±ŗå°č©± issues.review.resolved_by=ęØ™čØ˜äŗ†ę­¤å°č©±ē‚ŗå·²č§£ę±ŗ -issues.assignee.error=å› ē‚ŗęœŖé ęœŸēš„éŒÆčŖ¤ļ¼ŒęœŖčƒ½ęˆåŠŸęŒ‡ę“¾ę‰€ęœ‰ęˆå“”ć€‚ +issues.assignee.error=å› ē‚ŗęœŖé ęœŸēš„éŒÆčŖ¤ļ¼ŒęœŖčƒ½ęˆåŠŸåŠ å…„ę‰€ęœ‰č² č²¬äŗŗć€‚ issues.reference_issue.body=內容 issues.content_history.deleted=åˆŖé™¤ issues.content_history.edited=編輯 @@ -1552,8 +1572,8 @@ milestones.edit_success=å·²ę›“ę–°é‡ŒēØ‹ē¢‘ć€Œ%s怍怂 milestones.deletion=åˆŖé™¤é‡ŒēØ‹ē¢‘ milestones.deletion_desc=åˆŖé™¤é‡ŒēØ‹ē¢‘ęœƒå¾žę‰€ęœ‰ē›øé—œēš„å•é”Œē§»é™¤å®ƒć€‚ę˜Æå¦ē¹¼ēŗŒļ¼Ÿ milestones.deletion_success=é‡ŒēØ‹ē¢‘å·²åˆŖé™¤ -milestones.filter_sort.closest_due_date=åˆ°ęœŸę—„ē”±čæ‘åˆ°é  -milestones.filter_sort.furthest_due_date=åˆ°ęœŸę—„ē”±é åˆ°čæ‘ +milestones.filter_sort.closest_due_date=ęˆŖę­¢ę—„ęœŸē”±čæ‘åˆ°é  +milestones.filter_sort.furthest_due_date=ęˆŖę­¢ę—„ęœŸē”±é åˆ°čæ‘ milestones.filter_sort.least_complete=å®Œęˆåŗ¦ē”±ä½Žåˆ°é«˜ milestones.filter_sort.most_complete=å®Œęˆåŗ¦ē”±é«˜åˆ°ä½Ž milestones.filter_sort.most_issues=å•é”Œē”±å¤šåˆ°å°‘ @@ -1867,7 +1887,7 @@ settings.event_repository_desc=å»ŗē«‹ęˆ–åˆŖé™¤å„²å­˜åŗ«ć€‚ settings.event_header_issue=å•é”Œäŗ‹ä»¶ settings.event_issues=問锌 settings.event_issues_desc=å»ŗē«‹ć€ē·Øč¼Æć€é—œé–‰åŠé‡ę–°é–‹ę”¾å•é”Œć€‚ -settings.event_issue_assign=ęŒ‡ę“¾ +settings.event_issue_assign=ęŒ‡ę“¾å•é”Œ settings.event_issue_assign_desc=ęŒ‡ę“¾ęˆ–å–ę¶ˆęŒ‡ę“¾å•é”Œć€‚ settings.event_issue_label=標籤 settings.event_issue_label_desc=ę›“ę–°ęˆ–ęø…é™¤å•é”ŒęØ™ē±¤ć€‚ @@ -1878,7 +1898,7 @@ settings.event_issue_comment_desc=å·²ē¶“å»ŗē«‹ć€ē·Øč¼Æęˆ–åˆŖé™¤ēš„å•é”Œē•™čØ€ settings.event_header_pull_request=åˆä½µč«‹ę±‚äŗ‹ä»¶ settings.event_pull_request=åˆä½µč«‹ę±‚ settings.event_pull_request_desc=å»ŗē«‹ć€ē·Øč¼Æć€é—œé–‰åŠé‡ę–°é–‹ę”¾åˆä½µč«‹ę±‚ć€‚ -settings.event_pull_request_assign=åˆä½µč«‹ę±‚ęŒ‡ę“¾ +settings.event_pull_request_assign=ęŒ‡ę“¾åˆä½µč«‹ę±‚ settings.event_pull_request_assign_desc=ęŒ‡ę“¾ęˆ–å–ę¶ˆęŒ‡ę“¾åˆä½µč«‹ę±‚ć€‚ settings.event_pull_request_label=åˆä½µč«‹ę±‚ęØ™ē±¤ settings.event_pull_request_label_desc=ę›“ę–°ęˆ–ęø…é™¤åˆä½µč«‹ę±‚ęØ™ē±¤ć€‚ @@ -2314,11 +2334,12 @@ first_page=首頁 last_page=末頁 total=總計:%d +dashboard.new_version_hint=ē¾å·²ęŽØå‡ŗ Gitea %sļ¼Œę‚Øę­£åœØåŸ·č”Œ %sć€‚ęŸ„ēœ‹éƒØč½ę ¼ä»„ē²å¾—ę›“å¤šč³‡čØŠć€‚ dashboard.statistic=ę‘˜č¦ -dashboard.operations=ē¶­č­·ę“ä½œ +dashboard.operations=維護作愭 dashboard.system_status=系統狀態 dashboard.statistic_info=Gitea č³‡ę–™åŗ«ēµ±čØˆļ¼š%d ä½ä½æē”Øč€…ļ¼Œ%d å€‹ēµ„ē¹”ļ¼Œ%d å€‹å…¬é‘°ļ¼Œ%d å€‹å„²å­˜åŗ«ļ¼Œ%d å€‹å„²å­˜åŗ«é—œę³Øļ¼Œ%d å€‹ę˜Ÿč™Ÿļ¼Œ%d ę¬”č”Œē‚ŗļ¼Œ%d ę¢ę¬Šé™čØ˜éŒ„ļ¼Œ%d å€‹å•é”Œļ¼Œ%d å‰‡ē•™čØ€ļ¼Œ%d å€‹ē¤¾ē¾¤åø³ęˆ¶ļ¼Œ%d å€‹ē”Øęˆ¶é—œę³Øļ¼Œ%d å€‹é”åƒļ¼Œ%d å€‹ē‰ˆęœ¬ē™¼ä½ˆļ¼Œ%d å€‹čŖč­‰ä¾†ęŗļ¼Œ%d 個 Webhook ,%d å€‹é‡ŒēØ‹ē¢‘ļ¼Œ%d å€‹ęØ™ē±¤ļ¼Œ%d 個 Hook ä»»å‹™ļ¼Œ%d å€‹åœ˜éšŠļ¼Œ%d å€‹ę›“ę–°ä»»å‹™ļ¼Œ%d 個附件。 -dashboard.operation_name=ę“ä½œåēØ± +dashboard.operation_name=ä½œę„­åēØ± dashboard.operation_switch=開關 dashboard.operation_run=執蔌 dashboard.clean_unbind_oauth=ęø…ē†ęœŖē¶å®šēš„ OAuth 連結 @@ -2387,6 +2408,7 @@ dashboard.last_gc_pause=上欔 GC ęš«åœę™‚é–“ dashboard.gc_times=GC åŸ·č”Œę¬”ę•ø dashboard.delete_old_actions=å¾žč³‡ę–™åŗ«åˆŖé™¤ę‰€ęœ‰čˆŠč”Œē‚ŗ dashboard.delete_old_actions.started=å¾žč³‡ę–™åŗ«åˆŖé™¤ę‰€ęœ‰čˆŠč”Œē‚ŗēš„ä»»å‹™å·²å•Ÿå‹•ć€‚ +dashboard.update_checker=ę›“ę–°ęŖ¢ęŸ„å™Ø users.user_manage_panel=ä½æē”Øč€…åø³ęˆ¶ē®”ē† users.new_account=å»ŗē«‹ä½æē”Øč€…åø³ęˆ¶ @@ -2567,7 +2589,7 @@ auths.tips.oauth2.general=OAuth2 čŖč­‰ auths.tips.oauth2.general.tip=čØ»å†Šę–°ēš„ OAuth2 čŖč­‰ę™‚ļ¼Œcallback/redirect ē¶²å€ę‡‰ē‚ŗļ¼š/user/oauth2//callback auths.tip.oauth2_provider=OAuth2 ęä¾›č€… auths.tip.bitbucket=čØ»å†Šę–°ēš„ OAuth å®¢ęˆ¶ē«Æäø¦åŠ å…„ę¬Šé™ć€ŒAccount - Readć€ć€‚ē¶²å€ļ¼šhttps://bitbucket.org/account/user//oauth-consumers/new -auths.tip.nextcloud=åœØę‚Øēš„ Nextcloud ä½æē”Øć€ŒčØ­å®š -> 安全性 -> OAuth 2.0 å®¢ęˆ¶ē«Æć€čØ»å†Šę–°ēš„ OAuth 客戶端 +auths.tip.nextcloud=åœØę‚Øēš„åŸ·č”Œå€‹é«”äø­ļ¼Œę–¼éøå–®ć€ŒčØ­å®š -> 安全性 -> OAuth 2.0 å®¢ęˆ¶ē«Æć€čØ»å†Šę–°ēš„ OAuth 客戶端 auths.tip.dropbox=å»ŗē«‹äø€å€‹ę–°ēš„ Appć€‚ē¶²å€ļ¼šhttps://www.dropbox.com/developers/apps auths.tip.facebook=čØ»å†Šäø€å€‹ę–°ēš„ę‡‰ē”ØēØ‹å¼äø¦ę–°å¢žē”¢å“ć€ŒFacebook ē™»å…„ć€ć€‚ē¶²å€ļ¼šhttps://developers.facebook.com/apps auths.tip.github=čØ»å†Šę–°ēš„ OAuth ę‡‰ē”ØēØ‹å¼ć€‚ē¶²å€ļ¼šhttps://github.com/settings/applications/new @@ -2874,7 +2896,7 @@ notifications=é€šēŸ„ unread=ęœŖč®€ read=已讀 no_unread=ę²’ęœ‰ęœŖč®€é€šēŸ„ -no_read=ę²’ęœ‰é€šēŸ„ +no_read=ę²’ęœ‰å·²č®€é€šēŸ„ pin=å›ŗå®šé€šēŸ„ mark_as_read=ęØ™čØ˜ē‚ŗå·²č®€ mark_as_unread=ęØ™čØ˜ē‚ŗęœŖč®€ diff --git a/package-lock.json b/package-lock.json index da8a0d8303..2f8d921e21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "@claviska/jquery-minicolors": "2.3.6", "@primer/octicons": "16.2.0", "add-asset-webpack-plugin": "2.0.1", - "codemirror": "5.65.0", + "codemirror": "5.65.1", "css-loader": "6.5.1", "dropzone": "6.0.0-beta.2", "easymde": "2.16.1", @@ -23,13 +23,13 @@ "less": "4.1.2", "less-loader": "10.2.0", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "8.13.9", + "mermaid": "8.14.0", "mini-css-extract-plugin": "2.5.2", "monaco-editor": "0.31.1", "monaco-editor-webpack-plugin": "7.0.1", "pretty-ms": "7.0.1", "sortablejs": "1.14.0", - "swagger-ui-dist": "4.1.3", + "swagger-ui-dist": "4.2.1", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", "vue": "2.6.14", @@ -37,8 +37,8 @@ "vue-calendar-heatmap": "0.8.4", "vue-loader": "15.9.8", "vue-template-compiler": "2.6.14", - "webpack": "5.66.0", - "webpack-cli": "4.9.1", + "webpack": "5.67.0", + "webpack-cli": "4.9.2", "workbox-routing": "6.4.2", "workbox-strategies": "6.4.2", "worker-loader": "3.0.8", @@ -55,7 +55,7 @@ "jest-extended": "1.2.0", "jest-raw-loader": "1.0.1", "postcss-less": "6.0.0", - "stylelint": "14.2.0", + "stylelint": "14.3.0", "stylelint-config-standard": "24.0.0", "svgo": "2.8.0", "updates": "13.0.0" @@ -86,20 +86,20 @@ } }, "node_modules/@babel/core": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", - "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", + "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.16.7", + "@babel/generator": "^7.16.8", "@babel/helper-compilation-targets": "^7.16.7", "@babel/helper-module-transforms": "^7.16.7", "@babel/helpers": "^7.16.7", - "@babel/parser": "^7.16.7", + "@babel/parser": "^7.16.12", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7", + "@babel/traverse": "^7.16.10", + "@babel/types": "^7.16.8", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -330,9 +330,9 @@ } }, "node_modules/@babel/highlight": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", - "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", @@ -415,9 +415,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz", - "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==", + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.12.tgz", + "integrity": "sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -614,9 +614,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz", - "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.10.tgz", + "integrity": "sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.16.7", @@ -625,7 +625,7 @@ "@babel/helper-function-name": "^7.16.7", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.16.8", + "@babel/parser": "^7.16.10", "@babel/types": "^7.16.8", "debug": "^4.1.0", "globals": "^11.1.0" @@ -1229,9 +1229,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.2.tgz", - "integrity": "sha512-nQxgB8/Sg+QKhnV8e0WzPpxjIGT3tuJDDzybkDi8ItE/IgTlHo07U0shaIjzhcvQxlq9SDRE42lsJ23uvEgJ2A==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -1307,9 +1307,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.9.tgz", - "integrity": "sha512-5dNBXu/FOER+EXnyah7rn8xlNrfMOQb/qXnw4NQgLkCygKBKhdmF/CA5oXVOKZLBEahw8s2WP9LxIcN/oDDRgQ==" + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.10.tgz", + "integrity": "sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -1543,18 +1543,18 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", - "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", + "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", "peerDependencies": { "webpack": "4.x.x || 5.x.x", "webpack-cli": "4.x.x" } }, "node_modules/@webpack-cli/info": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz", - "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", + "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", "dependencies": { "envinfo": "^7.7.3" }, @@ -1563,9 +1563,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", - "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", + "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", "peerDependencies": { "webpack-cli": "4.x.x" }, @@ -2119,9 +2119,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001300", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz", - "integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==", + "version": "1.0.30001301", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001301.tgz", + "integrity": "sha512-csfD/GpHMqgEL3V3uIgosvh+SVIQvCh43SNu9HRbP1lnxkKm1kjDG4f32PP571JplkLjfS+mg2p1gxR7MYrrIA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/browserslist" @@ -2277,9 +2277,9 @@ } }, "node_modules/codemirror": { - "version": "5.65.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.0.tgz", - "integrity": "sha512-gWEnHKEcz1Hyz7fsQWpK7P0sPI2/kSkRX2tc7DFA6TmZuDN75x/1ejnH/Pn8adYKrLEA1V2ww6L00GudHZbSKw==" + "version": "5.65.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.1.tgz", + "integrity": "sha512-s6aac+DD+4O2u1aBmdxhB7yz2XU7tG3snOyQ05Kxifahz7hoxnfxIRHxiCSEv3TUC38dIVH8G+lZH9UWSfGQxA==" }, "node_modules/codemirror-spell-checker": { "version": "1.1.2", @@ -3435,9 +3435,9 @@ } }, "node_modules/dompurify": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.4.tgz", - "integrity": "sha512-6BVcgOAVFXjI0JTjEvZy901Rghm+7fDQOrNIcxB4+gdhj6Kwp6T9VBhBY/AbagKHJocRkDYGd6wvI+p4/10xtQ==" + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.5.tgz", + "integrity": "sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ==" }, "node_modules/domutils": { "version": "2.8.0", @@ -3495,9 +3495,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.47", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.47.tgz", - "integrity": "sha512-ZHc8i3/cgeCRK/vC7W2htAG6JqUmOUgDNn/f9yY9J8UjfLjwzwOVEt4MWmgJAdvmxyrsR5KIFA/6+kUHGY0eUA==" + "version": "1.4.51", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.51.tgz", + "integrity": "sha512-JNEmcYl3mk1tGQmy0EvL5eik/CKSBuzAyGP0QFdG6LIgxQe3II0BL1m2zKc2MZMf3uGqHWE1TFddJML0RpjSHQ==" }, "node_modules/emittery": { "version": "0.8.1", @@ -3637,38 +3637,38 @@ } }, "node_modules/esbuild": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.11.tgz", - "integrity": "sha512-xZvPtVj6yecnDeFb3KjjCM6i7B5TCAQZT77kkW/CpXTMnd6VLnRPKrUB1XHI1pSq6a4Zcy3BGueQ8VljqjDGCg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.13.tgz", + "integrity": "sha512-FIxvAdj3i2oHA6ex+E67bG7zlSTO+slt8kU2ogHDgGtrQLy2HNChv3PYjiFTYkt8hZbEAniZCXVeHn+FrHt7dA==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" }, "optionalDependencies": { - "esbuild-android-arm64": "0.14.11", - "esbuild-darwin-64": "0.14.11", - "esbuild-darwin-arm64": "0.14.11", - "esbuild-freebsd-64": "0.14.11", - "esbuild-freebsd-arm64": "0.14.11", - "esbuild-linux-32": "0.14.11", - "esbuild-linux-64": "0.14.11", - "esbuild-linux-arm": "0.14.11", - "esbuild-linux-arm64": "0.14.11", - "esbuild-linux-mips64le": "0.14.11", - "esbuild-linux-ppc64le": "0.14.11", - "esbuild-linux-s390x": "0.14.11", - "esbuild-netbsd-64": "0.14.11", - "esbuild-openbsd-64": "0.14.11", - "esbuild-sunos-64": "0.14.11", - "esbuild-windows-32": "0.14.11", - "esbuild-windows-64": "0.14.11", - "esbuild-windows-arm64": "0.14.11" + "esbuild-android-arm64": "0.14.13", + "esbuild-darwin-64": "0.14.13", + "esbuild-darwin-arm64": "0.14.13", + "esbuild-freebsd-64": "0.14.13", + "esbuild-freebsd-arm64": "0.14.13", + "esbuild-linux-32": "0.14.13", + "esbuild-linux-64": "0.14.13", + "esbuild-linux-arm": "0.14.13", + "esbuild-linux-arm64": "0.14.13", + "esbuild-linux-mips64le": "0.14.13", + "esbuild-linux-ppc64le": "0.14.13", + "esbuild-linux-s390x": "0.14.13", + "esbuild-netbsd-64": "0.14.13", + "esbuild-openbsd-64": "0.14.13", + "esbuild-sunos-64": "0.14.13", + "esbuild-windows-32": "0.14.13", + "esbuild-windows-64": "0.14.13", + "esbuild-windows-arm64": "0.14.13" } }, "node_modules/esbuild-android-arm64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.11.tgz", - "integrity": "sha512-6iHjgvMnC/SzDH8TefL+/3lgCjYWwAd1LixYfmz/TBPbDQlxcuSkX0yiQgcJB9k+ibZ54yjVXziIwGdlc+6WNw==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.13.tgz", + "integrity": "sha512-rhtwl+KJ3BzzXkK09N3/YbEF1i5WhriysJEStoeWNBzchx9hlmzyWmDGQQhu56HF78ua3JrVPyLOsdLGvtMvxQ==", "cpu": [ "arm64" ], @@ -3678,9 +3678,9 @@ ] }, "node_modules/esbuild-darwin-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.11.tgz", - "integrity": "sha512-olq84ikh6TiBcrs3FnM4eR5VPPlcJcdW8BnUz/lNoEWYifYQ+Po5DuYV1oz1CTFMw4k6bQIZl8T3yxL+ZT2uvQ==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.13.tgz", + "integrity": "sha512-Fl47xIt5RMu50WIgMU93kwmUUJb+BPuL8R895n/aBNQqavS+KUMpLPoqKGABBV4myfx/fnAD/97X8Gt1C1YW6w==", "cpu": [ "x64" ], @@ -3690,9 +3690,9 @@ ] }, "node_modules/esbuild-darwin-arm64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.11.tgz", - "integrity": "sha512-Jj0ieWLREPBYr/TZJrb2GFH8PVzDqiQWavo1pOFFShrcmHWDBDrlDxPzEZ67NF/Un3t6sNNmeI1TUS/fe1xARg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.13.tgz", + "integrity": "sha512-UttqKRFXsWvuivcyAbFmo54vdkC9Me1ZYQNuoz/uBYDbkb2MgqKYG2+xoVKPBhLvhT0CKM5QGKD81flMH5BE6A==", "cpu": [ "arm64" ], @@ -3702,9 +3702,9 @@ ] }, "node_modules/esbuild-freebsd-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.11.tgz", - "integrity": "sha512-C5sT3/XIztxxz/zwDjPRHyzj/NJFOnakAanXuyfLDwhwupKPd76/PPHHyJx6Po6NI6PomgVp/zi6GRB8PfrOTA==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.13.tgz", + "integrity": "sha512-dlIhPFSp29Yq2TPh7Cm3/4M0uKjlfvOylHVNCRvRNiOvDbBol6/NZ3kLisczms+Yra0rxVapBPN1oMbSMuts9g==", "cpu": [ "x64" ], @@ -3714,9 +3714,9 @@ ] }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.11.tgz", - "integrity": "sha512-y3Llu4wbs0bk4cwjsdAtVOesXb6JkdfZDLKMt+v1U3tOEPBdSu6w8796VTksJgPfqvpX22JmPLClls0h5p+L9w==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.13.tgz", + "integrity": "sha512-bNOHLu7Oq6RwaAMnwPbJ40DVGPl9GlAOnfH/dFZ792f8hFEbopkbtVzo1SU1jjfY3TGLWOgqHNWxPxx1N7Au+g==", "cpu": [ "arm64" ], @@ -3726,9 +3726,9 @@ ] }, "node_modules/esbuild-linux-32": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.11.tgz", - "integrity": "sha512-Cg3nVsxArjyLke9EuwictFF3Sva+UlDTwHIuIyx8qpxRYAOUTmxr2LzYrhHyTcGOleLGXUXYsnUVwKqnKAgkcg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.13.tgz", + "integrity": "sha512-WzXyBx6zx16adGi7wPBvH2lRCBzYMcqnBRrJ8ciLIqYyruGvprZocX1nFWfiexjLcFxIElWnMNPX6LG7ULqyXA==", "cpu": [ "ia32" ], @@ -3738,9 +3738,9 @@ ] }, "node_modules/esbuild-linux-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.11.tgz", - "integrity": "sha512-oeR6dIrrojr8DKVrxtH3xl4eencmjsgI6kPkDCRIIFwv4p+K7ySviM85K66BN01oLjzthpUMvBVfWSJkBLeRbg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.13.tgz", + "integrity": "sha512-P6OFAfcoUvE7g9h/0UKm3qagvTovwqpCF1wbFLWe/BcCY8BS1bR/+SxUjCeKX2BcpIsg4/43ezHDE/ntg/iOpw==", "cpu": [ "x64" ], @@ -3750,9 +3750,9 @@ ] }, "node_modules/esbuild-linux-arm": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.11.tgz", - "integrity": "sha512-vcwskfD9g0tojux/ZaTJptJQU3a7YgTYsptK1y6LQ/rJmw7U5QJvboNawqM98Ca3ToYEucfCRGbl66OTNtp6KQ==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.13.tgz", + "integrity": "sha512-4jmm0UySCg3Wi6FEBS7jpiPb1IyckI5um5kzYRwulHxPzkiokd6cgpcsTakR4/Y84UEicS8LnFAghHhXHZhbFg==", "cpu": [ "arm" ], @@ -3762,9 +3762,9 @@ ] }, "node_modules/esbuild-linux-arm64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.11.tgz", - "integrity": "sha512-+e6ZCgTFQYZlmg2OqLkg1jHLYtkNDksxWDBWNtI4XG4WxuOCUErLqfEt9qWjvzK3XBcCzHImrajkUjO+rRkbMg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.13.tgz", + "integrity": "sha512-k/uIvmkm4mc7vyMvJVwILgGxi2F+FuvLdmESIIWoHrnxEfEekC5AWpI/R6GQ2OMfp8snebSQLs8KL05QPnt1zA==", "cpu": [ "arm64" ], @@ -3774,9 +3774,9 @@ ] }, "node_modules/esbuild-linux-mips64le": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.11.tgz", - "integrity": "sha512-Rrs99L+p54vepmXIb87xTG6ukrQv+CzrM8eoeR+r/OFL2Rg8RlyEtCeshXJ2+Q66MXZOgPJaokXJZb9snq28bw==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.13.tgz", + "integrity": "sha512-vwYtgjQ1TRlUGL88km9wH9TjXsdZyZ/Xht1ASptg5XGRlqGquVjLGH11PfLLunoMdkQ0YTXR68b4l5gRfjVbyg==", "cpu": [ "mips64el" ], @@ -3786,9 +3786,9 @@ ] }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.11.tgz", - "integrity": "sha512-JyzziGAI0D30Vyzt0HDihp4s1IUtJ3ssV2zx9O/c+U/dhUHVP2TmlYjzCfCr2Q6mwXTeloDcLS4qkyvJtYptdQ==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.13.tgz", + "integrity": "sha512-0KqDSIkZaYugtcdpFCd3eQ38Fg6TzhxmOpkhDIKNTwD/W2RoXeiS+Z4y5yQ3oysb/ySDOxWkwNqTdXS4sz2LdQ==", "cpu": [ "ppc64" ], @@ -3798,9 +3798,9 @@ ] }, "node_modules/esbuild-linux-s390x": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.11.tgz", - "integrity": "sha512-DoThrkzunZ1nfRGoDN6REwmo8ZZWHd2ztniPVIR5RMw/Il9wiWEYBahb8jnMzQaSOxBsGp0PbyJeVLTUatnlcw==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.13.tgz", + "integrity": "sha512-bG20i7d0CN97fwPN9LaLe64E2IrI0fPZWEcoiff9hzzsvo/fQCx0YjMbPC2T3gqQ48QZRltdU9hQilTjHk3geQ==", "cpu": [ "s390x" ], @@ -3829,9 +3829,9 @@ } }, "node_modules/esbuild-netbsd-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.11.tgz", - "integrity": "sha512-12luoRQz+6eihKYh1zjrw0CBa2aw3twIiHV/FAfjh2NEBDgJQOY4WCEUEN+Rgon7xmLh4XUxCQjnwrvf8zhACw==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.13.tgz", + "integrity": "sha512-jz96PQb0ltqyqLggPpcRbWxzLvWHvrZBHZQyjcOzKRDqg1fR/R1y10b1Cuv84xoIbdAf+ceNUJkMN21FfR9G2g==", "cpu": [ "x64" ], @@ -3841,9 +3841,9 @@ ] }, "node_modules/esbuild-openbsd-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.11.tgz", - "integrity": "sha512-l18TZDjmvwW6cDeR4fmizNoxndyDHamGOOAenwI4SOJbzlJmwfr0jUgjbaXCUuYVOA964siw+Ix+A+bhALWg8Q==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.13.tgz", + "integrity": "sha512-bp6zSo3kDCXKPM5MmVUg6DEpt+yXDx37iDGzNTn3Kf9xh6d0cdITxUC4Bx6S3Di79GVYubWs+wNjSRVFIJpryw==", "cpu": [ "x64" ], @@ -3853,9 +3853,9 @@ ] }, "node_modules/esbuild-sunos-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.11.tgz", - "integrity": "sha512-bmYzDtwASBB8c+0/HVOAiE9diR7+8zLm/i3kEojUH2z0aIs6x/S4KiTuT5/0VKJ4zk69kXel1cNWlHBMkmavQg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.13.tgz", + "integrity": "sha512-08Fne1T9QHYxUnu55sV9V4i/yECADOaI1zMGET2YUa8SRkib10i80hc89U7U/G02DxpN/KUJMWEGq2wKTn0QFQ==", "cpu": [ "x64" ], @@ -3865,9 +3865,9 @@ ] }, "node_modules/esbuild-windows-32": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.11.tgz", - "integrity": "sha512-J1Ys5hMid8QgdY00OBvIolXgCQn1ARhYtxPnG6ESWNTty3ashtc4+As5nTrsErnv8ZGUcWZe4WzTP/DmEVX1UQ==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.13.tgz", + "integrity": "sha512-MW3BMIi9+fzTyDdljH0ftfT/qlD3t+aVzle1O+zZ2MgHRMQD20JwWgyqoJXhe6uDVyunrAUbcjH3qTIEZN3isg==", "cpu": [ "ia32" ], @@ -3877,9 +3877,9 @@ ] }, "node_modules/esbuild-windows-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.11.tgz", - "integrity": "sha512-h9FmMskMuGeN/9G9+LlHPAoiQk9jlKDUn9yA0MpiGzwLa82E7r1b1u+h2a+InprbSnSLxDq/7p5YGtYVO85Mlg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.13.tgz", + "integrity": "sha512-d7+0N+EOgBKdi/nMxlQ8QA5xHBlpcLtSrYnHsA+Xp4yZk28dYfRw1+embsHf5uN5/1iPvrJwPrcpgDH1xyy4JA==", "cpu": [ "x64" ], @@ -3889,9 +3889,9 @@ ] }, "node_modules/esbuild-windows-arm64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.11.tgz", - "integrity": "sha512-dZp7Krv13KpwKklt9/1vBFBMqxEQIO6ri7Azf8C+ob4zOegpJmha2XY9VVWP/OyQ0OWk6cEeIzMJwInRZrzBUQ==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.13.tgz", + "integrity": "sha512-oX5hmgXk9yNKbb5AxThzRQm/E9kiHyDll7JJeyeT1fuGENTifv33f0INCpjBQ+Ty5ChKc84++ZQTEBwLCA12Kw==", "cpu": [ "arm64" ], @@ -6797,15 +6797,15 @@ } }, "node_modules/mermaid": { - "version": "8.13.9", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.13.9.tgz", - "integrity": "sha512-kMH676xEomSe/gzxMpDx91L+z9L+9iB3lvtPFA8aeOPRNNrfd3ZDvDCGFnuqQaJvPRCxs3Me2JDaVVNOZjojrg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.14.0.tgz", + "integrity": "sha512-ITSHjwVaby1Li738sxhF48sLTxcNyUAoWfoqyztL1f7J6JOLpHOuQPNLBb6lxGPUA0u7xP9IRULgvod0dKu35A==", "dependencies": { "@braintree/sanitize-url": "^3.1.0", "d3": "^7.0.0", "dagre": "^0.8.5", "dagre-d3": "^0.6.4", - "dompurify": "2.3.4", + "dompurify": "2.3.5", "graphlib": "^2.1.8", "khroma": "^1.4.1", "moment-mini": "^2.24.0", @@ -7413,9 +7413,9 @@ } }, "node_modules/pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, "engines": { "node": ">= 6" @@ -7628,9 +7628,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", - "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7973,11 +7973,11 @@ } }, "node_modules/resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dependencies": { - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -8289,9 +8289,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", - "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "engines": { "node": ">=0.10.0" } @@ -8520,9 +8520,9 @@ "dev": true }, "node_modules/stylelint": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.2.0.tgz", - "integrity": "sha512-i0DrmDXFNpDsWiwx6SPRs4/pyw4kvZgqpDGvsTslQMY7hpUl6r33aQvNSn6cnTg2wtZ9rreFElI7XAKpOWi1vQ==", + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.3.0.tgz", + "integrity": "sha512-PZXSwtJe4f4qBPWBwAbHL0M0Qjrv8iHN+cLpUNsffaVMS3YzpDDRI73+2lsqLAYfQEzxRwpll6BDKImREbpHWA==", "dev": true, "dependencies": { "balanced-match": "^2.0.0", @@ -8530,12 +8530,12 @@ "cosmiconfig": "^7.0.1", "debug": "^4.3.3", "execall": "^2.0.0", - "fast-glob": "^3.2.7", + "fast-glob": "^3.2.11", "fastest-levenshtein": "^1.0.12", "file-entry-cache": "^6.0.1", "get-stdin": "^8.0.0", "global-modules": "^2.0.0", - "globby": "^11.0.4", + "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.1.0", "ignore": "^5.2.0", @@ -8549,21 +8549,22 @@ "normalize-path": "^3.0.0", "normalize-selector": "^0.2.0", "picocolors": "^1.0.0", - "postcss": "^8.3.11", + "postcss": "^8.4.5", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.7", - "postcss-value-parser": "^4.1.0", + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "specificity": "^0.4.1", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "style-search": "^0.1.0", + "supports-hyperlinks": "^2.2.0", "svg-tags": "^1.0.0", - "table": "^6.7.5", + "table": "^6.8.0", "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^3.0.3" + "write-file-atomic": "^4.0.0" }, "bin": { "stylelint": "bin/stylelint.js" @@ -8612,6 +8613,41 @@ "node": ">=8" } }, + "node_modules/stylelint/node_modules/typedarray-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", + "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/stylelint/node_modules/write-file-atomic": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.0.tgz", + "integrity": "sha512-JhcWoKffJNF7ivO9yflBhc7tn3wKnokMUfWpBriM9yCXj4ePQnRPcWglBkkg1AHC8nsW/EfxwwhqsLtOy59djA==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, "node_modules/stylis": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", @@ -8686,9 +8722,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.3.tgz", - "integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ==" + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.2.1.tgz", + "integrity": "sha512-ZzUeNKIIMXmKI53iLscAVCpQ7jblYxI2XX5EBaoBr6UBEfxT3L0vlnE+fzPBbHc9g0sgdOMLZGhC5OW++9pqlw==" }, "node_modules/symbol-tree": { "version": "3.2.4", @@ -9166,14 +9202,14 @@ } }, "node_modules/vue-eslint-parser": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.0.1.tgz", - "integrity": "sha512-lhWjDXJhe3UZw2uu3ztX51SJAPGPey1Tff2RK3TyZURwbuI4vximQLzz4nQfCv8CZq4xx7uIiogHMMoSJPr33A==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.2.0.tgz", + "integrity": "sha512-hvl8OVT8imlKk/lQyhkshqwQQChzHETcBd5abiO4ePw7ib7QUZLfW+2TUrJHKUvFOCFRJrDin5KJO9OHzB5bRQ==", "dev": true, "dependencies": { "debug": "^4.3.2", - "eslint-scope": "^6.0.0", - "eslint-visitor-keys": "^3.0.0", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", "espree": "^9.0.0", "esquery": "^1.4.0", "lodash": "^4.17.21", @@ -9189,19 +9225,6 @@ "eslint": ">=6.0.0" } }, - "node_modules/vue-eslint-parser/node_modules/eslint-scope": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", - "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/vue-hot-reload-api": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", @@ -9365,9 +9388,9 @@ } }, "node_modules/webpack": { - "version": "5.66.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.66.0.tgz", - "integrity": "sha512-NJNtGT7IKpGzdW7Iwpn/09OXz9inIkeIQ/ibY6B+MdV1x6+uReqz/5z1L89ezWnpPDWpXF0TY5PCYKQdWVn8Vg==", + "version": "5.67.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.67.0.tgz", + "integrity": "sha512-LjFbfMh89xBDpUMgA1W9Ur6Rn/gnr2Cq1jjHFPo4v6a79/ypznSYbAyPgGhwsxBtMIaEmDD1oJoA7BEYw/Fbrw==", "dependencies": { "@types/eslint-scope": "^3.7.0", "@types/estree": "^0.0.50", @@ -9392,7 +9415,7 @@ "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", "watchpack": "^2.3.1", - "webpack-sources": "^3.2.2" + "webpack-sources": "^3.2.3" }, "bin": { "webpack": "bin/webpack.js" @@ -9411,14 +9434,14 @@ } }, "node_modules/webpack-cli": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz", - "integrity": "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", + "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.0", - "@webpack-cli/info": "^1.4.0", - "@webpack-cli/serve": "^1.6.0", + "@webpack-cli/configtest": "^1.1.1", + "@webpack-cli/info": "^1.4.1", + "@webpack-cli/serve": "^1.6.1", "colorette": "^2.0.14", "commander": "^7.0.0", "execa": "^5.0.0", @@ -9854,20 +9877,20 @@ "dev": true }, "@babel/core": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", - "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", + "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", "dev": true, "requires": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.16.7", + "@babel/generator": "^7.16.8", "@babel/helper-compilation-targets": "^7.16.7", "@babel/helper-module-transforms": "^7.16.7", "@babel/helpers": "^7.16.7", - "@babel/parser": "^7.16.7", + "@babel/parser": "^7.16.12", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7", + "@babel/traverse": "^7.16.10", + "@babel/types": "^7.16.8", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -10040,9 +10063,9 @@ } }, "@babel/highlight": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", - "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", @@ -10109,9 +10132,9 @@ } }, "@babel/parser": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz", - "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==", + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.12.tgz", + "integrity": "sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -10251,9 +10274,9 @@ } }, "@babel/traverse": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz", - "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.10.tgz", + "integrity": "sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw==", "dev": true, "requires": { "@babel/code-frame": "^7.16.7", @@ -10262,7 +10285,7 @@ "@babel/helper-function-name": "^7.16.7", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.16.8", + "@babel/parser": "^7.16.10", "@babel/types": "^7.16.8", "debug": "^4.1.0", "globals": "^11.1.0" @@ -10752,9 +10775,9 @@ } }, "@types/eslint": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.2.tgz", - "integrity": "sha512-nQxgB8/Sg+QKhnV8e0WzPpxjIGT3tuJDDzybkDi8ItE/IgTlHo07U0shaIjzhcvQxlq9SDRE42lsJ23uvEgJ2A==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", "requires": { "@types/estree": "*", "@types/json-schema": "*" @@ -10830,9 +10853,9 @@ "dev": true }, "@types/node": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.9.tgz", - "integrity": "sha512-5dNBXu/FOER+EXnyah7rn8xlNrfMOQb/qXnw4NQgLkCygKBKhdmF/CA5oXVOKZLBEahw8s2WP9LxIcN/oDDRgQ==" + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.10.tgz", + "integrity": "sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -11059,23 +11082,23 @@ } }, "@webpack-cli/configtest": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", - "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", + "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", "requires": {} }, "@webpack-cli/info": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz", - "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", + "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", "requires": { "envinfo": "^7.7.3" } }, "@webpack-cli/serve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", - "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", + "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", "requires": {} }, "@xtuc/ieee754": { @@ -11474,9 +11497,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001300", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz", - "integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==" + "version": "1.0.30001301", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001301.tgz", + "integrity": "sha512-csfD/GpHMqgEL3V3uIgosvh+SVIQvCh43SNu9HRbP1lnxkKm1kjDG4f32PP571JplkLjfS+mg2p1gxR7MYrrIA==" }, "chalk": { "version": "4.1.2", @@ -11594,9 +11617,9 @@ "dev": true }, "codemirror": { - "version": "5.65.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.0.tgz", - "integrity": "sha512-gWEnHKEcz1Hyz7fsQWpK7P0sPI2/kSkRX2tc7DFA6TmZuDN75x/1ejnH/Pn8adYKrLEA1V2ww6L00GudHZbSKw==" + "version": "5.65.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.1.tgz", + "integrity": "sha512-s6aac+DD+4O2u1aBmdxhB7yz2XU7tG3snOyQ05Kxifahz7hoxnfxIRHxiCSEv3TUC38dIVH8G+lZH9UWSfGQxA==" }, "codemirror-spell-checker": { "version": "1.1.2", @@ -12524,9 +12547,9 @@ } }, "dompurify": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.4.tgz", - "integrity": "sha512-6BVcgOAVFXjI0JTjEvZy901Rghm+7fDQOrNIcxB4+gdhj6Kwp6T9VBhBY/AbagKHJocRkDYGd6wvI+p4/10xtQ==" + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.5.tgz", + "integrity": "sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ==" }, "domutils": { "version": "2.8.0", @@ -12577,9 +12600,9 @@ } }, "electron-to-chromium": { - "version": "1.4.47", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.47.tgz", - "integrity": "sha512-ZHc8i3/cgeCRK/vC7W2htAG6JqUmOUgDNn/f9yY9J8UjfLjwzwOVEt4MWmgJAdvmxyrsR5KIFA/6+kUHGY0eUA==" + "version": "1.4.51", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.51.tgz", + "integrity": "sha512-JNEmcYl3mk1tGQmy0EvL5eik/CKSBuzAyGP0QFdG6LIgxQe3II0BL1m2zKc2MZMf3uGqHWE1TFddJML0RpjSHQ==" }, "emittery": { "version": "0.8.1", @@ -12680,100 +12703,100 @@ } }, "esbuild": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.11.tgz", - "integrity": "sha512-xZvPtVj6yecnDeFb3KjjCM6i7B5TCAQZT77kkW/CpXTMnd6VLnRPKrUB1XHI1pSq6a4Zcy3BGueQ8VljqjDGCg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.13.tgz", + "integrity": "sha512-FIxvAdj3i2oHA6ex+E67bG7zlSTO+slt8kU2ogHDgGtrQLy2HNChv3PYjiFTYkt8hZbEAniZCXVeHn+FrHt7dA==", "requires": { - "esbuild-android-arm64": "0.14.11", - "esbuild-darwin-64": "0.14.11", - "esbuild-darwin-arm64": "0.14.11", - "esbuild-freebsd-64": "0.14.11", - "esbuild-freebsd-arm64": "0.14.11", - "esbuild-linux-32": "0.14.11", - "esbuild-linux-64": "0.14.11", - "esbuild-linux-arm": "0.14.11", - "esbuild-linux-arm64": "0.14.11", - "esbuild-linux-mips64le": "0.14.11", - "esbuild-linux-ppc64le": "0.14.11", - "esbuild-linux-s390x": "0.14.11", - "esbuild-netbsd-64": "0.14.11", - "esbuild-openbsd-64": "0.14.11", - "esbuild-sunos-64": "0.14.11", - "esbuild-windows-32": "0.14.11", - "esbuild-windows-64": "0.14.11", - "esbuild-windows-arm64": "0.14.11" + "esbuild-android-arm64": "0.14.13", + "esbuild-darwin-64": "0.14.13", + "esbuild-darwin-arm64": "0.14.13", + "esbuild-freebsd-64": "0.14.13", + "esbuild-freebsd-arm64": "0.14.13", + "esbuild-linux-32": "0.14.13", + "esbuild-linux-64": "0.14.13", + "esbuild-linux-arm": "0.14.13", + "esbuild-linux-arm64": "0.14.13", + "esbuild-linux-mips64le": "0.14.13", + "esbuild-linux-ppc64le": "0.14.13", + "esbuild-linux-s390x": "0.14.13", + "esbuild-netbsd-64": "0.14.13", + "esbuild-openbsd-64": "0.14.13", + "esbuild-sunos-64": "0.14.13", + "esbuild-windows-32": "0.14.13", + "esbuild-windows-64": "0.14.13", + "esbuild-windows-arm64": "0.14.13" } }, "esbuild-android-arm64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.11.tgz", - "integrity": "sha512-6iHjgvMnC/SzDH8TefL+/3lgCjYWwAd1LixYfmz/TBPbDQlxcuSkX0yiQgcJB9k+ibZ54yjVXziIwGdlc+6WNw==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.13.tgz", + "integrity": "sha512-rhtwl+KJ3BzzXkK09N3/YbEF1i5WhriysJEStoeWNBzchx9hlmzyWmDGQQhu56HF78ua3JrVPyLOsdLGvtMvxQ==", "optional": true }, "esbuild-darwin-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.11.tgz", - "integrity": "sha512-olq84ikh6TiBcrs3FnM4eR5VPPlcJcdW8BnUz/lNoEWYifYQ+Po5DuYV1oz1CTFMw4k6bQIZl8T3yxL+ZT2uvQ==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.13.tgz", + "integrity": "sha512-Fl47xIt5RMu50WIgMU93kwmUUJb+BPuL8R895n/aBNQqavS+KUMpLPoqKGABBV4myfx/fnAD/97X8Gt1C1YW6w==", "optional": true }, "esbuild-darwin-arm64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.11.tgz", - "integrity": "sha512-Jj0ieWLREPBYr/TZJrb2GFH8PVzDqiQWavo1pOFFShrcmHWDBDrlDxPzEZ67NF/Un3t6sNNmeI1TUS/fe1xARg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.13.tgz", + "integrity": "sha512-UttqKRFXsWvuivcyAbFmo54vdkC9Me1ZYQNuoz/uBYDbkb2MgqKYG2+xoVKPBhLvhT0CKM5QGKD81flMH5BE6A==", "optional": true }, "esbuild-freebsd-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.11.tgz", - "integrity": "sha512-C5sT3/XIztxxz/zwDjPRHyzj/NJFOnakAanXuyfLDwhwupKPd76/PPHHyJx6Po6NI6PomgVp/zi6GRB8PfrOTA==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.13.tgz", + "integrity": "sha512-dlIhPFSp29Yq2TPh7Cm3/4M0uKjlfvOylHVNCRvRNiOvDbBol6/NZ3kLisczms+Yra0rxVapBPN1oMbSMuts9g==", "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.11.tgz", - "integrity": "sha512-y3Llu4wbs0bk4cwjsdAtVOesXb6JkdfZDLKMt+v1U3tOEPBdSu6w8796VTksJgPfqvpX22JmPLClls0h5p+L9w==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.13.tgz", + "integrity": "sha512-bNOHLu7Oq6RwaAMnwPbJ40DVGPl9GlAOnfH/dFZ792f8hFEbopkbtVzo1SU1jjfY3TGLWOgqHNWxPxx1N7Au+g==", "optional": true }, "esbuild-linux-32": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.11.tgz", - "integrity": "sha512-Cg3nVsxArjyLke9EuwictFF3Sva+UlDTwHIuIyx8qpxRYAOUTmxr2LzYrhHyTcGOleLGXUXYsnUVwKqnKAgkcg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.13.tgz", + "integrity": "sha512-WzXyBx6zx16adGi7wPBvH2lRCBzYMcqnBRrJ8ciLIqYyruGvprZocX1nFWfiexjLcFxIElWnMNPX6LG7ULqyXA==", "optional": true }, "esbuild-linux-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.11.tgz", - "integrity": "sha512-oeR6dIrrojr8DKVrxtH3xl4eencmjsgI6kPkDCRIIFwv4p+K7ySviM85K66BN01oLjzthpUMvBVfWSJkBLeRbg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.13.tgz", + "integrity": "sha512-P6OFAfcoUvE7g9h/0UKm3qagvTovwqpCF1wbFLWe/BcCY8BS1bR/+SxUjCeKX2BcpIsg4/43ezHDE/ntg/iOpw==", "optional": true }, "esbuild-linux-arm": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.11.tgz", - "integrity": "sha512-vcwskfD9g0tojux/ZaTJptJQU3a7YgTYsptK1y6LQ/rJmw7U5QJvboNawqM98Ca3ToYEucfCRGbl66OTNtp6KQ==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.13.tgz", + "integrity": "sha512-4jmm0UySCg3Wi6FEBS7jpiPb1IyckI5um5kzYRwulHxPzkiokd6cgpcsTakR4/Y84UEicS8LnFAghHhXHZhbFg==", "optional": true }, "esbuild-linux-arm64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.11.tgz", - "integrity": "sha512-+e6ZCgTFQYZlmg2OqLkg1jHLYtkNDksxWDBWNtI4XG4WxuOCUErLqfEt9qWjvzK3XBcCzHImrajkUjO+rRkbMg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.13.tgz", + "integrity": "sha512-k/uIvmkm4mc7vyMvJVwILgGxi2F+FuvLdmESIIWoHrnxEfEekC5AWpI/R6GQ2OMfp8snebSQLs8KL05QPnt1zA==", "optional": true }, "esbuild-linux-mips64le": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.11.tgz", - "integrity": "sha512-Rrs99L+p54vepmXIb87xTG6ukrQv+CzrM8eoeR+r/OFL2Rg8RlyEtCeshXJ2+Q66MXZOgPJaokXJZb9snq28bw==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.13.tgz", + "integrity": "sha512-vwYtgjQ1TRlUGL88km9wH9TjXsdZyZ/Xht1ASptg5XGRlqGquVjLGH11PfLLunoMdkQ0YTXR68b4l5gRfjVbyg==", "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.11.tgz", - "integrity": "sha512-JyzziGAI0D30Vyzt0HDihp4s1IUtJ3ssV2zx9O/c+U/dhUHVP2TmlYjzCfCr2Q6mwXTeloDcLS4qkyvJtYptdQ==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.13.tgz", + "integrity": "sha512-0KqDSIkZaYugtcdpFCd3eQ38Fg6TzhxmOpkhDIKNTwD/W2RoXeiS+Z4y5yQ3oysb/ySDOxWkwNqTdXS4sz2LdQ==", "optional": true }, "esbuild-linux-s390x": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.11.tgz", - "integrity": "sha512-DoThrkzunZ1nfRGoDN6REwmo8ZZWHd2ztniPVIR5RMw/Il9wiWEYBahb8jnMzQaSOxBsGp0PbyJeVLTUatnlcw==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.13.tgz", + "integrity": "sha512-bG20i7d0CN97fwPN9LaLe64E2IrI0fPZWEcoiff9hzzsvo/fQCx0YjMbPC2T3gqQ48QZRltdU9hQilTjHk3geQ==", "optional": true }, "esbuild-loader": { @@ -12790,39 +12813,39 @@ } }, "esbuild-netbsd-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.11.tgz", - "integrity": "sha512-12luoRQz+6eihKYh1zjrw0CBa2aw3twIiHV/FAfjh2NEBDgJQOY4WCEUEN+Rgon7xmLh4XUxCQjnwrvf8zhACw==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.13.tgz", + "integrity": "sha512-jz96PQb0ltqyqLggPpcRbWxzLvWHvrZBHZQyjcOzKRDqg1fR/R1y10b1Cuv84xoIbdAf+ceNUJkMN21FfR9G2g==", "optional": true }, "esbuild-openbsd-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.11.tgz", - "integrity": "sha512-l18TZDjmvwW6cDeR4fmizNoxndyDHamGOOAenwI4SOJbzlJmwfr0jUgjbaXCUuYVOA964siw+Ix+A+bhALWg8Q==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.13.tgz", + "integrity": "sha512-bp6zSo3kDCXKPM5MmVUg6DEpt+yXDx37iDGzNTn3Kf9xh6d0cdITxUC4Bx6S3Di79GVYubWs+wNjSRVFIJpryw==", "optional": true }, "esbuild-sunos-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.11.tgz", - "integrity": "sha512-bmYzDtwASBB8c+0/HVOAiE9diR7+8zLm/i3kEojUH2z0aIs6x/S4KiTuT5/0VKJ4zk69kXel1cNWlHBMkmavQg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.13.tgz", + "integrity": "sha512-08Fne1T9QHYxUnu55sV9V4i/yECADOaI1zMGET2YUa8SRkib10i80hc89U7U/G02DxpN/KUJMWEGq2wKTn0QFQ==", "optional": true }, "esbuild-windows-32": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.11.tgz", - "integrity": "sha512-J1Ys5hMid8QgdY00OBvIolXgCQn1ARhYtxPnG6ESWNTty3ashtc4+As5nTrsErnv8ZGUcWZe4WzTP/DmEVX1UQ==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.13.tgz", + "integrity": "sha512-MW3BMIi9+fzTyDdljH0ftfT/qlD3t+aVzle1O+zZ2MgHRMQD20JwWgyqoJXhe6uDVyunrAUbcjH3qTIEZN3isg==", "optional": true }, "esbuild-windows-64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.11.tgz", - "integrity": "sha512-h9FmMskMuGeN/9G9+LlHPAoiQk9jlKDUn9yA0MpiGzwLa82E7r1b1u+h2a+InprbSnSLxDq/7p5YGtYVO85Mlg==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.13.tgz", + "integrity": "sha512-d7+0N+EOgBKdi/nMxlQ8QA5xHBlpcLtSrYnHsA+Xp4yZk28dYfRw1+embsHf5uN5/1iPvrJwPrcpgDH1xyy4JA==", "optional": true }, "esbuild-windows-arm64": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.11.tgz", - "integrity": "sha512-dZp7Krv13KpwKklt9/1vBFBMqxEQIO6ri7Azf8C+ob4zOegpJmha2XY9VVWP/OyQ0OWk6cEeIzMJwInRZrzBUQ==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.13.tgz", + "integrity": "sha512-oX5hmgXk9yNKbb5AxThzRQm/E9kiHyDll7JJeyeT1fuGENTifv33f0INCpjBQ+Ty5ChKc84++ZQTEBwLCA12Kw==", "optional": true }, "escalade": { @@ -15010,15 +15033,15 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "mermaid": { - "version": "8.13.9", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.13.9.tgz", - "integrity": "sha512-kMH676xEomSe/gzxMpDx91L+z9L+9iB3lvtPFA8aeOPRNNrfd3ZDvDCGFnuqQaJvPRCxs3Me2JDaVVNOZjojrg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.14.0.tgz", + "integrity": "sha512-ITSHjwVaby1Li738sxhF48sLTxcNyUAoWfoqyztL1f7J6JOLpHOuQPNLBb6lxGPUA0u7xP9IRULgvod0dKu35A==", "requires": { "@braintree/sanitize-url": "^3.1.0", "d3": "^7.0.0", "dagre": "^0.8.5", "dagre-d3": "^0.6.4", - "dompurify": "2.3.4", + "dompurify": "2.3.5", "graphlib": "^2.1.8", "khroma": "^1.4.1", "moment-mini": "^2.24.0", @@ -15466,9 +15489,9 @@ "optional": true }, "pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true }, "pkg-dir": { @@ -15604,9 +15627,9 @@ "requires": {} }, "postcss-selector-parser": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", - "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -15848,11 +15871,11 @@ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, "resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "requires": { - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -16079,9 +16102,9 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", - "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" }, "source-map-support": { "version": "0.5.21", @@ -16270,9 +16293,9 @@ "dev": true }, "stylelint": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.2.0.tgz", - "integrity": "sha512-i0DrmDXFNpDsWiwx6SPRs4/pyw4kvZgqpDGvsTslQMY7hpUl6r33aQvNSn6cnTg2wtZ9rreFElI7XAKpOWi1vQ==", + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.3.0.tgz", + "integrity": "sha512-PZXSwtJe4f4qBPWBwAbHL0M0Qjrv8iHN+cLpUNsffaVMS3YzpDDRI73+2lsqLAYfQEzxRwpll6BDKImREbpHWA==", "dev": true, "requires": { "balanced-match": "^2.0.0", @@ -16280,12 +16303,12 @@ "cosmiconfig": "^7.0.1", "debug": "^4.3.3", "execall": "^2.0.0", - "fast-glob": "^3.2.7", + "fast-glob": "^3.2.11", "fastest-levenshtein": "^1.0.12", "file-entry-cache": "^6.0.1", "get-stdin": "^8.0.0", "global-modules": "^2.0.0", - "globby": "^11.0.4", + "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.1.0", "ignore": "^5.2.0", @@ -16299,21 +16322,22 @@ "normalize-path": "^3.0.0", "normalize-selector": "^0.2.0", "picocolors": "^1.0.0", - "postcss": "^8.3.11", + "postcss": "^8.4.5", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.7", - "postcss-value-parser": "^4.1.0", + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "specificity": "^0.4.1", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "style-search": "^0.1.0", + "supports-hyperlinks": "^2.2.0", "svg-tags": "^1.0.0", - "table": "^6.7.5", + "table": "^6.8.0", "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^3.0.3" + "write-file-atomic": "^4.0.0" }, "dependencies": { "balanced-match": { @@ -16327,6 +16351,24 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true + }, + "typedarray-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", + "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==", + "dev": true + }, + "write-file-atomic": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.0.tgz", + "integrity": "sha512-JhcWoKffJNF7ivO9yflBhc7tn3wKnokMUfWpBriM9yCXj4ePQnRPcWglBkkg1AHC8nsW/EfxwwhqsLtOy59djA==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^4.0.0" + } } } }, @@ -16402,9 +16444,9 @@ } }, "swagger-ui-dist": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.3.tgz", - "integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ==" + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.2.1.tgz", + "integrity": "sha512-ZzUeNKIIMXmKI53iLscAVCpQ7jblYxI2XX5EBaoBr6UBEfxT3L0vlnE+fzPBbHc9g0sgdOMLZGhC5OW++9pqlw==" }, "symbol-tree": { "version": "3.2.4", @@ -16774,30 +16816,18 @@ } }, "vue-eslint-parser": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.0.1.tgz", - "integrity": "sha512-lhWjDXJhe3UZw2uu3ztX51SJAPGPey1Tff2RK3TyZURwbuI4vximQLzz4nQfCv8CZq4xx7uIiogHMMoSJPr33A==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.2.0.tgz", + "integrity": "sha512-hvl8OVT8imlKk/lQyhkshqwQQChzHETcBd5abiO4ePw7ib7QUZLfW+2TUrJHKUvFOCFRJrDin5KJO9OHzB5bRQ==", "dev": true, "requires": { "debug": "^4.3.2", - "eslint-scope": "^6.0.0", - "eslint-visitor-keys": "^3.0.0", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", "espree": "^9.0.0", "esquery": "^1.4.0", "lodash": "^4.17.21", "semver": "^7.3.5" - }, - "dependencies": { - "eslint-scope": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", - "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - } } }, "vue-hot-reload-api": { @@ -16931,9 +16961,9 @@ "dev": true }, "webpack": { - "version": "5.66.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.66.0.tgz", - "integrity": "sha512-NJNtGT7IKpGzdW7Iwpn/09OXz9inIkeIQ/ibY6B+MdV1x6+uReqz/5z1L89ezWnpPDWpXF0TY5PCYKQdWVn8Vg==", + "version": "5.67.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.67.0.tgz", + "integrity": "sha512-LjFbfMh89xBDpUMgA1W9Ur6Rn/gnr2Cq1jjHFPo4v6a79/ypznSYbAyPgGhwsxBtMIaEmDD1oJoA7BEYw/Fbrw==", "requires": { "@types/eslint-scope": "^3.7.0", "@types/estree": "^0.0.50", @@ -16958,7 +16988,7 @@ "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", "watchpack": "^2.3.1", - "webpack-sources": "^3.2.2" + "webpack-sources": "^3.2.3" }, "dependencies": { "eslint-scope": { @@ -16993,14 +17023,14 @@ } }, "webpack-cli": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz", - "integrity": "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", + "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.0", - "@webpack-cli/info": "^1.4.0", - "@webpack-cli/serve": "^1.6.0", + "@webpack-cli/configtest": "^1.1.1", + "@webpack-cli/info": "^1.4.1", + "@webpack-cli/serve": "^1.6.1", "colorette": "^2.0.14", "commander": "^7.0.0", "execa": "^5.0.0", diff --git a/package.json b/package.json index 6983b46df0..369f9a5d4e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "@claviska/jquery-minicolors": "2.3.6", "@primer/octicons": "16.2.0", "add-asset-webpack-plugin": "2.0.1", - "codemirror": "5.65.0", + "codemirror": "5.65.1", "css-loader": "6.5.1", "dropzone": "6.0.0-beta.2", "easymde": "2.16.1", @@ -23,13 +23,13 @@ "less": "4.1.2", "less-loader": "10.2.0", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "8.13.9", + "mermaid": "8.14.0", "mini-css-extract-plugin": "2.5.2", "monaco-editor": "0.31.1", "monaco-editor-webpack-plugin": "7.0.1", "pretty-ms": "7.0.1", "sortablejs": "1.14.0", - "swagger-ui-dist": "4.1.3", + "swagger-ui-dist": "4.2.1", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", "vue": "2.6.14", @@ -37,8 +37,8 @@ "vue-calendar-heatmap": "0.8.4", "vue-loader": "15.9.8", "vue-template-compiler": "2.6.14", - "webpack": "5.66.0", - "webpack-cli": "4.9.1", + "webpack": "5.67.0", + "webpack-cli": "4.9.2", "workbox-routing": "6.4.2", "workbox-strategies": "6.4.2", "worker-loader": "3.0.8", @@ -55,7 +55,7 @@ "jest-extended": "1.2.0", "jest-raw-loader": "1.0.1", "postcss-less": "6.0.0", - "stylelint": "14.2.0", + "stylelint": "14.3.0", "stylelint-config-standard": "24.0.0", "svgo": "2.8.0", "updates": "13.0.0" diff --git a/routers/api/v1/admin/adopt.go b/routers/api/v1/admin/adopt.go index 1c0e237cdb..db1754c8d0 100644 --- a/routers/api/v1/admin/adopt.go +++ b/routers/api/v1/admin/adopt.go @@ -43,9 +43,13 @@ func ListUnadoptedRepositories(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" listOptions := utils.GetListOptions(ctx) + if listOptions.Page == 0 { + listOptions.Page = 1 + } repoNames, count, err := repo_service.ListUnadoptedRepositories(ctx.FormString("query"), &listOptions) if err != nil { ctx.InternalServerError(err) + return } ctx.SetTotalCountHeader(int64(count)) diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index e95ab33d77..7262073bbd 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -22,6 +22,7 @@ import ( "code.gitea.io/gitea/modules/password" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/utils" @@ -81,7 +82,6 @@ func CreateUser(ctx *context.APIContext) { Email: form.Email, Passwd: form.Password, MustChangePassword: true, - IsActive: true, LoginType: auth.Plain, } if form.MustChangePassword != nil { @@ -107,11 +107,17 @@ func CreateUser(ctx *context.APIContext) { return } - var overwriteDefault *user_model.CreateUserOverwriteOptions + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsActive: util.OptionalBoolTrue, + } + + if form.Restricted != nil { + overwriteDefault.IsRestricted = util.OptionalBoolOf(*form.Restricted) + } + if form.Visibility != "" { - overwriteDefault = &user_model.CreateUserOverwriteOptions{ - Visibility: api.VisibilityModes[form.Visibility], - } + visibility := api.VisibilityModes[form.Visibility] + overwriteDefault.Visibility = &visibility } if err := user_model.CreateUser(u, overwriteDefault); err != nil { @@ -119,6 +125,7 @@ func CreateUser(ctx *context.APIContext) { user_model.IsErrEmailAlreadyUsed(err) || db.IsErrNameReserved(err) || db.IsErrNameCharsNotAllowed(err) || + user_model.IsErrEmailCharIsNotSupported(err) || user_model.IsErrEmailInvalid(err) || db.IsErrNamePatternNotAllowed(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -265,7 +272,9 @@ func EditUser(ctx *context.APIContext) { } if err := user_model.UpdateUser(u, emailChanged); err != nil { - if user_model.IsErrEmailAlreadyUsed(err) || user_model.IsErrEmailInvalid(err) { + if user_model.IsErrEmailAlreadyUsed(err) || + user_model.IsErrEmailCharIsNotSupported(err) || + user_model.IsErrEmailInvalid(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) } else { ctx.Error(http.StatusInternalServerError, "UpdateUser", err) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 7a2347650a..d06adeed0f 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -954,7 +954,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route { }, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(false)) m.Group("/statuses", func() { m.Combo("/{sha}").Get(repo.GetCommitStatuses). - Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus) + Post(reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateStatusOption{}), repo.NewCommitStatus) }, reqRepoReader(unit.TypeCode)) m.Group("/commits", func() { m.Get("", repo.GetAllCommits) diff --git a/routers/api/v1/misc/markdown_test.go b/routers/api/v1/misc/markdown_test.go index dc6762c4cf..6248e11754 100644 --- a/routers/api/v1/misc/markdown_test.go +++ b/routers/api/v1/misc/markdown_test.go @@ -35,6 +35,8 @@ func createContext(req *http.Request) (*context.Context, *httptest.ResponseRecor Render: rnd, Data: make(map[string]interface{}), } + defer c.Close() + return c, resp } diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go index 8bf5d37116..936647e12b 100644 --- a/routers/api/v1/notify/repo.go +++ b/routers/api/v1/notify/repo.go @@ -121,7 +121,7 @@ func ListRepoNotifications(ctx *context.APIContext) { return } err = nl.LoadAttributes() - if err != nil && !models.IsErrCommentNotExist(err) { + if err != nil { ctx.InternalServerError(err) return } @@ -214,7 +214,7 @@ func ReadRepoNotifications(ctx *context.APIContext) { targetStatus = models.NotificationStatusRead } - changed := make([]*structs.NotificationThread, len(nl)) + changed := make([]*structs.NotificationThread, 0, len(nl)) for _, n := range nl { notif, err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus) diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index cc7a63af33..62e6c0a6b4 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -47,7 +47,7 @@ func ListTeams(ctx *context.APIContext) { // "200": // "$ref": "#/responses/TeamList" - teams, count, err := models.SearchTeam(&models.SearchTeamOptions{ + teams, count, err := models.SearchOrgTeams(&models.SearchOrgTeamOptions{ ListOptions: utils.GetListOptions(ctx), OrgID: ctx.Org.Organization.ID, }) @@ -90,7 +90,7 @@ func ListUserTeams(ctx *context.APIContext) { // "200": // "$ref": "#/responses/TeamList" - teams, count, err := models.SearchTeam(&models.SearchTeamOptions{ + teams, count, err := models.GetUserTeams(&models.GetUserTeamOptions{ ListOptions: utils.GetListOptions(ctx), UserID: ctx.User.ID, }) @@ -533,7 +533,7 @@ func GetTeamRepos(ctx *context.APIContext) { // "$ref": "#/responses/RepositoryList" team := ctx.Org.Team - if err := team.GetRepositories(&models.SearchTeamOptions{ + if err := team.GetRepositories(&models.SearchOrgTeamOptions{ ListOptions: utils.GetListOptions(ctx), }); err != nil { ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) @@ -707,15 +707,14 @@ func SearchTeam(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - opts := &models.SearchTeamOptions{ - UserID: ctx.User.ID, + opts := &models.SearchOrgTeamOptions{ Keyword: ctx.FormTrim("q"), OrgID: ctx.Org.Organization.ID, IncludeDesc: ctx.FormString("include_desc") == "" || ctx.FormBool("include_desc"), ListOptions: listOptions, } - teams, maxResults, err := models.SearchTeam(opts) + teams, maxResults, err := models.SearchOrgTeams(opts) if err != nil { log.Error("SearchTeam failed: %v", err) ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 56266b406a..2e4dbf0e4c 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -177,23 +177,18 @@ func CreateBranch(ctx *context.APIContext) { } err := repo_service.CreateNewBranch(ctx.User, ctx.Repo.Repository, opt.OldBranchName, opt.BranchName) - if err != nil { if models.IsErrBranchDoesNotExist(err) { ctx.Error(http.StatusNotFound, "", "The old branch does not exist") } if models.IsErrTagAlreadyExists(err) { ctx.Error(http.StatusConflict, "", "The branch with the same tag already exists.") - } else if models.IsErrBranchAlreadyExists(err) || git.IsErrPushOutOfDate(err) { ctx.Error(http.StatusConflict, "", "The branch already exists.") - } else if models.IsErrBranchNameConflict(err) { ctx.Error(http.StatusConflict, "", "The branch with the same name already exists.") - } else { ctx.Error(http.StatusInternalServerError, "CreateRepoBranch", err) - } return } @@ -263,10 +258,15 @@ func ListBranches(ctx *context.APIContext) { return } - apiBranches := make([]*api.Branch, len(branches)) + apiBranches := make([]*api.Branch, 0, len(branches)) for i := range branches { c, err := branches[i].GetCommit() if err != nil { + // Skip if this branch doesn't exist anymore. + if git.IsErrNotExist(err) { + totalNumOfBranches-- + continue + } ctx.Error(http.StatusInternalServerError, "GetCommit", err) return } @@ -275,11 +275,12 @@ func ListBranches(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err) return } - apiBranches[i], err = convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.User, ctx.Repo.IsAdmin()) + apiBranch, err := convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.User, ctx.Repo.IsAdmin()) if err != nil { ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err) return } + apiBranches = append(apiBranches, apiBranch) } ctx.SetLinkHeader(totalNumOfBranches, listOptions.PageSize) @@ -532,7 +533,6 @@ func CreateBranchProtection(ctx *context.APIContext) { } ctx.JSON(http.StatusCreated, convert.ToBranchProtection(bp)) - } // EditBranchProtection edits a branch protection for a repo diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 5137c7246e..b5b1659c93 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -173,6 +173,7 @@ func SearchIssues(ctx *context.APIContext) { opts.TeamID = team.ID } + repoCond := models.SearchRepositoryCondition(opts) repoIDs, _, err := models.SearchRepositoryIDs(opts) if err != nil { ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err) @@ -233,7 +234,7 @@ func SearchIssues(ctx *context.APIContext) { Page: ctx.FormInt("page"), PageSize: limit, }, - RepoIDs: repoIDs, + RepoCond: repoCond, IsClosed: isClosed, IssueIDs: issueIDs, IncludedLabelNames: includedLabelNames, @@ -245,18 +246,23 @@ func SearchIssues(ctx *context.APIContext) { UpdatedAfterUnix: since, } + ctxUserID := int64(0) + if ctx.IsSigned { + ctxUserID = ctx.User.ID + } + // Filter for: Created by User, Assigned to User, Mentioning User, Review of User Requested if ctx.FormBool("created") { - issuesOpt.PosterID = ctx.User.ID + issuesOpt.PosterID = ctxUserID } if ctx.FormBool("assigned") { - issuesOpt.AssigneeID = ctx.User.ID + issuesOpt.AssigneeID = ctxUserID } if ctx.FormBool("mentioned") { - issuesOpt.MentionedID = ctx.User.ID + issuesOpt.MentionedID = ctxUserID } if ctx.FormBool("review_requested") { - issuesOpt.ReviewRequestedID = ctx.User.ID + issuesOpt.ReviewRequestedID = ctxUserID } if issues, err = models.Issues(issuesOpt); err != nil { @@ -455,7 +461,7 @@ func ListIssues(ctx *context.APIContext) { if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 { issuesOpt := &models.IssuesOptions{ ListOptions: listOptions, - RepoIDs: []int64{ctx.Repo.Repository.ID}, + RepoID: ctx.Repo.Repository.ID, IsClosed: isClosed, IssueIDs: issueIDs, LabelIDs: labelIDs, @@ -599,7 +605,7 @@ func CreateIssue(ctx *context.APIContext) { DeadlineUnix: deadlineUnix, } - var assigneeIDs = make([]int64, 0) + assigneeIDs := make([]int64, 0) var err error if ctx.Repo.CanWrite(unit.TypeIssues) { issue.MilestoneID = form.Milestone diff --git a/routers/api/v1/repo/key.go b/routers/api/v1/repo/key.go index 669cc7c51c..4ec825472a 100644 --- a/routers/api/v1/repo/key.go +++ b/routers/api/v1/repo/key.go @@ -144,7 +144,7 @@ func GetDeployKey(ctx *context.APIContext) { // "200": // "$ref": "#/responses/DeployKey" - key, err := asymkey_model.GetDeployKeyByID(db.DefaultContext, ctx.ParamsInt64(":id")) + key, err := asymkey_model.GetDeployKeyByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if asymkey_model.IsErrDeployKeyNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index 8a6f421c87..44e188abc2 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -203,7 +203,7 @@ func Migrate(ctx *context.APIContext) { } }() - if _, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), ctx.User, repoOwner.Name, opts, nil); err != nil { + if repo, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), ctx.User, repoOwner.Name, opts, nil); err != nil { handleMigrateError(ctx, repoOwner, remoteAddr, err) return } diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 158abd4651..06641b3f84 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -95,7 +95,6 @@ func ListPullRequests(ctx *context.APIContext) { Labels: ctx.FormStrings("labels"), MilestoneID: ctx.FormInt64("milestone"), }) - if err != nil { ctx.Error(http.StatusInternalServerError, "PullRequests", err) return @@ -724,13 +723,12 @@ func MergePullRequest(ctx *context.APIContext) { return } - if err = pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepo(); err != nil { ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) return } - err = pr.LoadIssue() - if err != nil { + if err := pr.LoadIssue(); err != nil { ctx.Error(http.StatusInternalServerError, "LoadIssue", err) return } @@ -744,29 +742,33 @@ func MergePullRequest(ctx *context.APIContext) { } } - if pr.Issue.IsClosed { - ctx.NotFound() - return - } + manuallMerge := repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged + force := form.ForceMerge != nil && *form.ForceMerge - allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.Repo.Permission, ctx.User) - if err != nil { - ctx.Error(http.StatusInternalServerError, "IsUSerAllowedToMerge", err) - return - } - if !allowedMerge { - ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR") - return - } - - if pr.HasMerged { - ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "") + if err := pull_service.CheckPullMergable(ctx, ctx.User, &ctx.Repo.Permission, pr, manuallMerge, force); err != nil { + if errors.Is(err, pull_service.ErrIsClosed) { + ctx.NotFound() + } else if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) { + ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR") + } else if errors.Is(err, pull_service.ErrHasMerged) { + ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "") + } else if errors.Is(err, pull_service.ErrIsWorkInProgress) { + ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged") + } else if errors.Is(err, pull_service.ErrNotMergableState) { + ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later") + } else if models.IsErrNotAllowedToMerge(err) { + ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err) + } else if asymkey_service.IsErrWontSign(err) { + ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err) + } else { + ctx.InternalServerError(err) + } return } // handle manually-merged mark - if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged { - if err = pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil { + if manuallMerge { + if err := pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil { if models.IsErrInvalidMergeStyle(err) { ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do))) return @@ -782,63 +784,13 @@ func MergePullRequest(ctx *context.APIContext) { return } - if !pr.CanAutoMerge() { - ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later") + // set defaults to propagate needed fields + if err := form.SetDefaults(pr); err != nil { + ctx.ServerError("SetDefaults", fmt.Errorf("SetDefaults: %v", err)) return } - if pr.IsWorkInProgress() { - ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged") - return - } - - if err := pull_service.CheckPRReadyToMerge(pr, false); err != nil { - if !models.IsErrNotAllowedToMerge(err) { - ctx.Error(http.StatusInternalServerError, "CheckPRReadyToMerge", err) - return - } - if form.ForceMerge != nil && *form.ForceMerge { - if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.User); err != nil { - ctx.Error(http.StatusInternalServerError, "IsUserRepoAdmin", err) - return - } else if !isRepoAdmin { - ctx.Error(http.StatusMethodNotAllowed, "Merge", "Only repository admin can merge if not all checks are ok (force merge)") - } - } else { - ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err) - return - } - } - - if _, err := pull_service.IsSignedIfRequired(pr, ctx.User); err != nil { - if !asymkey_service.IsErrWontSign(err) { - ctx.Error(http.StatusInternalServerError, "IsSignedIfRequired", err) - return - } - ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err) - return - } - - if len(form.Do) == 0 { - form.Do = string(repo_model.MergeStyleMerge) - } - - message := strings.TrimSpace(form.MergeTitleField) - if len(message) == 0 { - if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleMerge { - message = pr.GetDefaultMergeMessage() - } - if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleSquash { - message = pr.GetDefaultSquashMessage() - } - } - - form.MergeMessageField = strings.TrimSpace(form.MergeMessageField) - if len(form.MergeMessageField) > 0 { - message += "\n\n" + form.MergeMessageField - } - - if err := pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message); err != nil { + if err := pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, form.MergeTitleField); err != nil { if models.IsErrInvalidMergeStyle(err) { ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do))) return diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index ec5f045647..2d8550bb5f 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -883,7 +883,7 @@ func dismissReview(ctx *context.APIContext, msg string, isDismiss bool) { return } - _, err := pull_service.DismissReview(review.ID, msg, ctx.User, isDismiss) + _, err := pull_service.DismissReview(review.ID, ctx.Repo.Repository.ID, msg, ctx.User, isDismiss) if err != nil { ctx.Error(http.StatusInternalServerError, "pull_service.DismissReview", err) return diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index 299eaddbc8..da9f0f7a55 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -344,6 +344,8 @@ func DeleteRelease(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/notFound" + // "405": + // "$ref": "#/responses/empty" id := ctx.ParamsInt64(":id") rel, err := models.GetReleaseByID(id) @@ -357,6 +359,10 @@ func DeleteRelease(ctx *context.APIContext) { return } if err := releaseservice.DeleteReleaseByID(id, ctx.User, false); err != nil { + if models.IsErrProtectedTagName(err) { + ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag") + return + } ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err) return } diff --git a/routers/api/v1/repo/release_tags.go b/routers/api/v1/repo/release_tags.go index 4b853d44bb..8acbb619f7 100644 --- a/routers/api/v1/repo/release_tags.go +++ b/routers/api/v1/repo/release_tags.go @@ -92,6 +92,8 @@ func DeleteReleaseByTag(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/notFound" + // "405": + // "$ref": "#/responses/empty" tag := ctx.Params(":tag") @@ -111,7 +113,12 @@ func DeleteReleaseByTag(ctx *context.APIContext) { } if err = releaseservice.DeleteReleaseByID(release.ID, ctx.User, false); err != nil { + if models.IsErrProtectedTagName(err) { + ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag") + return + } ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err) + return } ctx.Status(http.StatusNoContent) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 340ba0f6d5..851505fe4a 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -160,7 +160,7 @@ func Search(ctx *context.APIContext) { opts.Collaborate = util.OptionalBoolFalse } - var mode = ctx.FormString("mode") + mode := ctx.FormString("mode") switch mode { case "source": opts.Fork = util.OptionalBoolFalse @@ -186,9 +186,9 @@ func Search(ctx *context.APIContext) { opts.IsPrivate = util.OptionalBoolOf(ctx.FormBool("is_private")) } - var sortMode = ctx.FormString("sort") + sortMode := ctx.FormString("sort") if len(sortMode) > 0 { - var sortOrder = ctx.FormString("order") + sortOrder := ctx.FormString("order") if len(sortOrder) == 0 { sortOrder = "asc" } @@ -264,7 +264,8 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre if repo_model.IsErrRepoAlreadyExist(err) { ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.") } else if db.IsErrNameReserved(err) || - db.IsErrNamePatternNotAllowed(err) { + db.IsErrNamePatternNotAllowed(err) || + models.IsErrIssueLabelTemplateLoad(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) } else { ctx.Error(http.StatusInternalServerError, "CreateRepository", err) @@ -624,7 +625,7 @@ func Edit(ctx *context.APIContext) { } if opts.MirrorInterval != nil { - if err := updateMirrorInterval(ctx, opts); err != nil { + if err := updateMirror(ctx, opts); err != nil { return } } @@ -949,37 +950,67 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e return nil } -// updateMirrorInterval updates the repo's mirror Interval -func updateMirrorInterval(ctx *context.APIContext, opts api.EditRepoOption) error { +// updateMirror updates a repo's mirror Interval and EnablePrune +func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error { repo := ctx.Repo.Repository + // only update mirror if interval or enable prune are provided + if opts.MirrorInterval == nil && opts.EnablePrune == nil { + return nil + } + + // these values only make sense if the repo is a mirror + if !repo.IsMirror { + err := fmt.Errorf("repo is not a mirror, can not change mirror interval") + ctx.Error(http.StatusUnprocessableEntity, err.Error(), err) + return err + } + + // get the mirror from the repo + mirror, err := repo_model.GetMirrorByRepoID(repo.ID) + if err != nil { + log.Error("Failed to get mirror: %s", err) + ctx.Error(http.StatusInternalServerError, "MirrorInterval", err) + return err + } + + // update MirrorInterval if opts.MirrorInterval != nil { - if !repo.IsMirror { - err := fmt.Errorf("repo is not a mirror, can not change mirror interval") - ctx.Error(http.StatusUnprocessableEntity, err.Error(), err) - return err - } - mirror, err := repo_model.GetMirrorByRepoID(repo.ID) + + // MirrorInterval should be a duration + interval, err := time.ParseDuration(*opts.MirrorInterval) if err != nil { - log.Error("Failed to get mirror: %s", err) - ctx.Error(http.StatusInternalServerError, "MirrorInterval", err) - return err - } - if interval, err := time.ParseDuration(*opts.MirrorInterval); err == nil { - mirror.Interval = interval - mirror.Repo = repo - if err := repo_model.UpdateMirror(mirror); err != nil { - log.Error("Failed to Set Mirror Interval: %s", err) - ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err) - return err - } - log.Trace("Repository %s/%s Mirror Interval was Updated to %s", ctx.Repo.Owner.Name, repo.Name, interval) - } else { log.Error("Wrong format for MirrorInternal Sent: %s", err) ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err) return err } + + // Ensure the provided duration is not too short + if interval != 0 && interval < setting.Mirror.MinInterval { + err := fmt.Errorf("invalid mirror interval: %s is below minimum interval: %s", interval, setting.Mirror.MinInterval) + ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err) + return err + } + + mirror.Interval = interval + mirror.Repo = repo + mirror.ScheduleNextUpdate() + log.Trace("Repository %s Mirror[%d] Set Interval: %s NextUpdateUnix: %s", repo.FullName(), mirror.ID, interval, mirror.NextUpdateUnix) } + + // update EnablePrune + if opts.EnablePrune != nil { + mirror.EnablePrune = *opts.EnablePrune + log.Trace("Repository %s Mirror[%d] Set EnablePrune: %t", repo.FullName(), mirror.ID, mirror.EnablePrune) + } + + // finally update the mirror in the DB + if err := repo_model.UpdateMirror(mirror); err != nil { + log.Error("Failed to Set Mirror Interval: %s", err) + ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err) + return err + } + return nil } diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index 13a625bafb..621b742e91 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -176,6 +176,8 @@ func CreateTag(ctx *context.APIContext) { // "$ref": "#/responses/Tag" // "404": // "$ref": "#/responses/notFound" + // "405": + // "$ref": "#/responses/empty" // "409": // "$ref": "#/responses/conflict" form := web.GetForm(ctx).(*api.CreateTagOption) @@ -196,6 +198,11 @@ func CreateTag(ctx *context.APIContext) { ctx.Error(http.StatusConflict, "tag exist", err) return } + if models.IsErrProtectedTagName(err) { + ctx.Error(http.StatusMethodNotAllowed, "CreateNewTag", "user not allowed to create protected tag") + return + } + ctx.InternalServerError(err) return } @@ -236,6 +243,8 @@ func DeleteTag(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/notFound" + // "405": + // "$ref": "#/responses/empty" // "409": // "$ref": "#/responses/conflict" tagName := ctx.Params("*") @@ -256,7 +265,12 @@ func DeleteTag(ctx *context.APIContext) { } if err = releaseservice.DeleteReleaseByID(tag.ID, ctx.User, true); err != nil { + if models.IsErrProtectedTagName(err) { + ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag") + return + } ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err) + return } ctx.Status(http.StatusNoContent) diff --git a/routers/api/v1/user/email.go b/routers/api/v1/user/email.go index 6887c306cc..7423bfbf2a 100644 --- a/routers/api/v1/user/email.go +++ b/routers/api/v1/user/email.go @@ -80,8 +80,16 @@ func AddEmail(ctx *context.APIContext) { if err := user_model.AddEmailAddresses(emails); err != nil { if user_model.IsErrEmailAlreadyUsed(err) { ctx.Error(http.StatusUnprocessableEntity, "", "Email address has been used: "+err.(user_model.ErrEmailAlreadyUsed).Email) - } else if user_model.IsErrEmailInvalid(err) { - errMsg := fmt.Sprintf("Email address %s invalid", err.(user_model.ErrEmailInvalid).Email) + } else if user_model.IsErrEmailCharIsNotSupported(err) || user_model.IsErrEmailInvalid(err) { + email := "" + if typedError, ok := err.(user_model.ErrEmailInvalid); ok { + email = typedError.Email + } + if typedError, ok := err.(user_model.ErrEmailCharIsNotSupported); ok { + email = typedError.Email + } + + errMsg := fmt.Sprintf("Email address %q invalid", email) ctx.Error(http.StatusUnprocessableEntity, "", errMsg) } else { ctx.Error(http.StatusInternalServerError, "AddEmailAddresses", err) diff --git a/routers/api/v1/user/follower.go b/routers/api/v1/user/follower.go index 1eacb89db2..d648d50d69 100644 --- a/routers/api/v1/user/follower.go +++ b/routers/api/v1/user/follower.go @@ -24,13 +24,13 @@ func responseAPIUsers(ctx *context.APIContext, users []*user_model.User) { } func listUserFollowers(ctx *context.APIContext, u *user_model.User) { - users, err := user_model.GetUserFollowers(u, utils.GetListOptions(ctx)) + users, count, err := user_model.GetUserFollowers(ctx, u, ctx.User, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err) return } - ctx.SetTotalCountHeader(int64(u.NumFollowers)) + ctx.SetTotalCountHeader(count) responseAPIUsers(ctx, users) } @@ -90,13 +90,13 @@ func ListFollowers(ctx *context.APIContext) { } func listUserFollowing(ctx *context.APIContext, u *user_model.User) { - users, err := user_model.GetUserFollowing(u, utils.GetListOptions(ctx)) + users, count, err := user_model.GetUserFollowing(ctx, u, ctx.User, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserFollowing", err) return } - ctx.SetTotalCountHeader(int64(u.NumFollowing)) + ctx.SetTotalCountHeader(count) responseAPIUsers(ctx, users) } diff --git a/routers/api/v1/user/key.go b/routers/api/v1/user/key.go index e8cc2035e5..aba723cf2e 100644 --- a/routers/api/v1/user/key.go +++ b/routers/api/v1/user/key.go @@ -266,16 +266,21 @@ func DeletePublicKey(ctx *context.APIContext) { id := ctx.ParamsInt64(":id") externallyManaged, err := asymkey_model.PublicKeyIsExternallyManaged(id) if err != nil { - ctx.Error(http.StatusInternalServerError, "PublicKeyIsExternallyManaged", err) + if asymkey_model.IsErrKeyNotExist(err) { + ctx.NotFound() + } else { + ctx.Error(http.StatusInternalServerError, "PublicKeyIsExternallyManaged", err) + } + return } + if externallyManaged { ctx.Error(http.StatusForbidden, "", "SSH Key is externally managed for this user") + return } if err := asymkey_service.DeletePublicKey(ctx.User, id); err != nil { - if asymkey_model.IsErrKeyNotExist(err) { - ctx.NotFound() - } else if asymkey_model.IsErrKeyAccessDenied(err) { + if asymkey_model.IsErrKeyAccessDenied(err) { ctx.Error(http.StatusForbidden, "", "You do not have access to this key") } else { ctx.Error(http.StatusInternalServerError, "DeletePublicKey", err) diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index 1f0a35ce22..6c06bcdd41 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -246,18 +246,29 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *webhook.Webh w.ChooseEvents = true w.Create = util.IsStringInSlice(string(webhook.HookEventCreate), form.Events, true) w.Push = util.IsStringInSlice(string(webhook.HookEventPush), form.Events, true) - w.PullRequest = util.IsStringInSlice(string(webhook.HookEventPullRequest), form.Events, true) w.Create = util.IsStringInSlice(string(webhook.HookEventCreate), form.Events, true) w.Delete = util.IsStringInSlice(string(webhook.HookEventDelete), form.Events, true) w.Fork = util.IsStringInSlice(string(webhook.HookEventFork), form.Events, true) - w.Issues = util.IsStringInSlice(string(webhook.HookEventIssues), form.Events, true) - w.IssueComment = util.IsStringInSlice(string(webhook.HookEventIssueComment), form.Events, true) - w.Push = util.IsStringInSlice(string(webhook.HookEventPush), form.Events, true) - w.PullRequest = util.IsStringInSlice(string(webhook.HookEventPullRequest), form.Events, true) w.Repository = util.IsStringInSlice(string(webhook.HookEventRepository), form.Events, true) w.Release = util.IsStringInSlice(string(webhook.HookEventRelease), form.Events, true) w.BranchFilter = form.BranchFilter + // Issues + w.Issues = issuesHook(form.Events, "issues_only") + w.IssueAssign = issuesHook(form.Events, string(webhook.HookEventIssueAssign)) + w.IssueLabel = issuesHook(form.Events, string(webhook.HookEventIssueLabel)) + w.IssueMilestone = issuesHook(form.Events, string(webhook.HookEventIssueMilestone)) + w.IssueComment = issuesHook(form.Events, string(webhook.HookEventIssueComment)) + + // Pull requests + w.PullRequest = pullHook(form.Events, "pull_request_only") + w.PullRequestAssign = pullHook(form.Events, string(webhook.HookEventPullRequestAssign)) + w.PullRequestLabel = pullHook(form.Events, string(webhook.HookEventPullRequestLabel)) + w.PullRequestMilestone = pullHook(form.Events, string(webhook.HookEventPullRequestMilestone)) + w.PullRequestComment = pullHook(form.Events, string(webhook.HookEventPullRequestComment)) + w.PullRequestReview = pullHook(form.Events, "pull_request_review") + w.PullRequestSync = pullHook(form.Events, string(webhook.HookEventPullRequestSync)) + if err := w.UpdateEvent(); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateEvent", err) return false diff --git a/routers/common/repo.go b/routers/common/repo.go index b0e14b63f5..1e9076a198 100644 --- a/routers/common/repo.go +++ b/routers/common/repo.go @@ -87,10 +87,14 @@ func ServeData(ctx *context.Context, name string, size int64, reader io.Reader) } if (st.IsImage() || st.IsPDF()) && (setting.UI.SVG.Enabled || !st.IsSvgImage()) { ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name)) - if st.IsSvgImage() { + if st.IsSvgImage() || st.IsPDF() { ctx.Resp.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox") ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff") - ctx.Resp.Header().Set("Content-Type", typesniffer.SvgMimeType) + if st.IsSvgImage() { + ctx.Resp.Header().Set("Content-Type", typesniffer.SvgMimeType) + } else { + ctx.Resp.Header().Set("Content-Type", typesniffer.ApplicationOctetStream) + } } } else { ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name)) diff --git a/routers/init.go b/routers/init.go index 804dfd6533..1e40a71d68 100644 --- a/routers/init.go +++ b/routers/init.go @@ -10,7 +10,6 @@ import ( "reflect" "runtime" "strconv" - "strings" "code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey" @@ -47,6 +46,8 @@ import ( "code.gitea.io/gitea/services/repository/archiver" "code.gitea.io/gitea/services/task" "code.gitea.io/gitea/services/webhook" + "golang.org/x/text/cases" + "golang.org/x/text/language" "gitea.com/go-chi/session" ) @@ -111,7 +112,7 @@ func GlobalInitInstalled(ctx context.Context) { log.Info("Custom path: %s", setting.CustomPath) log.Info("Log path: %s", setting.LogRootPath) log.Info("Configuration file: %s", setting.CustomConf) - log.Info("Run Mode: %s", strings.Title(setting.RunMode)) + log.Info("Run Mode: %s", cases.Title(language.English).String(setting.RunMode)) // Setup i18n translation.InitLocales() diff --git a/routers/install/install.go b/routers/install/install.go index 7c3d43bbde..a31a9bafb0 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -84,6 +84,8 @@ func Init(next http.Handler) http.Handler { "PasswordHashAlgorithms": user_model.AvailableHashAlgorithms, }, } + defer ctx.Close() + for _, lang := range translation.AllLangs() { if lang.Lang == locale.Language() { ctx.Data["LangName"] = lang.Name @@ -508,13 +510,17 @@ func SubmitInstall(ctx *context.Context) { // Create admin account if len(form.AdminName) > 0 { u := &user_model.User{ - Name: form.AdminName, - Email: form.AdminEmail, - Passwd: form.AdminPasswd, - IsAdmin: true, - IsActive: true, + Name: form.AdminName, + Email: form.AdminEmail, + Passwd: form.AdminPasswd, + IsAdmin: true, } - if err = user_model.CreateUser(u); err != nil { + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsRestricted: util.OptionalBoolFalse, + IsActive: util.OptionalBoolTrue, + } + + if err = user_model.CreateUser(u, overwriteDefault); err != nil { if !user_model.IsErrUserAlreadyExist(err) { setting.InstallLock = false ctx.Data["Err_AdminName"] = true diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index b8f61cbb11..bb87268412 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -12,6 +12,8 @@ import ( "strings" "code.gitea.io/gitea/models" + asymkey_model "code.gitea.io/gitea/models/asymkey" + perm_model "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" gitea_context "code.gitea.io/gitea/modules/context" @@ -24,8 +26,12 @@ import ( type preReceiveContext struct { *gitea_context.PrivateContext - user *user_model.User - perm models.Permission + + // loadedPusher indicates that where the following information are loaded + loadedPusher bool + user *user_model.User // it's the org user if a DeployKey is used + userPerm models.Permission + deployKeyAccessMode perm_model.AccessMode canCreatePullRequest bool checkedCanCreatePullRequest bool @@ -41,62 +47,52 @@ type preReceiveContext struct { opts *private.HookOptions } -// User gets or loads User -func (ctx *preReceiveContext) User() *user_model.User { - if ctx.user == nil { - ctx.user, ctx.perm = loadUserAndPermission(ctx.PrivateContext, ctx.opts.UserID) - } - return ctx.user -} - -// Perm gets or loads Perm -func (ctx *preReceiveContext) Perm() *models.Permission { - if ctx.user == nil { - ctx.user, ctx.perm = loadUserAndPermission(ctx.PrivateContext, ctx.opts.UserID) - } - return &ctx.perm -} - -// CanWriteCode returns true if can write code +// CanWriteCode returns true if pusher can write code func (ctx *preReceiveContext) CanWriteCode() bool { if !ctx.checkedCanWriteCode { - ctx.canWriteCode = ctx.Perm().CanWrite(unit.TypeCode) + if !ctx.loadPusherAndPermission() { + return false + } + ctx.canWriteCode = ctx.userPerm.CanWrite(unit.TypeCode) || ctx.deployKeyAccessMode >= perm_model.AccessModeWrite ctx.checkedCanWriteCode = true } return ctx.canWriteCode } -// AssertCanWriteCode returns true if can write code +// AssertCanWriteCode returns true if pusher can write code func (ctx *preReceiveContext) AssertCanWriteCode() bool { if !ctx.CanWriteCode() { if ctx.Written() { return false } ctx.JSON(http.StatusForbidden, map[string]interface{}{ - "err": "User permission denied.", + "err": "User permission denied for writing.", }) return false } return true } -// CanCreatePullRequest returns true if can create pull requests +// CanCreatePullRequest returns true if pusher can create pull requests func (ctx *preReceiveContext) CanCreatePullRequest() bool { if !ctx.checkedCanCreatePullRequest { - ctx.canCreatePullRequest = ctx.Perm().CanRead(unit.TypePullRequests) + if !ctx.loadPusherAndPermission() { + return false + } + ctx.canCreatePullRequest = ctx.userPerm.CanRead(unit.TypePullRequests) ctx.checkedCanCreatePullRequest = true } return ctx.canCreatePullRequest } -// AssertCanCreatePullRequest returns true if can create pull requests +// AssertCreatePullRequest returns true if can create pull requests func (ctx *preReceiveContext) AssertCreatePullRequest() bool { if !ctx.CanCreatePullRequest() { if ctx.Written() { return false } ctx.JSON(http.StatusForbidden, map[string]interface{}{ - "err": "User permission denied.", + "err": "User permission denied for creating pull-request.", }) return false } @@ -246,7 +242,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN // 5. Check if the doer is allowed to push canPush := false - if ctx.opts.IsDeployKey { + if ctx.opts.DeployKeyID != 0 { canPush = !changedProtectedfiles && protectBranch.CanPush && (!protectBranch.EnableWhitelist || protectBranch.WhitelistDeployKeys) } else { canPush = !changedProtectedfiles && protectBranch.CanUserPush(ctx.opts.UserID) @@ -303,9 +299,15 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN return } + // although we should have called `loadPusherAndPermission` before, here we call it explicitly again because we need to access ctx.user below + if !ctx.loadPusherAndPermission() { + // if error occurs, loadPusherAndPermission had written the error response + return + } + // Now check if the user is allowed to merge PRs for this repository // Note: we can use ctx.perm and ctx.user directly as they will have been loaded above - allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.perm, ctx.user) + allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.userPerm, ctx.user) if err != nil { log.Error("Error calculating if allowed to merge: %v", err) ctx.JSON(http.StatusInternalServerError, private.Response{ @@ -323,7 +325,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN } // If we're an admin for the repository we can ignore status checks, reviews and override protected files - if ctx.perm.IsAdmin() { + if ctx.userPerm.IsAdmin() { return } @@ -450,24 +452,44 @@ func generateGitEnv(opts *private.HookOptions) (env []string) { return env } -func loadUserAndPermission(ctx *gitea_context.PrivateContext, id int64) (user *user_model.User, perm models.Permission) { - user, err := user_model.GetUserByID(id) - if err != nil { - log.Error("Unable to get User id %d Error: %v", id, err) - ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: fmt.Sprintf("Unable to get User id %d Error: %v", id, err), - }) - return +// loadPusherAndPermission returns false if an error occurs, and it writes the error response +func (ctx *preReceiveContext) loadPusherAndPermission() bool { + if ctx.loadedPusher { + return true } - perm, err = models.GetUserRepoPermission(ctx.Repo.Repository, user) + user, err := user_model.GetUserByID(ctx.opts.UserID) + if err != nil { + log.Error("Unable to get User id %d Error: %v", ctx.opts.UserID, err) + ctx.JSON(http.StatusInternalServerError, private.Response{ + Err: fmt.Sprintf("Unable to get User id %d Error: %v", ctx.opts.UserID, err), + }) + return false + } + ctx.user = user + + userPerm, err := models.GetUserRepoPermission(ctx.Repo.Repository, user) if err != nil { log.Error("Unable to get Repo permission of repo %s/%s of User %s", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to get Repo permission of repo %s/%s of User %s: %v", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err), }) - return + return false + } + ctx.userPerm = userPerm + + if ctx.opts.DeployKeyID != 0 { + deployKey, err := asymkey_model.GetDeployKeyByID(ctx, ctx.opts.DeployKeyID) + if err != nil { + log.Error("Unable to get DeployKey id %d Error: %v", ctx.opts.DeployKeyID, err) + ctx.JSON(http.StatusInternalServerError, private.Response{ + Err: fmt.Sprintf("Unable to get DeployKey id %d Error: %v", ctx.opts.DeployKeyID, err), + }) + return false + } + ctx.deployKeyAccessMode = deployKey.Mode } - return + ctx.loadedPusher = true + return true } diff --git a/routers/private/mail.go b/routers/private/mail.go index 8b69c38093..853b58b09d 100644 --- a/routers/private/mail.go +++ b/routers/private/mail.go @@ -60,7 +60,7 @@ func SendEmail(ctx *context.PrivateContext) { } } else { err := user_model.IterateUser(func(user *user_model.User) error { - if len(user.Email) > 0 { + if len(user.Email) > 0 && user.IsActive { emails = append(emails, user.Email) } return nil diff --git a/routers/private/serv.go b/routers/private/serv.go index 6bf0ceeca2..8fe5c44922 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -229,8 +229,6 @@ func ServCommand(ctx *context.PrivateContext) { var deployKey *asymkey_model.DeployKey var user *user_model.User if key.Type == asymkey_model.KeyTypeDeploy { - results.IsDeployKey = true - var err error deployKey, err = asymkey_model.GetDeployKeyByRepo(key.ID, repo.ID) if err != nil { @@ -248,6 +246,7 @@ func ServCommand(ctx *context.PrivateContext) { }) return } + results.DeployKeyID = deployKey.ID results.KeyName = deployKey.Name // FIXME: Deploy keys aren't really the owner of the repo pushing changes @@ -410,9 +409,9 @@ func ServCommand(ctx *context.PrivateContext) { return } } - log.Debug("Serv Results:\nIsWiki: %t\nIsDeployKey: %t\nKeyID: %d\tKeyName: %s\nUserName: %s\nUserID: %d\nOwnerName: %s\nRepoName: %s\nRepoID: %d", + log.Debug("Serv Results:\nIsWiki: %t\nDeployKeyID: %d\nKeyID: %d\tKeyName: %s\nUserName: %s\nUserID: %d\nOwnerName: %s\nRepoName: %s\nRepoID: %d", results.IsWiki, - results.IsDeployKey, + results.DeployKeyID, results.KeyID, results.KeyName, results.UserName, diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index 7e25f96ee0..77fffc5e1f 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -209,7 +209,7 @@ func shadowPassword(provider, cfgItem string) string { case "redis": return shadowPasswordKV(cfgItem, ",") case "mysql": - //root:@tcp(localhost:3306)/macaron?charset=utf8 + // root:@tcp(localhost:3306)/macaron?charset=utf8 atIdx := strings.Index(cfgItem, "@") if atIdx > 0 { colonIdx := strings.Index(cfgItem[:atIdx], ":") @@ -244,7 +244,7 @@ func Config(ctx *context.Context) { ctx.Data["OfflineMode"] = setting.OfflineMode ctx.Data["DisableRouterLog"] = setting.DisableRouterLog ctx.Data["RunUser"] = setting.RunUser - ctx.Data["RunMode"] = strings.Title(setting.RunMode) + ctx.Data["RunMode"] = setting.RunMode if version, err := git.LocalVersion(); err == nil { ctx.Data["GitVersion"] = version.Original() } diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index 338a54c5dd..283bafad2d 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -93,7 +93,7 @@ func NewAuthSource(ctx *context.Context) { ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminAuthentications"] = true - ctx.Data["type"] = auth.LDAP + ctx.Data["type"] = auth.LDAP.Int() ctx.Data["CurrentTypeName"] = auth.Names[auth.LDAP] ctx.Data["CurrentSecurityProtocol"] = ldap.SecurityProtocolNames[ldap.SecurityProtocolUnencrypted] ctx.Data["smtp_auth"] = "PLAIN" @@ -112,7 +112,7 @@ func NewAuthSource(ctx *context.Context) { ctx.Data["SSPIDefaultLanguage"] = "" // only the first as default - ctx.Data["oauth2_provider"] = oauth2providers[0] + ctx.Data["oauth2_provider"] = oauth2providers[0].Name() ctx.HTML(http.StatusOK, tplAuthNew) } @@ -181,6 +181,14 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source { } else { customURLMapping = nil } + var scopes []string + for _, s := range strings.Split(form.Oauth2Scopes, ",") { + s = strings.TrimSpace(s) + if s != "" { + scopes = append(scopes, s) + } + } + return &oauth2.Source{ Provider: form.Oauth2Provider, ClientID: form.Oauth2Key, @@ -188,10 +196,13 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source { OpenIDConnectAutoDiscoveryURL: form.OpenIDConnectAutoDiscoveryURL, CustomURLMapping: customURLMapping, IconURL: form.Oauth2IconURL, - Scopes: strings.Split(form.Oauth2Scopes, ","), + Scopes: scopes, RequiredClaimName: form.Oauth2RequiredClaimName, RequiredClaimValue: form.Oauth2RequiredClaimValue, SkipLocalTwoFA: form.SkipLocalTwoFA, + GroupClaimName: form.Oauth2GroupClaimName, + RestrictedGroup: form.Oauth2RestrictedGroup, + AdminGroup: form.Oauth2AdminGroup, } } @@ -240,6 +251,9 @@ func NewAuthSourcePost(ctx *context.Context) { ctx.Data["SSPISeparatorReplacement"] = "_" ctx.Data["SSPIDefaultLanguage"] = "" + // FIXME: most error path to render tplAuthNew will fail and result in 500 + // * template: admin/auth/new:17:68: executing "admin/auth/new" at <.type.Int>: can't evaluate field Int in type interface {} + // * template: admin/auth/source/oauth:5:93: executing "admin/auth/source/oauth" at <.oauth2_provider.Name>: can't evaluate field Name in type interface {} hasTLS := false var config convert.Conversion switch auth.Type(form.Type) { @@ -390,6 +404,7 @@ func EditAuthSourcePost(ctx *context.Context) { source.IsActive = form.IsActive source.IsSyncEnabled = form.IsSyncEnabled source.Cfg = config + // FIXME: if the name conflicts, it will result in 500: Error 1062: Duplicate entry 'aa' for key 'login_source.UQE_login_source_name' if err := auth.UpdateSource(source); err != nil { if oauth2.IsErrOpenIDConnectInitialize(err) { ctx.Flash.Error(err.Error(), true) diff --git a/routers/web/admin/hooks.go b/routers/web/admin/hooks.go index 8cb99e1d1e..1483d0959d 100644 --- a/routers/web/admin/hooks.go +++ b/routers/web/admin/hooks.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) const ( @@ -34,7 +35,7 @@ func DefaultOrSystemWebhooks(ctx *context.Context) { sys["Title"] = ctx.Tr("admin.systemhooks") sys["Description"] = ctx.Tr("admin.systemhooks.desc") - sys["Webhooks"], err = webhook.GetSystemWebhooks() + sys["Webhooks"], err = webhook.GetSystemWebhooks(util.OptionalBoolNone) sys["BaseLink"] = setting.AppSubURL + "/admin/hooks" sys["BaseLinkNew"] = setting.AppSubURL + "/admin/system-hooks" if err != nil { diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 5cb25d8672..1576f58b41 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -41,10 +41,16 @@ func Users(ctx *context.Context) { ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminUsers"] = true + extraParamStrings := map[string]string{} statusFilterKeys := []string{"is_active", "is_admin", "is_restricted", "is_2fa_enabled", "is_prohibit_login"} statusFilterMap := map[string]string{} for _, filterKey := range statusFilterKeys { - statusFilterMap[filterKey] = ctx.FormString("status_filter[" + filterKey + "]") + paramKey := "status_filter[" + filterKey + "]" + paramVal := ctx.FormString(paramKey) + statusFilterMap[filterKey] = paramVal + if paramVal != "" { + extraParamStrings[paramKey] = paramVal + } } sortType := ctx.FormString("sort") @@ -68,6 +74,7 @@ func Users(ctx *context.Context) { IsRestricted: util.OptionalBoolParse(statusFilterMap["is_restricted"]), IsTwoFactorEnabled: util.OptionalBoolParse(statusFilterMap["is_2fa_enabled"]), IsProhibitLogin: util.OptionalBoolParse(statusFilterMap["is_prohibit_login"]), + ExtraParamStrings: extraParamStrings, }, tplUsers) } @@ -118,10 +125,14 @@ func NewUserPost(ctx *context.Context) { Name: form.UserName, Email: form.Email, Passwd: form.Password, - IsActive: true, LoginType: auth.Plain, } + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsActive: util.OptionalBoolTrue, + Visibility: &form.Visibility, + } + if len(form.LoginType) > 0 { fields := strings.Split(form.LoginType, "-") if len(fields) == 2 { @@ -156,7 +167,7 @@ func NewUserPost(ctx *context.Context) { u.MustChangePassword = form.MustChangePassword } - if err := user_model.CreateUser(u, &user_model.CreateUserOverwriteOptions{Visibility: form.Visibility}); err != nil { + if err := user_model.CreateUser(u, overwriteDefault); err != nil { switch { case user_model.IsErrUserAlreadyExist(err): ctx.Data["Err_UserName"] = true @@ -164,6 +175,9 @@ func NewUserPost(ctx *context.Context) { case user_model.IsErrEmailAlreadyUsed(err): ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserNew, &form) + case user_model.IsErrEmailCharIsNotSupported(err): + ctx.Data["Err_Email"] = true + ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form) case user_model.IsErrEmailInvalid(err): ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form) @@ -217,15 +231,17 @@ func prepareUserInfo(ctx *context.Context) *user_model.User { } ctx.Data["Sources"] = sources - ctx.Data["TwoFactorEnabled"] = true - _, err = auth.GetTwoFactorByUID(u.ID) + hasTOTP, err := auth.HasTwoFactorByUID(u.ID) if err != nil { - if !auth.IsErrTwoFactorNotEnrolled(err) { - ctx.ServerError("IsErrTwoFactorNotEnrolled", err) - return nil - } - ctx.Data["TwoFactorEnabled"] = false + ctx.ServerError("auth.HasTwoFactorByUID", err) + return nil } + hasWebAuthn, err := auth.HasWebAuthnRegistrationsByUID(u.ID) + if err != nil { + ctx.ServerError("auth.HasWebAuthnRegistrationsByUID", err) + return nil + } + ctx.Data["TwoFactorEnabled"] = hasTOTP || hasWebAuthn return u } @@ -327,14 +343,27 @@ func EditUserPost(ctx *context.Context) { if form.Reset2FA { tf, err := auth.GetTwoFactorByUID(u.ID) if err != nil && !auth.IsErrTwoFactorNotEnrolled(err) { - ctx.ServerError("GetTwoFactorByUID", err) + ctx.ServerError("auth.GetTwoFactorByUID", err) return + } else if tf != nil { + if err := auth.DeleteTwoFactorByID(tf.ID, u.ID); err != nil { + ctx.ServerError("auth.DeleteTwoFactorByID", err) + return + } } - if err = auth.DeleteTwoFactorByID(tf.ID, u.ID); err != nil { - ctx.ServerError("DeleteTwoFactorByID", err) + wn, err := auth.GetWebAuthnCredentialsByUID(u.ID) + if err != nil { + ctx.ServerError("auth.GetTwoFactorByUID", err) return } + for _, cred := range wn { + if _, err := auth.DeleteCredential(cred.ID, u.ID); err != nil { + ctx.ServerError("auth.DeleteCredential", err) + return + } + } + } u.LoginName = form.LoginName @@ -364,7 +393,8 @@ func EditUserPost(ctx *context.Context) { if user_model.IsErrEmailAlreadyUsed(err) { ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form) - } else if user_model.IsErrEmailInvalid(err) { + } else if user_model.IsErrEmailCharIsNotSupported(err) || + user_model.IsErrEmailInvalid(err) { ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserEdit, &form) } else { diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index d6b3635584..3ef9fb6541 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -195,7 +195,7 @@ func SignInPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.SignInForm) u, source, err := auth_service.UserSignIn(form.UserName, form.Password) if err != nil { - if user_model.IsErrUserNotExist(err) { + if user_model.IsErrUserNotExist(err) || user_model.IsErrEmailAddressNotExist(err) { ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form) log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) } else if user_model.IsErrEmailAlreadyUsed(err) { @@ -417,7 +417,7 @@ func SignUp(ctx *context.Context) { ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey ctx.Data["PageIsSignUp"] = true - //Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true + // Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration || setting.Service.AllowOnlyExternalRegistration ctx.HTML(http.StatusOK, tplSignUp) @@ -438,7 +438,7 @@ func SignUpPost(ctx *context.Context) { ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey ctx.Data["PageIsSignUp"] = true - //Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true + // Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true if setting.Service.DisableRegistration || setting.Service.AllowOnlyExternalRegistration { ctx.Error(http.StatusForbidden) return @@ -507,14 +507,12 @@ func SignUpPost(ctx *context.Context) { } u := &user_model.User{ - Name: form.UserName, - Email: form.Email, - Passwd: form.Password, - IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm), - IsRestricted: setting.Service.DefaultUserIsRestricted, + Name: form.UserName, + Email: form.Email, + Passwd: form.Password, } - if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, false) { + if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, nil, false) { // error already handled return } @@ -525,8 +523,8 @@ func SignUpPost(ctx *context.Context) { // createAndHandleCreatedUser calls createUserInContext and // then handleUserCreated. -func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, gothUser *goth.User, allowLink bool) bool { - if !createUserInContext(ctx, tpl, form, u, gothUser, allowLink) { +func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) bool { + if !createUserInContext(ctx, tpl, form, u, overwrites, gothUser, allowLink) { return false } return handleUserCreated(ctx, u, gothUser) @@ -534,8 +532,8 @@ func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form int // createUserInContext creates a user and handles errors within a given context. // Optionally a template can be specified. -func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, gothUser *goth.User, allowLink bool) (ok bool) { - if err := user_model.CreateUser(u); err != nil { +func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) { + if err := user_model.CreateUser(u, overwrites); err != nil { if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) { if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto { var user *user_model.User @@ -573,6 +571,9 @@ func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{ case user_model.IsErrEmailAlreadyUsed(err): ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tpl, form) + case user_model.IsErrEmailCharIsNotSupported(err): + ctx.Data["Err_Email"] = true + ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form) case user_model.IsErrEmailInvalid(err): ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form) @@ -618,6 +619,12 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth. // Send confirmation email if !u.IsActive && u.ID > 1 { + if setting.Service.RegisterManualConfirm { + ctx.Data["ManualActivationOnly"] = true + ctx.HTML(http.StatusOK, TplActivate) + return + } + mailer.SendActivateAccountMail(ctx.Locale, u) ctx.Data["IsSendRegisterMail"] = true @@ -625,8 +632,10 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth. ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language()) ctx.HTML(http.StatusOK, TplActivate) - if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { - log.Error("Set cache(MailResendLimit) fail: %v", err) + if setting.CacheService.Enabled { + if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } return } @@ -646,14 +655,15 @@ func Activate(ctx *context.Context) { } // Resend confirmation email. if setting.Service.RegisterEmailConfirm { - if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) { + if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.User.LowerName) { ctx.Data["ResendLimited"] = true } else { ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language()) mailer.SendActivateAccountMail(ctx.Locale, ctx.User) - - if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil { - log.Error("Set cache(MailResendLimit) fail: %v", err) + if setting.CacheService.Enabled { + if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } } } else { @@ -782,7 +792,7 @@ func ActivateEmail(ctx *context.Context) { if u, err := user_model.GetUserByID(email.UID); err != nil { log.Warn("GetUserByID: %d", email.UID) - } else { + } else if setting.CacheService.Enabled { // Allow user to validate more emails _ = ctx.Cache.Delete("MailResendLimit_" + u.LowerName) } diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index 27eb954a58..59e314b7c2 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -285,13 +285,12 @@ func LinkAccountPostRegister(ctx *context.Context) { Name: form.UserName, Email: form.Email, Passwd: form.Password, - IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm), LoginType: auth.OAuth2, LoginSource: authSource.ID, LoginName: gothUser.UserID, } - if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, &gothUser, false) { + if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, nil, &gothUser, false) { // error already handled return } diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index fa2b0aa65f..313cd804eb 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -25,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" auth_service "code.gitea.io/gitea/services/auth" @@ -826,7 +827,7 @@ func SignInOAuthCallback(ctx *context.Context) { u, gothUser, err := oAuth2UserLoginCallback(authSource, ctx.Req, ctx.Resp) if err != nil { if user_model.IsErrUserProhibitLogin(err) { - uplerr := err.(*user_model.ErrUserProhibitLogin) + uplerr := err.(user_model.ErrUserProhibitLogin) log.Info("Failed authentication attempt for %s from %s: %v", uplerr.Name, ctx.RemoteAddr(), err) ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") ctx.HTML(http.StatusOK, "user/auth/prohibit_login") @@ -872,19 +873,21 @@ func SignInOAuthCallback(ctx *context.Context) { return } u = &user_model.User{ - Name: getUserName(&gothUser), - FullName: gothUser.Name, - Email: gothUser.Email, - IsActive: !setting.OAuth2Client.RegisterEmailConfirm, - LoginType: auth.OAuth2, - LoginSource: authSource.ID, - LoginName: gothUser.UserID, - IsRestricted: setting.Service.DefaultUserIsRestricted, + Name: getUserName(&gothUser), + FullName: gothUser.Name, + Email: gothUser.Email, + LoginType: auth.OAuth2, + LoginSource: authSource.ID, + LoginName: gothUser.UserID, + } + + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm), } setUserGroupClaims(authSource, u, &gothUser) - if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) { + if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, overwriteDefault, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) { // error already handled return } @@ -904,6 +907,10 @@ func claimValueToStringSlice(claimValue interface{}) []string { switch rawGroup := claimValue.(type) { case []string: groups = rawGroup + case []interface{}: + for _, group := range rawGroup { + groups = append(groups, fmt.Sprintf("%s", group)) + } default: str := fmt.Sprintf("%s", rawGroup) groups = strings.Split(str, ",") diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index 4395641795..4450aefbe3 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -425,12 +425,11 @@ func RegisterOpenIDPost(ctx *context.Context) { } u := &user_model.User{ - Name: form.UserName, - Email: form.Email, - Passwd: password, - IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm), + Name: form.UserName, + Email: form.Email, + Passwd: password, } - if !createUserInContext(ctx, tplSignUpOID, form, u, nil, false) { + if !createUserInContext(ctx, tplSignUpOID, form, u, nil, nil, false) { // error already handled return } diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go index 65d5c55976..fe11554120 100644 --- a/routers/web/auth/password.go +++ b/routers/web/auth/password.go @@ -80,7 +80,7 @@ func ForgotPasswdPost(ctx *context.Context) { return } - if ctx.Cache.IsExist("MailResendLimit_" + u.LowerName) { + if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+u.LowerName) { ctx.Data["ResendLimited"] = true ctx.HTML(http.StatusOK, tplForgotPassword) return @@ -88,8 +88,10 @@ func ForgotPasswdPost(ctx *context.Context) { mailer.SendResetPasswordMail(u) - if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { - log.Error("Set cache(MailResendLimit) fail: %v", err) + if setting.CacheService.Enabled { + if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language()) diff --git a/routers/web/base.go b/routers/web/base.go index 98713bc881..dcd00f2c61 100644 --- a/routers/web/base.go +++ b/routers/web/base.go @@ -11,7 +11,6 @@ import ( "net/http" "os" "path" - "path/filepath" "strings" "code.gitea.io/gitea/modules/context" @@ -27,6 +26,8 @@ import ( ) func storageHandler(storageSetting setting.Storage, prefix string, objStore storage.ObjectStorage) func(next http.Handler) http.Handler { + prefix = strings.Trim(prefix, "/") + return func(next http.Handler) http.Handler { if storageSetting.ServeDirect { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { @@ -35,12 +36,14 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor return } - if !strings.HasPrefix(req.URL.RequestURI(), "/"+prefix) { + if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") { next.ServeHTTP(w, req) return } - rPath := strings.TrimPrefix(req.URL.RequestURI(), "/"+prefix) + rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/") + rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:] + u, err := objStore.URL(rPath, path.Base(rPath)) if err != nil { if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) { @@ -52,11 +55,12 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor http.Error(w, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath), 500) return } + http.Redirect( w, req, u.String(), - 301, + http.StatusMovedPermanently, ) }) } @@ -67,28 +71,24 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor return } - prefix := strings.Trim(prefix, "/") - - if !strings.HasPrefix(req.URL.EscapedPath(), "/"+prefix+"/") { + if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") { next.ServeHTTP(w, req) return } - rPath := strings.TrimPrefix(req.URL.EscapedPath(), "/"+prefix+"/") - rPath = strings.TrimPrefix(rPath, "/") + rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/") + rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:] if rPath == "" { http.Error(w, "file not found", 404) return } - rPath = path.Clean("/" + filepath.ToSlash(rPath)) - rPath = rPath[1:] fi, err := objStore.Stat(rPath) if err == nil && httpcache.HandleTimeCache(req, w, fi) { return } - //If we have matched and access to release or issue + // If we have matched and access to release or issue fr, err := objStore.Open(rPath) if err != nil { if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) { @@ -121,7 +121,7 @@ func (d *dataStore) GetData() map[string]interface{} { // Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so. // This error will be created with the gitea 500 page. func Recovery() func(next http.Handler) http.Handler { - var rnd = templates.HTMLRenderer() + rnd := templates.HTMLRenderer() return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { defer func() { @@ -131,14 +131,14 @@ func Recovery() func(next http.Handler) http.Handler { sessionStore := session.GetSession(req) - var lc = middleware.Locale(w, req) - var store = dataStore{ + lc := middleware.Locale(w, req) + store := dataStore{ "Language": lc.Language(), "CurrentURL": setting.AppSubURL + req.URL.RequestURI(), "i18n": lc, } - var user = context.GetContextUser(req) + user := context.GetContextUser(req) if user == nil { // Get user from session if logged in - do not attempt to sign-in user = auth.SessionUser(sessionStore) diff --git a/routers/web/explore/user.go b/routers/web/explore/user.go index 27634c3d4e..5973a4e066 100644 --- a/routers/web/explore/user.go +++ b/routers/web/explore/user.go @@ -84,6 +84,9 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5) pager.SetDefaultParams(ctx) + for paramKey, paramVal := range opts.ExtraParamStrings { + pager.AddParamString(paramKey, paramVal) + } ctx.Data["Page"] = pager ctx.HTML(http.StatusOK, tplName) diff --git a/routers/web/feed/profile.go b/routers/web/feed/profile.go index 1a7f4ad24b..bd6e381143 100644 --- a/routers/web/feed/profile.go +++ b/routers/web/feed/profile.go @@ -34,6 +34,9 @@ func RetrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) []*mode } for _, act := range actions { + if act.Repo == nil { + continue + } repoOwner, ok := userCache[act.Repo.OwnerID] if !ok { repoOwner, err = user_model.GetUserByID(act.Repo.OwnerID) diff --git a/routers/web/org/home.go b/routers/web/org/home.go index 3a42044281..4967ce0e99 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -6,6 +6,7 @@ package org import ( "net/http" + "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" @@ -23,7 +24,14 @@ const ( // Home show organization home page func Home(ctx *context.Context) { - ctx.SetParams(":org", ctx.Params(":username")) + uname := ctx.Params(":username") + + if strings.HasSuffix(uname, ".keys") || strings.HasSuffix(uname, ".gpg") { + ctx.NotFound("", nil) + return + } + + ctx.SetParams(":org", uname) context.HandleOrgAssignment(ctx) if ctx.Written() { return @@ -109,7 +117,7 @@ func Home(ctx *context.Context) { return } - var opts = &models.FindOrgMembersOpts{ + opts := &models.FindOrgMembersOpts{ OrgID: org.ID, PublicOnly: true, ListOptions: db.ListOptions{Page: 1, PageSize: 25}, diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 732f24b22c..f6e09eb4c8 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -311,6 +311,7 @@ func TeamMembers(ctx *context.Context) { ctx.ServerError("GetMembers", err) return } + ctx.Data["Units"] = unit_model.Units ctx.HTML(http.StatusOK, tplTeamMembers) } @@ -319,10 +320,11 @@ func TeamRepositories(ctx *context.Context) { ctx.Data["Title"] = ctx.Org.Team.Name ctx.Data["PageIsOrgTeams"] = true ctx.Data["PageIsOrgTeamRepos"] = true - if err := ctx.Org.Team.GetRepositories(&models.SearchTeamOptions{}); err != nil { + if err := ctx.Org.Team.GetRepositories(&models.SearchOrgTeamOptions{}); err != nil { ctx.ServerError("GetRepositories", err) return } + ctx.Data["Units"] = unit_model.Units ctx.HTML(http.StatusOK, tplTeamRepositories) } diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 29b8acd61c..806814efde 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -370,6 +370,12 @@ func CreateBranch(ctx *context.Context) { err = repo_service.CreateNewBranchFromCommit(ctx.User, ctx.Repo.Repository, ctx.Repo.CommitID, form.NewBranchName) } if err != nil { + if models.IsErrProtectedTagName(err) { + ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected")) + ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()) + return + } + if models.IsErrTagAlreadyExists(err) { e := err.(models.ErrTagAlreadyExists) ctx.Flash.Error(ctx.Tr("repo.branch.tag_collision", e.TagName)) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 304f76158c..6b890ac484 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -351,7 +351,7 @@ func Diff(ctx *context.Context) { ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0 if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) { - return models.IsUserRepoAdmin(ctx.Repo.Repository, user) + return models.IsOwnerMemberCollaborator(ctx.Repo.Repository, user.ID) }, nil); err != nil { ctx.ServerError("CalculateTrustStatus", err) return diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 3b07c35cb0..f1b89a7be0 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -77,8 +77,8 @@ func setPathsCompareContext(ctx *context.Context, base, head *git.Commit, headOw ctx.Data["SourcePath"] = SourceCommitURL(headOwner, headName, head) ctx.Data["RawPath"] = RawCommitURL(headOwner, headName, head) if base != nil { - ctx.Data["BeforeSourcePath"] = SourceCommitURL(headOwner, headName, head) - ctx.Data["BeforeRawPath"] = RawCommitURL(headOwner, headName, head) + ctx.Data["BeforeSourcePath"] = SourceCommitURL(headOwner, headName, base) + ctx.Data["BeforeRawPath"] = RawCommitURL(headOwner, headName, base) } } @@ -298,6 +298,13 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { ci.BaseBranch = baseCommit.ID.String() ctx.Data["BaseBranch"] = ci.BaseBranch baseIsCommit = true + } else if ci.BaseBranch == git.EmptySHA { + if isSameRepo { + ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch)) + } else { + ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadRepo.FullName()) + ":" + util.PathEscapeSegments(ci.HeadBranch)) + } + return nil } else { ctx.NotFound("IsRefExist", nil) return nil @@ -786,6 +793,15 @@ func ExcerptBlob(ctx *context.Context) { direction := ctx.FormString("direction") filePath := ctx.FormString("path") gitRepo := ctx.Repo.GitRepo + if ctx.FormBool("wiki") { + var err error + gitRepo, err = git.OpenRepositoryCtx(ctx, ctx.Repo.Repository.WikiPath()) + if err != nil { + ctx.ServerError("OpenRepository", err) + return + } + defer gitRepo.Close() + } chunkSize := gitdiff.BlobExcerptChunkSize commit, err := gitRepo.GetCommit(commitID) if err != nil { diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go index 6ebf6a789a..fb48ac73fd 100644 --- a/routers/web/repo/http.go +++ b/routers/web/repo/http.go @@ -103,7 +103,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) { } isWiki := false - var unitType = unit.TypeCode + unitType := unit.TypeCode var wikiRepoName string if strings.HasSuffix(reponame, ".wiki") { isWiki = true @@ -223,7 +223,6 @@ func httpBase(ctx *context.Context) (h *serviceHandler) { models.EnvRepoName + "=" + reponame, models.EnvPusherName + "=" + ctx.User.Name, models.EnvPusherID + fmt.Sprintf("=%d", ctx.User.ID), - models.EnvIsDeployKey + "=false", models.EnvAppURL + "=" + setting.AppURL, } @@ -456,7 +455,6 @@ func serviceRPC(h serviceHandler, service string) { if err := h.r.Body.Close(); err != nil { log.Error("serviceRPC: Close: %v", err) } - }() if !hasAccess(service, h, true) { @@ -467,7 +465,7 @@ func serviceRPC(h serviceHandler, service string) { h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service)) var err error - var reqBody = h.r.Body + reqBody := h.r.Body // Handle GZIP. if h.r.Header.Get("Content-Encoding") == "gzip" { @@ -491,7 +489,10 @@ func serviceRPC(h serviceHandler, service string) { defer finished() var stderr bytes.Buffer - cmd := exec.CommandContext(ctx, git.GitExecutable, service, "--stateless-rpc", h.dir) + args := make([]string, len(git.GlobalCommandArgs)) + copy(args, git.GlobalCommandArgs) + args = append(args, []string{service, "--stateless-rpc", h.dir}...) + cmd := exec.CommandContext(ctx, git.GitExecutable, args...) cmd.Dir = h.dir cmd.Env = append(os.Environ(), h.environ...) cmd.Stdout = h.w @@ -499,7 +500,9 @@ func serviceRPC(h serviceHandler, service string) { cmd.Stderr = &stderr if err := cmd.Run(); err != nil { - log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String()) + if err.Error() != "signal: killed" { + log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String()) + } return } } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 9dee477537..cc384bd013 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -57,17 +57,15 @@ const ( issueTemplateTitleKey = "IssueTemplateTitle" ) -var ( - // IssueTemplateCandidates issue templates - IssueTemplateCandidates = []string{ - "ISSUE_TEMPLATE.md", - "issue_template.md", - ".gitea/ISSUE_TEMPLATE.md", - ".gitea/issue_template.md", - ".github/ISSUE_TEMPLATE.md", - ".github/issue_template.md", - } -) +// IssueTemplateCandidates issue templates +var IssueTemplateCandidates = []string{ + "ISSUE_TEMPLATE.md", + "issue_template.md", + ".gitea/ISSUE_TEMPLATE.md", + ".gitea/issue_template.md", + ".github/ISSUE_TEMPLATE.md", + ".github/issue_template.md", +} // MustAllowUserComment checks to make sure if an issue is locked. // If locked and user has permissions to write to the repository, @@ -226,7 +224,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti Page: pager.Paginater.Current(), PageSize: setting.UI.IssuePagingNum, }, - RepoIDs: []int64{repo.ID}, + RepoID: repo.ID, AssigneeID: assigneeID, PosterID: posterID, MentionedID: mentionedID, @@ -245,7 +243,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti } } - var issueList = models.IssueList(issues) + issueList := models.IssueList(issues) approvalCounts, err := issueList.GetApprovalCounts() if err != nil { ctx.ServerError("ApprovalCounts", err) @@ -311,8 +309,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti assigneeID = 0 // Reset ID to prevent unexpected selection of assignee. } - ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = - issue_service.GetRefEndNamesAndURLs(issues, ctx.Repo.RepoLink) + ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, ctx.Repo.RepoLink) ctx.Data["ApprovalCounts"] = func(issueID int64, typ string) int64 { counts, ok := approvalCounts[issueID] @@ -442,7 +439,6 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R } func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) { - var err error ctx.Data["OpenProjects"], _, err = models.GetProjects(models.ProjectSearchOptions{ @@ -796,13 +792,14 @@ func NewIssue(ctx *context.Context) { body := ctx.FormString("body") ctx.Data["BodyQuery"] = body - ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(unit.TypeProjects) + isProjectsEnabled := ctx.Repo.CanRead(unit.TypeProjects) + ctx.Data["IsProjectsEnabled"] = isProjectsEnabled ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled upload.AddUploadContext(ctx, "comment") milestoneID := ctx.FormInt64("milestone") if milestoneID > 0 { - milestone, err := models.GetMilestoneByID(milestoneID) + milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, milestoneID) if err != nil { log.Error("GetMilestoneByID: %d: %v", milestoneID, err) } else { @@ -812,7 +809,7 @@ func NewIssue(ctx *context.Context) { } projectID := ctx.FormInt64("project") - if projectID > 0 { + if projectID > 0 && isProjectsEnabled { project, err := models.GetProjectByID(projectID) if err != nil { log.Error("GetProjectByID: %d: %v", projectID, err) @@ -843,12 +840,19 @@ func NewIssue(ctx *context.Context) { func NewIssueChooseTemplate(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.issues.new") ctx.Data["PageIsIssueList"] = true - ctx.Data["milestone"] = ctx.FormInt64("milestone") issueTemplates := ctx.IssueTemplatesFromDefaultBranch() - ctx.Data["NewIssueChooseTemplate"] = len(issueTemplates) > 0 ctx.Data["IssueTemplates"] = issueTemplates + if len(issueTemplates) == 0 { + // The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if no template here, just redirect to the "issues/new" page with these parameters. + ctx.Redirect(fmt.Sprintf("%s/issues/new?%s", ctx.Repo.Repository.HTMLURL(), ctx.Req.URL.RawQuery), http.StatusSeeOther) + return + } + + ctx.Data["milestone"] = ctx.FormInt64("milestone") + ctx.Data["project"] = ctx.FormInt64("project") + ctx.HTML(http.StatusOK, tplIssueChoose) } @@ -889,7 +893,7 @@ func ValidateRepoMetas(ctx *context.Context, form forms.CreateIssueForm, isPull // Check milestone. milestoneID := form.MilestoneID if milestoneID > 0 { - milestone, err := models.GetMilestoneByID(milestoneID) + milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, milestoneID) if err != nil { ctx.ServerError("GetMilestoneByID", err) return nil, nil, 0, 0 @@ -1010,6 +1014,12 @@ func NewIssuePost(ctx *context.Context) { } if projectID > 0 { + if !ctx.Repo.CanRead(unit.TypeProjects) { + // User must also be able to see the project. + ctx.Error(http.StatusBadRequest, "user hasn't permissions to read projects") + return + } + if err := models.ChangeProjectAssign(issue, ctx.User, projectID); err != nil { ctx.ServerError("ChangeProjectAssign", err) return @@ -1706,6 +1716,11 @@ func getActionIssues(ctx *context.Context) []*models.Issue { issueUnitEnabled := ctx.Repo.CanRead(unit.TypeIssues) prUnitEnabled := ctx.Repo.CanRead(unit.TypePullRequests) for _, issue := range issues { + if issue.RepoID != ctx.Repo.Repository.ID { + ctx.NotFound("some issue's RepoID is incorrect", errors.New("some issue's RepoID is incorrect")) + return nil + } + if issue.IsPull && !prUnitEnabled || !issue.IsPull && !issueUnitEnabled { ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil) return nil @@ -2508,7 +2523,7 @@ func filterXRefComments(ctx *context.Context, issue *models.Issue) error { // GetIssueAttachments returns attachments for the issue func GetIssueAttachments(ctx *context.Context) { issue := GetActionIssue(ctx) - var attachments = make([]*api.Attachment, len(issue.Attachments)) + attachments := make([]*api.Attachment, len(issue.Attachments)) for i := 0; i < len(issue.Attachments); i++ { attachments[i] = convert.ToReleaseAttachment(issue.Attachments[i]) } @@ -2522,7 +2537,7 @@ func GetCommentAttachments(ctx *context.Context) { ctx.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err) return } - var attachments = make([]*api.Attachment, 0) + attachments := make([]*api.Attachment, 0) if comment.Type == models.CommentTypeComment { if err := comment.LoadAttachments(); err != nil { ctx.ServerError("LoadAttachments", err) @@ -2667,7 +2682,7 @@ func handleTeamMentions(ctx *context.Context) { var isAdmin bool var err error var teams []*models.Team - var org = models.OrgFromUser(ctx.Repo.Owner) + org := models.OrgFromUser(ctx.Repo.Owner) // Admin has super access. if ctx.User.IsAdmin { isAdmin = true diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go index 08eb98acb8..90217a0346 100644 --- a/routers/web/repo/issue_content_history.go +++ b/routers/web/repo/issue_content_history.go @@ -9,6 +9,7 @@ import ( "fmt" "html" "net/http" + "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" @@ -16,6 +17,7 @@ import ( "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "github.com/sergi/go-diff/diffmatchpatch" @@ -68,9 +70,15 @@ func GetContentHistoryList(ctx *context.Context) { actionText = i18n.Tr(lang, "repo.issues.content_history.edited") } timeSinceText := timeutil.TimeSinceUnix(item.EditedUnix, lang) + + username := item.UserName + if setting.UI.DefaultShowFullName && strings.TrimSpace(item.UserFullName) != "" { + username = strings.TrimSpace(item.UserFullName) + } + results = append(results, map[string]interface{}{ "name": fmt.Sprintf("%s %s %s", - html.EscapeString(item.UserAvatarLink), html.EscapeString(item.UserName), actionText, timeSinceText), + html.EscapeString(item.UserAvatarLink), html.EscapeString(username), actionText, timeSinceText), "value": item.HistoryID, }) } diff --git a/routers/web/repo/lfs.go b/routers/web/repo/lfs.go index 8943641381..beddedb079 100644 --- a/routers/web/repo/lfs.go +++ b/routers/web/repo/lfs.go @@ -253,6 +253,13 @@ func LFSFileGet(ctx *context.Context) { } ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs" oid := ctx.Params("oid") + + p := lfs.Pointer{Oid: oid} + if !p.IsValid() { + ctx.NotFound("LFSFileGet", nil) + return + } + ctx.Data["Title"] = oid ctx.Data["PageIsSettingsLFS"] = true meta, err := models.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid) @@ -343,6 +350,12 @@ func LFSDelete(ctx *context.Context) { return } oid := ctx.Params("oid") + p := lfs.Pointer{Oid: oid} + if !p.IsValid() { + ctx.NotFound("LFSDelete", nil) + return + } + count, err := models.RemoveLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid) if err != nil { ctx.ServerError("LFSDelete", err) diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index eadc89333f..df5fd411b4 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -264,7 +264,7 @@ func DeleteMilestone(ctx *context.Context) { // MilestoneIssuesAndPulls lists all the issues and pull requests of the milestone func MilestoneIssuesAndPulls(ctx *context.Context) { milestoneID := ctx.ParamsInt64(":id") - milestone, err := models.GetMilestoneByID(milestoneID) + milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, milestoneID) if err != nil { if models.IsErrMilestoneNotExist(err) { ctx.NotFound("GetMilestoneByID", err) diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index f6be8add0b..aae973511e 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -5,6 +5,7 @@ package repo import ( + "errors" "fmt" "net/http" "net/url" @@ -531,7 +532,6 @@ func EditProjectBoard(ctx *context.Context) { // SetDefaultProjectBoard set default board for uncategorized issues/pulls func SetDefaultProjectBoard(ctx *context.Context) { - project, board := checkProjectBoardChangePermissions(ctx) if ctx.Written() { return @@ -631,10 +631,17 @@ func MoveIssues(ctx *context.Context) { } if len(movedIssues) != len(form.Issues) { - ctx.ServerError("IssuesNotFound", err) + ctx.ServerError("some issues do not exist", errors.New("some issues do not exist")) return } + for _, issue := range movedIssues { + if issue.RepoID != project.RepoID { + ctx.ServerError("Some issue's repoID is not equal to project's repoID", errors.New("Some issue's repoID is not equal to project's repoID")) + return + } + } + if err = models.MoveIssuesOnProjectBoard(board, sortedIssueIDs); err != nil { ctx.ServerError("MoveIssuesOnProjectBoard", err) return diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 6e68fd0c69..cdf130abf4 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -33,6 +33,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/routers/utils" + asymkey_service "code.gitea.io/gitea/services/asymkey" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/gitdiff" pull_service "code.gitea.io/gitea/services/pull" @@ -48,16 +49,14 @@ const ( pullRequestTemplateKey = "PullRequestTemplate" ) -var ( - pullRequestTemplateCandidates = []string{ - "PULL_REQUEST_TEMPLATE.md", - "pull_request_template.md", - ".gitea/PULL_REQUEST_TEMPLATE.md", - ".gitea/pull_request_template.md", - ".github/PULL_REQUEST_TEMPLATE.md", - ".github/pull_request_template.md", - } -) +var pullRequestTemplateCandidates = []string{ + "PULL_REQUEST_TEMPLATE.md", + "pull_request_template.md", + ".gitea/PULL_REQUEST_TEMPLATE.md", + ".gitea/pull_request_template.md", + ".github/PULL_REQUEST_TEMPLATE.md", + ".github/pull_request_template.md", +} func getRepository(ctx *context.Context, repoID int64) *repo_model.Repository { repo, err := repo_model.GetRepositoryByID(repoID) @@ -125,7 +124,7 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository { } } - var traverseParentRepo = forkRepo + traverseParentRepo := forkRepo for { if ctx.User.ID == traverseParentRepo.OwnerID { canForkToUser = false @@ -195,7 +194,7 @@ func ForkPost(ctx *context.Context) { } var err error - var traverseParentRepo = forkRepo + traverseParentRepo := forkRepo for { if ctxUser.ID == traverseParentRepo.OwnerID { ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form) @@ -392,6 +391,8 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C // PrepareViewPullInfo show meta information for a pull request preview page func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.CompareInfo { + ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes + repo := ctx.Repo.Repository pull := issue.PullRequest @@ -575,8 +576,6 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare ctx.Data["IsNothingToCompare"] = true } - ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes - if pull.IsWorkInProgress() { ctx.Data["IsPullWorkInProgress"] = true ctx.Data["WorkInProgressPrefix"] = pull.GetWorkInProgressPrefix() @@ -853,39 +852,53 @@ func MergePullRequest(ctx *context.Context) { if ctx.Written() { return } - if issue.IsClosed { - if issue.IsPull { - ctx.Flash.Error(ctx.Tr("repo.pulls.is_closed")) - ctx.Redirect(issue.Link()) - return - } - ctx.Flash.Error(ctx.Tr("repo.issues.closed_title")) - ctx.Redirect(issue.Link()) - return - } pr := issue.PullRequest + pr.Issue = issue + pr.Issue.Repo = ctx.Repo.Repository + manuallMerge := repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged + forceMerge := form.ForceMerge != nil && *form.ForceMerge - allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.Repo.Permission, ctx.User) - if err != nil { - ctx.ServerError("IsUserAllowedToMerge", err) - return - } - if !allowedMerge { - ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed")) - ctx.Redirect(issue.Link()) - return - } + if err := pull_service.CheckPullMergable(ctx, ctx.User, &ctx.Repo.Permission, pr, manuallMerge, forceMerge); err != nil { + if errors.Is(err, pull_service.ErrIsClosed) { + if issue.IsPull { + ctx.Flash.Error(ctx.Tr("repo.pulls.is_closed")) + ctx.Redirect(issue.Link()) + } else { + ctx.Flash.Error(ctx.Tr("repo.issues.closed_title")) + ctx.Redirect(issue.Link()) + } + } else if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) { + ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed")) + ctx.Redirect(issue.Link()) + } else if errors.Is(err, pull_service.ErrHasMerged) { + ctx.Flash.Error(ctx.Tr("repo.pulls.has_merged")) + ctx.Redirect(issue.Link()) + } else if errors.Is(err, pull_service.ErrIsWorkInProgress) { + ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_wip")) + ctx.Redirect(issue.Link()) + } else if errors.Is(err, pull_service.ErrNotMergableState) { + ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready")) + ctx.Redirect(issue.Link()) + } else if models.IsErrNotAllowedToMerge(err) { + ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready")) + ctx.Redirect(issue.Link()) + } else if asymkey_service.IsErrWontSign(err) { + ctx.Flash.Error(err.Error()) // has not translation ... + ctx.Redirect(issue.Link()) + } else if errors.Is(err, pull_service.ErrDependenciesLeft) { + ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked")) + ctx.Redirect(issue.Link()) + } else { + ctx.ServerError("WebCheck", err) + } - if pr.HasMerged { - ctx.Flash.Error(ctx.Tr("repo.pulls.has_merged")) - ctx.Redirect(issue.Link()) return } // handle manually-merged mark - if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged { - if err = pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil { + if manuallMerge { + if err := pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil { if models.IsErrInvalidMergeStyle(err) { ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option")) ctx.Redirect(issue.Link()) @@ -904,72 +917,13 @@ func MergePullRequest(ctx *context.Context) { return } - if !pr.CanAutoMerge() { - ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready")) - ctx.Redirect(issue.Link()) + // set defaults to propagate needed fields + if err := form.SetDefaults(pr); err != nil { + ctx.ServerError("SetDefaults", fmt.Errorf("SetDefaults: %v", err)) return } - if pr.IsWorkInProgress() { - ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_wip")) - ctx.Redirect(issue.Link()) - return - } - - if err := pull_service.CheckPRReadyToMerge(pr, false); err != nil { - if !models.IsErrNotAllowedToMerge(err) { - ctx.ServerError("Merge PR status", err) - return - } - if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.User); err != nil { - ctx.ServerError("IsUserRepoAdmin", err) - return - } else if !isRepoAdmin { - ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready")) - ctx.Redirect(issue.Link()) - return - } - } - - if ctx.HasError() { - ctx.Flash.Error(ctx.Data["ErrorMsg"].(string)) - ctx.Redirect(issue.Link()) - return - } - - message := strings.TrimSpace(form.MergeTitleField) - if len(message) == 0 { - if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleMerge { - message = pr.GetDefaultMergeMessage() - } - if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleRebaseMerge { - message = pr.GetDefaultMergeMessage() - } - if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleSquash { - message = pr.GetDefaultSquashMessage() - } - } - - form.MergeMessageField = strings.TrimSpace(form.MergeMessageField) - if len(form.MergeMessageField) > 0 { - message += "\n\n" + form.MergeMessageField - } - - pr.Issue = issue - pr.Issue.Repo = ctx.Repo.Repository - - noDeps, err := models.IssueNoDependenciesLeft(issue) - if err != nil { - return - } - - if !noDeps { - ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked")) - ctx.Redirect(issue.Link()) - return - } - - if err = pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message); err != nil { + if err := pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, form.MergeTitleField); err != nil { if models.IsErrInvalidMergeStyle(err) { ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option")) ctx.Redirect(issue.Link()) @@ -1079,7 +1033,6 @@ func MergePullRequest(ctx *context.Context) { } func stopTimerIfAvailable(user *user_model.User, issue *models.Issue) error { - if models.StopwatchExists(user.ID, issue.ID) { if err := models.CreateOrStopIssueStopwatch(user, issue); err != nil { return err diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go index 257aa737f6..383e2d6cab 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -5,6 +5,7 @@ package repo import ( + "errors" "fmt" "net/http" @@ -116,6 +117,11 @@ func UpdateResolveConversation(ctx *context.Context) { return } + if comment.Issue.RepoID != ctx.Repo.Repository.ID { + ctx.NotFound("comment's repoID is incorrect", errors.New("comment's repoID is incorrect")) + return + } + var permResult bool if permResult, err = models.CanMarkConversation(comment.Issue, ctx.User); err != nil { ctx.ServerError("CanMarkConversation", err) @@ -234,7 +240,7 @@ func SubmitReview(ctx *context.Context) { // DismissReview dismissing stale review by repo admin func DismissReview(ctx *context.Context) { form := web.GetForm(ctx).(*forms.DismissReviewForm) - comm, err := pull_service.DismissReview(form.ReviewID, form.Message, ctx.User, true) + comm, err := pull_service.DismissReview(form.ReviewID, ctx.Repo.Repository.ID, form.Message, ctx.User, true) if err != nil { ctx.ServerError("pull_service.DismissReview", err) return diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index f2ab8b85f2..781ef55455 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -98,7 +98,14 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { listOptions.PageSize = setting.API.MaxResponseItems } - tags, err := ctx.Repo.GitRepo.GetTags(listOptions.GetStartEnd()) + // TODO(20073) tags are used for compare feature witch needs all tags + // filtering is doen at the client side atm + tagListStart, tagListEnd := 0, 0 + if isTagList { + tagListStart, tagListEnd = listOptions.GetStartEnd() + } + + tags, err := ctx.Repo.GitRepo.GetTags(tagListStart, tagListEnd) if err != nil { ctx.ServerError("GetTags", err) return @@ -279,7 +286,9 @@ func NewRelease(ctx *context.Context) { } ctx.Data["tag_name"] = rel.TagName - ctx.Data["tag_target"] = rel.Target + if rel.Target != "" { + ctx.Data["tag_target"] = rel.Target + } ctx.Data["title"] = rel.Title ctx.Data["content"] = rel.Note ctx.Data["attachments"] = rel.Attachments @@ -517,7 +526,11 @@ func DeleteTag(ctx *context.Context) { func deleteReleaseOrTag(ctx *context.Context, isDelTag bool) { if err := releaseservice.DeleteReleaseByID(ctx.FormInt64("id"), ctx.User, isDelTag); err != nil { - ctx.Flash.Error("DeleteReleaseByID: " + err.Error()) + if models.IsErrProtectedTagName(err) { + ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected")) + } else { + ctx.Flash.Error("DeleteReleaseByID: " + err.Error()) + } } else { if isDelTag { ctx.Flash.Success(ctx.Tr("repo.release.deletion_tag_success")) diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go index b7269b6718..f89bffb00f 100644 --- a/routers/web/repo/setting.go +++ b/routers/web/repo/setting.go @@ -31,7 +31,6 @@ import ( "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" @@ -194,11 +193,7 @@ func SettingsPost(ctx *context.Context) { } else { ctx.Repo.Mirror.EnablePrune = form.EnablePrune ctx.Repo.Mirror.Interval = interval - if interval != 0 { - ctx.Repo.Mirror.NextUpdateUnix = timeutil.TimeStampNow().AddDuration(interval) - } else { - ctx.Repo.Mirror.NextUpdateUnix = 0 - } + ctx.Repo.Mirror.ScheduleNextUpdate() if err := repo_model.UpdateMirror(ctx.Repo.Mirror); err != nil { ctx.Data["Err_Interval"] = true ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form) diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index e8c02b64b8..adc0802404 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -465,6 +465,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st return } ctx.Data["LFSLockOwner"] = u.DisplayName() + ctx.Data["LFSLockOwnerHomeLink"] = u.HomeLink() ctx.Data["LFSLockHint"] = ctx.Tr("repo.editor.this_file_locked") } @@ -800,7 +801,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri verification := asymkey_model.ParseCommitWithSignature(latestCommit) if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) { - return models.IsUserRepoAdmin(ctx.Repo.Repository, user) + return models.IsOwnerMemberCollaborator(ctx.Repo.Repository, user.ID) }, nil); err != nil { ctx.ServerError("CalculateTrustStatus", err) return nil @@ -855,10 +856,14 @@ func renderCode(ctx *context.Context) { ctx.Data["PageIsViewCode"] = true if ctx.Repo.Repository.IsEmpty { - reallyEmpty, err := ctx.Repo.GitRepo.IsEmpty() - if err != nil { - ctx.ServerError("GitRepo.IsEmpty", err) - return + reallyEmpty := true + var err error + if ctx.Repo.GitRepo != nil { + reallyEmpty, err = ctx.Repo.GitRepo.IsEmpty() + if err != nil { + ctx.ServerError("GitRepo.IsEmpty", err) + return + } } if reallyEmpty { ctx.HTML(http.StatusOK, tplRepoEMPTY) diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index d8666c7a29..d0876f4c74 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -191,7 +191,10 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { ctx.Data["title"] = pageName ctx.Data["RequireHighlightJS"] = true - //lookup filename in wiki - get filecontent, gitTree entry , real filename + isSideBar := pageName == "_Sidebar" + isFooter := pageName == "_Footer" + + // lookup filename in wiki - get filecontent, gitTree entry , real filename data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName) if noEntry { ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages") @@ -203,23 +206,33 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { return nil, nil } - sidebarContent, _, _, _ := wikiContentsByName(ctx, commit, "_Sidebar") - if ctx.Written() { - if wikiRepo != nil { - wikiRepo.Close() + var sidebarContent []byte + if !isSideBar { + sidebarContent, _, _, _ = wikiContentsByName(ctx, commit, "_Sidebar") + if ctx.Written() { + if wikiRepo != nil { + wikiRepo.Close() + } + return nil, nil } - return nil, nil + } else { + sidebarContent = data } - footerContent, _, _, _ := wikiContentsByName(ctx, commit, "_Footer") - if ctx.Written() { - if wikiRepo != nil { - wikiRepo.Close() + var footerContent []byte + if !isFooter { + footerContent, _, _, _ = wikiContentsByName(ctx, commit, "_Footer") + if ctx.Written() { + if wikiRepo != nil { + wikiRepo.Close() + } + return nil, nil } - return nil, nil + } else { + footerContent = data } - var rctx = &markup.RenderContext{ + rctx := &markup.RenderContext{ URLPrefix: ctx.Repo.RepoLink, Metas: ctx.Repo.Repository.ComposeDocumentMetas(), IsWiki: true, @@ -236,27 +249,35 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { ctx.Data["EscapeStatus"], ctx.Data["content"] = charset.EscapeControlString(buf.String()) - buf.Reset() - if err := markdown.Render(rctx, bytes.NewReader(sidebarContent), &buf); err != nil { - if wikiRepo != nil { - wikiRepo.Close() + if !isSideBar { + buf.Reset() + if err := markdown.Render(rctx, bytes.NewReader(sidebarContent), &buf); err != nil { + if wikiRepo != nil { + wikiRepo.Close() + } + ctx.ServerError("Render", err) + return nil, nil } - ctx.ServerError("Render", err) - return nil, nil + ctx.Data["sidebarPresent"] = sidebarContent != nil + ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"] = charset.EscapeControlString(buf.String()) + } else { + ctx.Data["sidebarPresent"] = false } - ctx.Data["sidebarPresent"] = sidebarContent != nil - ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"] = charset.EscapeControlString(buf.String()) - buf.Reset() - if err := markdown.Render(rctx, bytes.NewReader(footerContent), &buf); err != nil { - if wikiRepo != nil { - wikiRepo.Close() + if !isFooter { + buf.Reset() + if err := markdown.Render(rctx, bytes.NewReader(footerContent), &buf); err != nil { + if wikiRepo != nil { + wikiRepo.Close() + } + ctx.ServerError("Render", err) + return nil, nil } - ctx.ServerError("Render", err) - return nil, nil + ctx.Data["footerPresent"] = footerContent != nil + ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"] = charset.EscapeControlString(buf.String()) + } else { + ctx.Data["footerPresent"] = false } - ctx.Data["footerPresent"] = footerContent != nil - ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"] = charset.EscapeControlString(buf.String()) // get commit count - wiki revisions commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename) @@ -290,7 +311,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name - //lookup filename in wiki - get filecontent, gitTree entry , real filename + // lookup filename in wiki - get filecontent, gitTree entry , real filename data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName) if noEntry { ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages") @@ -364,7 +385,7 @@ func renderEditPage(ctx *context.Context) { ctx.Data["title"] = pageName ctx.Data["RequireHighlightJS"] = true - //lookup filename in wiki - get filecontent, gitTree entry , real filename + // lookup filename in wiki - get filecontent, gitTree entry , real filename data, entry, _, noEntry := wikiContentsByName(ctx, commit, pageName) if noEntry { ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages") diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 367cf5ca08..7c8f018856 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -197,7 +197,7 @@ func Milestones(ctx *context.Context) { if issueReposQueryPattern.MatchString(reposQuery) { // remove "[" and "]" from string reposQuery = reposQuery[1 : len(reposQuery)-1] - //for each ID (delimiter ",") add to int to repoIDs + // for each ID (delimiter ",") add to int to repoIDs for _, rID := range strings.Split(reposQuery, ",") { // Ensure nonempty string entries @@ -350,7 +350,6 @@ func Issues(ctx *context.Context) { var issueReposQueryPattern = regexp.MustCompile(`^\[\d+(,\d+)*,?\]$`) func buildIssueOverview(ctx *context.Context, unitType unit.Type) { - // ---------------------------------------------------- // Determine user; can be either user or organization. // Return with NotFound or ServerError if unsuccessful. @@ -364,7 +363,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { var ( viewType string sortType = ctx.FormString("sort") - filterMode = models.FilterModeAll + filterMode int ) // -------------------------------------------------------------------------------- @@ -390,8 +389,10 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { filterMode = models.FilterModeMention case "review_requested": filterMode = models.FilterModeReviewRequested - case "your_repositories": // filterMode already set to All + case "your_repositories": + fallthrough default: + filterMode = models.FilterModeYourRepositories viewType = "your_repositories" } @@ -421,8 +422,33 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { User: ctx.User, } + // Search all repositories which + // + // As user: + // - Owns the repository. + // - Have collaborator permissions in repository. + // + // As org: + // - Owns the repository. + // + // As team: + // - Team org's owns the repository. + // - Team has read permission to repository. + repoOpts := &models.SearchRepoOptions{ + Actor: ctx.User, + OwnerID: ctx.User.ID, + Private: true, + AllPublic: false, + AllLimited: false, + } + + if team != nil { + repoOpts.TeamID = team.ID + } + switch filterMode { case models.FilterModeAll: + case models.FilterModeYourRepositories: case models.FilterModeAssign: opts.AssigneeID = ctx.User.ID case models.FilterModeCreate: @@ -494,7 +520,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { // Gets set when clicking filters on the issues overview page. repoIDs := getRepoIDs(ctx.FormString("repos")) if len(repoIDs) > 0 { - opts.RepoIDs = repoIDs + opts.RepoCond = builder.In("issue.repo_id", repoIDs) } // ------------------------------ @@ -562,9 +588,6 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { Org: org, Team: team, } - if len(repoIDs) > 0 { - statsOpts.RepoIDs = repoIDs - } issueStats, err = models.GetUserIssueStats(statsOpts) if err != nil { ctx.ServerError("GetUserIssueStats Shown", err) @@ -586,8 +609,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { ctx.Data["IsShowClosed"] = isShowClosed - ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = - issue_service.GetRefEndNamesAndURLs(issues, ctx.FormString("RepoLink")) + ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, ctx.FormString("RepoLink")) ctx.Data["Issues"] = issues @@ -661,7 +683,7 @@ func getRepoIDs(reposQuery string) []int64 { var repoIDs []int64 // remove "[" and "]" from string reposQuery = reposQuery[1 : len(reposQuery)-1] - //for each ID (delimiter ",") add to int to repoIDs + // for each ID (delimiter ",") add to int to repoIDs for _, rID := range strings.Split(reposQuery, ",") { // Ensure nonempty string entries if rID != "" && rID != "0" { @@ -693,8 +715,8 @@ func issueIDsFromSearch(ctxUser *user_model.User, keyword string, opts *models.I } func loadRepoByIDs(ctxUser *user_model.User, issueCountByRepo map[int64]int64, unitType unit.Type) (map[int64]*repo_model.Repository, error) { - var totalRes = make(map[int64]*repo_model.Repository, len(issueCountByRepo)) - var repoIDs = make([]int64, 0, 500) + totalRes := make(map[int64]*repo_model.Repository, len(issueCountByRepo)) + repoIDs := make([]int64, 0, 500) for id := range issueCountByRepo { if id <= 0 { continue @@ -745,7 +767,7 @@ func ShowGPGKeys(ctx *context.Context, uid int64) { if err != nil { if asymkey_model.IsErrGPGKeyImportNotExist(err) { failedEntitiesID = append(failedEntitiesID, k.KeyID) - continue //Skip previous import without backup of imported armored key + continue // Skip previous import without backup of imported armored key } ctx.ServerError("ShowGPGKeys", err) return @@ -755,12 +777,12 @@ func ShowGPGKeys(ctx *context.Context, uid int64) { var buf bytes.Buffer headers := make(map[string]string) - if len(failedEntitiesID) > 0 { //If some key need re-import to be exported + if len(failedEntitiesID) > 0 { // If some key need re-import to be exported headers["Note"] = fmt.Sprintf("The keys with the following IDs couldn't be exported and need to be reuploaded %s", strings.Join(failedEntitiesID, ", ")) } writer, _ := armor.Encode(&buf, "PGP PUBLIC KEY BLOCK", headers) for _, e := range entities { - err = e.Serialize(writer) //TODO find why key are exported with a different cipherTypeByte as original (should not be blocking but strange) + err = e.Serialize(writer) // TODO find why key are exported with a different cipherTypeByte as original (should not be blocking but strange) if err != nil { ctx.ServerError("ShowGPGKeys", err) return diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index 08cd1b8b31..282cd956ef 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) @@ -35,7 +36,7 @@ func GetNotificationCount(c *context.Context) { c.Data["NotificationUnreadCount"] = func() int64 { count, err := models.GetNotificationCount(c.User, models.NotificationStatusUnread) if err != nil { - c.ServerError("GetNotificationCount", err) + log.Error("Unable to GetNotificationCount for user:%-v: %v", c.User, err) return -1 } diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 40fc44ed14..5366a4c2cb 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -234,7 +234,7 @@ func Profile(ctx *context.Context) { ctx.Data["Keyword"] = keyword switch tab { case "followers": - items, err := user_model.GetUserFollowers(ctxUser, db.ListOptions{ + items, count, err := user_model.GetUserFollowers(ctx, ctxUser, ctx.User, db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, }) @@ -244,9 +244,9 @@ func Profile(ctx *context.Context) { } ctx.Data["Cards"] = items - total = ctxUser.NumFollowers + total = int(count) case "following": - items, err := user_model.GetUserFollowing(ctxUser, db.ListOptions{ + items, count, err := user_model.GetUserFollowing(ctx, ctxUser, ctx.User, db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, }) @@ -256,9 +256,10 @@ func Profile(ctx *context.Context) { } ctx.Data["Cards"] = items - total = ctxUser.NumFollowing + total = int(count) case "activity": - ctx.Data["Feeds"] = feed.RetrieveFeeds(ctx, models.GetFeedsOptions{RequestedUser: ctxUser, + ctx.Data["Feeds"] = feed.RetrieveFeeds(ctx, models.GetFeedsOptions{ + RequestedUser: ctxUser, Actor: ctx.User, IncludePrivate: showPrivate, OnlyPerformedBy: true, diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index b73122fa12..92290c22d6 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -35,6 +35,7 @@ func Account(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsAccount"] = true ctx.Data["Email"] = ctx.User.Email + ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail loadAccountData(ctx) @@ -106,7 +107,7 @@ func EmailPost(ctx *context.Context) { // Send activation Email if ctx.FormString("_method") == "SENDACTIVATION" { var address string - if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) { + if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.User.LowerName) { log.Error("Send activation: activation still pending") ctx.Redirect(setting.AppSubURL + "/user/settings/account") return @@ -142,8 +143,10 @@ func EmailPost(ctx *context.Context) { } address = email.Email - if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil { - log.Error("Set cache(MailResendLimit) fail: %v", err) + if setting.CacheService.Enabled { + if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language()))) ctx.Redirect(setting.AppSubURL + "/user/settings/account") @@ -188,7 +191,8 @@ func EmailPost(ctx *context.Context) { ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsAccount, &form) return - } else if user_model.IsErrEmailInvalid(err) { + } else if user_model.IsErrEmailCharIsNotSupported(err) || + user_model.IsErrEmailInvalid(err) { loadAccountData(ctx) ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsAccount, &form) @@ -201,8 +205,10 @@ func EmailPost(ctx *context.Context) { // Send confirmation email if setting.Service.RegisterEmailConfirm { mailer.SendActivateEmailMail(ctx.User, email) - if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil { - log.Error("Set cache(MailResendLimit) fail: %v", err) + if setting.CacheService.Enabled { + if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language()))) } else { @@ -270,7 +276,7 @@ func loadAccountData(ctx *context.Context) { user_model.EmailAddress CanBePrimary bool } - pendingActivation := ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) + pendingActivation := setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.User.LowerName) emails := make([]*UserEmail, len(emlist)) for i, em := range emlist { var email UserEmail diff --git a/routers/web/web.go b/routers/web/web.go index 55a64ee7d5..e18ed8f8ee 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -5,6 +5,7 @@ package web import ( + gocontext "context" "net/http" "os" "path" @@ -97,6 +98,11 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route { http.Redirect(w, req, path.Join(setting.StaticURLPrefix, "/assets/img/apple-touch-icon.png"), 301) }) + // redirect default favicon to the path of the custom favicon with a default as a fallback + routes.Get("/favicon.ico", func(w http.ResponseWriter, req *http.Request) { + http.Redirect(w, req, path.Join(setting.StaticURLPrefix, "/assets/img/favicon.png"), 301) + }) + common := []interface{}{} if setting.EnableGzip { @@ -368,8 +374,8 @@ func RegisterRoutes(m *web.Route) { m.Group("/user", func() { // r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds) - m.Get("/activate", auth.Activate, reqSignIn) - m.Post("/activate", auth.ActivatePost, reqSignIn) + m.Get("/activate", auth.Activate) + m.Post("/activate", auth.ActivatePost) m.Any("/activate_email", auth.ActivateEmail) m.Get("/avatar/{username}/{size}", user.AvatarByUserName) m.Get("/recover_account", auth.ResetPasswd) @@ -377,7 +383,7 @@ func RegisterRoutes(m *web.Route) { m.Get("/forgot_password", auth.ForgotPasswd) m.Post("/forgot_password", auth.ForgotPasswdPost) m.Post("/logout", auth.SignOut) - m.Get("/task/{task}", user.TaskStatus) + m.Get("/task/{task}", reqSignIn, user.TaskStatus) }) // ***** END: User ***** @@ -952,7 +958,25 @@ func RegisterRoutes(m *web.Route) { m.Group("/blob_excerpt", func() { m.Get("/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob) - }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) + }, func(ctx *context.Context) (cancel gocontext.CancelFunc) { + if ctx.FormBool("wiki") { + ctx.Data["PageIsWiki"] = true + repo.MustEnableWiki(ctx) + return + } + + reqRepoCodeReader(ctx) + if ctx.Written() { + return + } + cancel = context.RepoRef()(ctx) + if ctx.Written() { + return + } + + repo.MustBeNotEmpty(ctx) + return + }) m.Group("/pulls/{index}", func() { m.Get(".diff", repo.DownloadPullDiff) diff --git a/services/auth/reverseproxy.go b/services/auth/reverseproxy.go index 3e44d8b863..d2b0ab2148 100644 --- a/services/auth/reverseproxy.go +++ b/services/auth/reverseproxy.go @@ -12,6 +12,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/services/mailer" @@ -106,11 +107,15 @@ func (r *ReverseProxy) newUser(req *http.Request) *user_model.User { } user := &user_model.User{ - Name: username, - Email: email, - IsActive: true, + Name: username, + Email: email, } - if err := user_model.CreateUser(user); err != nil { + + overwriteDefault := user_model.CreateUserOverwriteOptions{ + IsActive: util.OptionalBoolTrue, + } + + if err := user_model.CreateUser(user, &overwriteDefault); err != nil { // FIXME: should I create a system notice? log.Error("CreateUser: %v", err) return nil diff --git a/services/auth/signin.go b/services/auth/signin.go index 4392e861f9..3ccf68c3a7 100644 --- a/services/auth/signin.go +++ b/services/auth/signin.go @@ -23,17 +23,22 @@ import ( // UserSignIn validates user name and password. func UserSignIn(username, password string) (*user_model.User, *auth.Source, error) { var user *user_model.User + isEmail := false if strings.Contains(username, "@") { - user = &user_model.User{Email: strings.ToLower(strings.TrimSpace(username))} + isEmail = true + emailAddress := user_model.EmailAddress{LowerEmail: strings.ToLower(strings.TrimSpace(username))} // check same email - cnt, err := db.Count(user) + has, err := db.GetEngine(db.DefaultContext).Get(&emailAddress) if err != nil { return nil, nil, err } - if cnt > 1 { - return nil, nil, user_model.ErrEmailAlreadyUsed{ - Email: user.Email, + if has { + if !emailAddress.IsActivated { + return nil, nil, user_model.ErrEmailAddressNotExist{ + Email: username, + } } + user = &user_model.User{ID: emailAddress.UID} } } else { trimmedUsername := strings.TrimSpace(username) @@ -44,38 +49,40 @@ func UserSignIn(username, password string) (*user_model.User, *auth.Source, erro user = &user_model.User{LowerName: strings.ToLower(trimmedUsername)} } - hasUser, err := user_model.GetUser(user) - if err != nil { - return nil, nil, err - } - - if hasUser { - source, err := auth.GetSourceByID(user.LoginSource) + if user != nil { + hasUser, err := user_model.GetUser(user) if err != nil { return nil, nil, err } - if !source.IsActive { - return nil, nil, oauth2.ErrAuthSourceNotActived - } + if hasUser { + source, err := auth.GetSourceByID(user.LoginSource) + if err != nil { + return nil, nil, err + } - authenticator, ok := source.Cfg.(PasswordAuthenticator) - if !ok { - return nil, nil, smtp.ErrUnsupportedLoginType - } + if !source.IsActive { + return nil, nil, oauth2.ErrAuthSourceNotActived + } - user, err := authenticator.Authenticate(user, username, password) - if err != nil { - return nil, nil, err - } + authenticator, ok := source.Cfg.(PasswordAuthenticator) + if !ok { + return nil, nil, smtp.ErrUnsupportedLoginType + } - // WARN: DON'T check user.IsActive, that will be checked on reqSign so that - // user could be hint to resend confirm email. - if user.ProhibitLogin { - return nil, nil, user_model.ErrUserProhibitLogin{UID: user.ID, Name: user.Name} - } + user, err := authenticator.Authenticate(user, user.LoginName, password) + if err != nil { + return nil, nil, err + } - return user, source, nil + // WARN: DON'T check user.IsActive, that will be checked on reqSign so that + // user could be hint to resend confirm email. + if user.ProhibitLogin { + return nil, nil, user_model.ErrUserProhibitLogin{UID: user.ID, Name: user.Name} + } + + return user, source, nil + } } sources, err := auth.AllActiveSources() @@ -110,5 +117,9 @@ func UserSignIn(username, password string) (*user_model.User, *auth.Source, erro } } + if isEmail { + return nil, nil, user_model.ErrEmailAddressNotExist{Email: username} + } + return nil, nil, user_model.ErrUserNotExist{Name: username} } diff --git a/services/auth/source/ldap/source_authenticate.go b/services/auth/source/ldap/source_authenticate.go index 52971bb87e..c5e3677a2b 100644 --- a/services/auth/source/ldap/source_authenticate.go +++ b/services/auth/source/ldap/source_authenticate.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/mailer" user_service "code.gitea.io/gitea/services/user" ) @@ -19,10 +20,14 @@ import ( // Authenticate queries if login/password is valid against the LDAP directory pool, // and create a local user if success when enabled. func (source *Source) Authenticate(user *user_model.User, userName, password string) (*user_model.User, error) { - sr := source.SearchEntry(userName, password, source.authSource.Type == auth.DLDAP) + loginName := userName + if user != nil { + loginName = user.LoginName + } + sr := source.SearchEntry(loginName, password, source.authSource.Type == auth.DLDAP) if sr == nil { // User not in LDAP, do nothing - return nil, user_model.ErrUserNotExist{Name: userName} + return nil, user_model.ErrUserNotExist{Name: loginName} } isAttributeSSHPublicKeySet := len(strings.TrimSpace(source.AttributeSSHPublicKey)) > 0 @@ -76,19 +81,21 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str } user = &user_model.User{ - LowerName: strings.ToLower(sr.Username), - Name: sr.Username, - FullName: composeFullName(sr.Name, sr.Surname, sr.Username), - Email: sr.Mail, - LoginType: source.authSource.Type, - LoginSource: source.authSource.ID, - LoginName: userName, - IsActive: true, - IsAdmin: sr.IsAdmin, - IsRestricted: sr.IsRestricted, + LowerName: strings.ToLower(sr.Username), + Name: sr.Username, + FullName: composeFullName(sr.Name, sr.Surname, sr.Username), + Email: sr.Mail, + LoginType: source.authSource.Type, + LoginSource: source.authSource.ID, + LoginName: userName, + IsAdmin: sr.IsAdmin, + } + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsRestricted: util.OptionalBoolOf(sr.IsRestricted), + IsActive: util.OptionalBoolTrue, } - err := user_model.CreateUser(user) + err := user_model.CreateUser(user, overwriteDefault) if err != nil { return user, err } diff --git a/services/auth/source/ldap/source_sync.go b/services/auth/source/ldap/source_sync.go index 78aa90aaa5..37b07cf316 100644 --- a/services/auth/source/ldap/source_sync.go +++ b/services/auth/source/ldap/source_sync.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" user_service "code.gitea.io/gitea/services/user" ) @@ -99,19 +100,21 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { log.Trace("SyncExternalUsers[%s]: Creating user %s", source.authSource.Name, su.Username) usr = &user_model.User{ - LowerName: su.LowerName, - Name: su.Username, - FullName: fullName, - LoginType: source.authSource.Type, - LoginSource: source.authSource.ID, - LoginName: su.Username, - Email: su.Mail, - IsAdmin: su.IsAdmin, - IsRestricted: su.IsRestricted, - IsActive: true, + LowerName: su.LowerName, + Name: su.Username, + FullName: fullName, + LoginType: source.authSource.Type, + LoginSource: source.authSource.ID, + LoginName: su.Username, + Email: su.Mail, + IsAdmin: su.IsAdmin, + } + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsRestricted: util.OptionalBoolOf(su.IsRestricted), + IsActive: util.OptionalBoolTrue, } - err = user_model.CreateUser(usr) + err = user_model.CreateUser(usr, overwriteDefault) if err != nil { log.Error("SyncExternalUsers[%s]: Error creating user %s: %v", source.authSource.Name, su.Username, err) @@ -143,6 +146,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { log.Trace("SyncExternalUsers[%s]: Updating user %s", source.authSource.Name, usr.Name) usr.FullName = fullName + emailChanged := usr.Email != su.Mail usr.Email = su.Mail // Change existing admin flag only if AdminFilter option is set if len(source.AdminFilter) > 0 { @@ -154,7 +158,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { } usr.IsActive = true - err = user_model.UpdateUserCols(db.DefaultContext, usr, "full_name", "email", "is_admin", "is_restricted", "is_active") + err = user_model.UpdateUser(usr, emailChanged, "full_name", "email", "is_admin", "is_restricted", "is_active") if err != nil { log.Error("SyncExternalUsers[%s]: Error updating user %s: %v", source.authSource.Name, usr.Name, err) } diff --git a/services/auth/source/oauth2/providers_simple.go b/services/auth/source/oauth2/providers_simple.go index a4d61eb2f3..39d3d74f6d 100644 --- a/services/auth/source/oauth2/providers_simple.go +++ b/services/auth/source/oauth2/providers_simple.go @@ -70,13 +70,13 @@ func init() { })) // named gplus due to legacy gplus -> google migration (Google killed Google+). This ensures old connections still work - RegisterGothProvider(NewSimpleProvider("gplus", "Google", []string{"email"}, + RegisterGothProvider(NewImagedProvider("/assets/img/auth/google.png", NewSimpleProvider("gplus", "Google", []string{"email"}, func(clientKey, secret, callbackURL string, scopes ...string) goth.Provider { if setting.OAuth2Client.UpdateAvatar || setting.OAuth2Client.EnableAutoRegistration { scopes = append(scopes, "profile") } return google.New(clientKey, secret, callbackURL, scopes...) - })) + }))) RegisterGothProvider(NewSimpleProvider("twitter", "Twitter", nil, func(clientKey, secret, callbackURL string, scopes ...string) goth.Provider { @@ -107,5 +107,4 @@ func init() { return microsoftonline.New(clientID, secret, callbackURL, scopes...) }, )) - } diff --git a/services/auth/source/pam/source_authenticate.go b/services/auth/source/pam/source_authenticate.go index d5bd940996..16ddc0598e 100644 --- a/services/auth/source/pam/source_authenticate.go +++ b/services/auth/source/pam/source_authenticate.go @@ -12,6 +12,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/pam" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/mailer" "github.com/google/uuid" @@ -58,10 +59,12 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str LoginType: auth.PAM, LoginSource: source.authSource.ID, LoginName: userName, // This is what the user typed in - IsActive: true, + } + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsActive: util.OptionalBoolTrue, } - if err := user_model.CreateUser(user); err != nil { + if err := user_model.CreateUser(user, overwriteDefault); err != nil { return user, err } diff --git a/services/auth/source/smtp/source_authenticate.go b/services/auth/source/smtp/source_authenticate.go index 3be2f1128d..dff24d494e 100644 --- a/services/auth/source/smtp/source_authenticate.go +++ b/services/auth/source/smtp/source_authenticate.go @@ -74,10 +74,12 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str LoginType: auth_model.SMTP, LoginSource: source.authSource.ID, LoginName: userName, - IsActive: true, + } + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsActive: util.OptionalBoolTrue, } - if err := user_model.CreateUser(user); err != nil { + if err := user_model.CreateUser(user, overwriteDefault); err != nil { return user, err } diff --git a/services/auth/sspi_windows.go b/services/auth/sspi_windows.go index cadf721796..55732a6be0 100644 --- a/services/auth/sspi_windows.go +++ b/services/auth/sspi_windows.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/services/auth/source/sspi" "code.gitea.io/gitea/services/mailer" @@ -187,17 +188,20 @@ func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) { func (s *SSPI) newUser(username string, cfg *sspi.Source) (*user_model.User, error) { email := gouuid.New().String() + "@localhost.localdomain" user := &user_model.User{ - Name: username, - Email: email, - KeepEmailPrivate: true, - Passwd: gouuid.New().String(), - IsActive: cfg.AutoActivateUsers, - Language: cfg.DefaultLanguage, - UseCustomAvatar: true, - Avatar: avatars.DefaultAvatarLink(), - EmailNotificationsPreference: user_model.EmailNotificationsDisabled, + Name: username, + Email: email, + Passwd: gouuid.New().String(), + Language: cfg.DefaultLanguage, + UseCustomAvatar: true, + Avatar: avatars.DefaultAvatarLink(), } - if err := user_model.CreateUser(user); err != nil { + emailNotificationPreference := user_model.EmailNotificationsDisabled + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsActive: util.OptionalBoolOf(cfg.AutoActivateUsers), + KeepEmailPrivate: util.OptionalBoolTrue, + EmailNotificationsPreference: &emailNotificationPreference, + } + if err := user_model.CreateUser(user, overwriteDefault); err != nil { return nil, err } diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 19b5a37664..e78559912e 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -582,6 +582,31 @@ func (f *MergePullRequestForm) Validate(req *http.Request, errs binding.Errors) return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } +// SetDefaults if not provided for mergestyle and commit message +func (f *MergePullRequestForm) SetDefaults(pr *models.PullRequest) (err error) { + if f.Do == "" { + f.Do = "merge" + } + + f.MergeTitleField = strings.TrimSpace(f.MergeTitleField) + if len(f.MergeTitleField) == 0 { + switch f.Do { + case "merge", "rebase-merge": + f.MergeTitleField, err = pr.GetDefaultMergeMessage() + case "squash": + f.MergeTitleField, err = pr.GetDefaultSquashMessage() + } + } + + f.MergeMessageField = strings.TrimSpace(f.MergeMessageField) + if len(f.MergeMessageField) > 0 { + f.MergeTitleField += "\n\n" + f.MergeMessageField + f.MergeMessageField = "" + } + + return +} + // CodeCommentForm form for adding code comments for PRs type CodeCommentForm struct { Origin string `binding:"Required;In(timeline,diff)"` diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index fb3e32935d..28c034fafd 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -190,9 +190,11 @@ var ( codeTagSuffix = []byte(``) ) -var unfinishedtagRegex = regexp.MustCompile(`<[^>]*$`) -var trailingSpanRegex = regexp.MustCompile(`]?$`) -var entityRegex = regexp.MustCompile(`&[#]*?[0-9[:alpha:]]*$`) +var ( + unfinishedtagRegex = regexp.MustCompile(`<[^>]*$`) + trailingSpanRegex = regexp.MustCompile(`]?$`) + entityRegex = regexp.MustCompile(`&[#]*?[0-9[:alpha:]]*$`) +) // shouldWriteInline represents combinations where we manually write inline changes func shouldWriteInline(diff diffmatchpatch.Diff, lineType DiffLineType) bool { @@ -206,7 +208,6 @@ func shouldWriteInline(diff diffmatchpatch.Diff, lineType DiffLineType) bool { } func fixupBrokenSpans(diffs []diffmatchpatch.Diff) []diffmatchpatch.Diff { - // Create a new array to store our fixed up blocks fixedup := make([]diffmatchpatch.Diff, 0, len(diffs)) @@ -658,10 +659,10 @@ func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, LastRightIdx: lastLine.RightIdx, LeftIdx: leftLineCount, RightIdx: rightLineCount, - }} + }, + } tailSection := &DiffSection{FileName: diffFile.Name, Lines: []*DiffLine{tailDiffLine}} return tailSection - } func getCommitFileLineCount(commit *git.Commit, filePath string) int { @@ -942,8 +943,8 @@ parsingLoop: // TODO: There are numerous issues with this: // - we might want to consider detecting encoding while parsing but... // - we're likely to fail to get the correct encoding here anyway as we won't have enough information - var diffLineTypeBuffers = make(map[DiffLineType]*bytes.Buffer, 3) - var diffLineTypeDecoders = make(map[DiffLineType]*encoding.Decoder, 3) + diffLineTypeBuffers := make(map[DiffLineType]*bytes.Buffer, 3) + diffLineTypeDecoders := make(map[DiffLineType]*encoding.Decoder, 3) diffLineTypeBuffers[DiffLinePlain] = new(bytes.Buffer) diffLineTypeBuffers[DiffLineAdd] = new(bytes.Buffer) diffLineTypeBuffers[DiffLineDel] = new(bytes.Buffer) @@ -1420,6 +1421,7 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff }() } defer func() { + _ = checker.Close() cancel() }() } @@ -1539,7 +1541,8 @@ func GetWhitespaceFlag(whiteSpaceBehavior string) string { "ignore-all": "-w", "ignore-change": "-b", "ignore-eol": "--ignore-space-at-eol", - "": ""} + "": "", + } return whitespaceFlags[whiteSpaceBehavior] } diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index b64ac092aa..104df96788 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -715,7 +715,8 @@ func TestDiffToHTML_14231(t *testing.T) { diffRecord := diffMatchPatch.DiffMain(highlight.Code("main.v", "", " run()\n"), highlight.Code("main.v", "", " run(db)\n"), true) diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) - expected := ` run(db)` + expected := ` run(db) +` output := diffToHTML("main.v", diffRecord, DiffLineAdd) assertEqual(t, expected, output.Content) diff --git a/services/issue/assignee.go b/services/issue/assignee.go index 4fdf0029c8..7ccefef78e 100644 --- a/services/issue/assignee.go +++ b/services/issue/assignee.go @@ -16,9 +16,10 @@ import ( // DeleteNotPassedAssignee deletes all assignees who aren't passed via the "assignees" array func DeleteNotPassedAssignee(issue *models.Issue, doer *user_model.User, assignees []*user_model.User) (err error) { var found bool + oriAssignes := make([]*user_model.User, len(issue.Assignees)) + _ = copy(oriAssignes, issue.Assignees) - for _, assignee := range issue.Assignees { - + for _, assignee := range oriAssignes { found = false for _, alreadyAssignee := range assignees { if assignee.ID == alreadyAssignee.ID { diff --git a/services/mailer/mail.go b/services/mailer/mail.go index 20552be584..7e5f531c8f 100644 --- a/services/mailer/mail.go +++ b/services/mailer/mail.go @@ -14,6 +14,7 @@ import ( "strconv" "strings" texttmpl "text/template" + "time" "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" @@ -76,8 +77,9 @@ func sendUserMail(language string, u *user_model.User, tpl base.TplName, code, s "Code": code, "Language": locale.Language(), // helper - "i18n": locale, - "Str2html": templates.Str2html, + "i18n": locale, + "Str2html": templates.Str2html, + "DotEscape": templates.DotEscape, } var content bytes.Buffer @@ -126,8 +128,9 @@ func SendActivateEmailMail(u *user_model.User, email *user_model.EmailAddress) { "Email": email.Email, "Language": locale.Language(), // helper - "i18n": locale, - "Str2html": templates.Str2html, + "i18n": locale, + "Str2html": templates.Str2html, + "DotEscape": templates.DotEscape, } var content bytes.Buffer @@ -145,8 +148,8 @@ func SendActivateEmailMail(u *user_model.User, email *user_model.EmailAddress) { // SendRegisterNotifyMail triggers a notify e-mail by admin created a account. func SendRegisterNotifyMail(u *user_model.User) { - if setting.MailService == nil { - // No mail service configured + if setting.MailService == nil || !u.IsActive { + // No mail service configured OR user is inactive return } locale := translation.NewLocale(u.Language) @@ -156,8 +159,9 @@ func SendRegisterNotifyMail(u *user_model.User) { "Username": u.Name, "Language": locale.Language(), // helper - "i18n": locale, - "Str2html": templates.Str2html, + "i18n": locale, + "Str2html": templates.Str2html, + "DotEscape": templates.DotEscape, } var content bytes.Buffer @@ -175,8 +179,8 @@ func SendRegisterNotifyMail(u *user_model.User) { // SendCollaboratorMail sends mail notification to new collaborator. func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository) { - if setting.MailService == nil { - // No mail service configured + if setting.MailService == nil || !u.IsActive { + // No mail service configured OR the user is inactive return } locale := translation.NewLocale(u.Language) @@ -189,8 +193,9 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository) "Link": repo.HTMLURL(), "Language": locale.Language(), // helper - "i18n": locale, - "Str2html": templates.Str2html, + "i18n": locale, + "Str2html": templates.Str2html, + "DotEscape": templates.DotEscape, } var content bytes.Buffer @@ -272,8 +277,9 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient "ReviewComments": reviewComments, "Language": locale.Language(), // helper - "i18n": locale, - "Str2html": templates.Str2html, + "i18n": locale, + "Str2html": templates.Str2html, + "DotEscape": templates.DotEscape, } var mailSubject bytes.Buffer @@ -297,13 +303,15 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient } // Make sure to compose independent messages to avoid leaking user emails + msgID := createReference(ctx.Issue, ctx.Comment, ctx.ActionType) + reference := createReference(ctx.Issue, nil, models.ActionType(0)) + msgs := make([]*Message, 0, len(recipients)) for _, recipient := range recipients { msg := NewMessageFrom([]string{recipient.Email}, ctx.Doer.DisplayName(), setting.MailService.FromEmail, subject, mailBody.String()) msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info) - msg.SetHeader("Message-ID", "<"+createReference(ctx.Issue, ctx.Comment)+">") - reference := createReference(ctx.Issue, nil) + msg.SetHeader("Message-ID", "<"+msgID+">") msg.SetHeader("In-Reply-To", "<"+reference+">") msg.SetHeader("References", "<"+reference+">") @@ -317,7 +325,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient return msgs, nil } -func createReference(issue *models.Issue, comment *models.Comment) string { +func createReference(issue *models.Issue, comment *models.Comment, actionType models.ActionType) string { var path string if issue.IsPull { path = "pulls" @@ -328,6 +336,17 @@ func createReference(issue *models.Issue, comment *models.Comment) string { var extra string if comment != nil { extra = fmt.Sprintf("/comment/%d", comment.ID) + } else { + switch actionType { + case models.ActionCloseIssue, models.ActionClosePullRequest: + extra = fmt.Sprintf("/close/%d", time.Now().UnixNano()/1e6) + case models.ActionReopenIssue, models.ActionReopenPullRequest: + extra = fmt.Sprintf("/reopen/%d", time.Now().UnixNano()/1e6) + case models.ActionMergePullRequest: + extra = fmt.Sprintf("/merge/%d", time.Now().UnixNano()/1e6) + case models.ActionPullRequestReadyForReview: + extra = fmt.Sprintf("/ready/%d", time.Now().UnixNano()/1e6) + } } return fmt.Sprintf("%s/%s/%d%s@%s", issue.Repo.FullName(), path, issue.Index, extra, setting.Domain) @@ -390,6 +409,10 @@ func SendIssueAssignedMail(issue *models.Issue, doer *user_model.User, content s langMap := make(map[string][]*user_model.User) for _, user := range recipients { + if !user.IsActive { + // don't send emails to inactive users + continue + } langMap[user.Language] = append(langMap[user.Language], user) } diff --git a/services/mailer/mail_issue.go b/services/mailer/mail_issue.go index c9cc2e015a..c37414df05 100644 --- a/services/mailer/mail_issue.go +++ b/services/mailer/mail_issue.go @@ -125,6 +125,10 @@ func mailIssueCommentBatch(ctx *mailCommentContext, users []*user_model.User, vi langMap := make(map[string][]*user_model.User) for _, user := range users { + if !user.IsActive { + // Exclude deactivated users + continue + } // At this point we exclude: // user that don't have all mails enabled or users only get mail on mention and this is one ... if !(user.EmailNotificationsPreference == user_model.EmailNotificationsEnabled || diff --git a/services/mailer/mail_release.go b/services/mailer/mail_release.go index ee4c6f3a59..ff0e14c47a 100644 --- a/services/mailer/mail_release.go +++ b/services/mailer/mail_release.go @@ -74,8 +74,9 @@ func mailNewRelease(lang string, tos []string, rel *models.Release) { "Subject": subject, "Language": locale.Language(), // helper - "i18n": locale, - "Str2html": templates.Str2html, + "i18n": locale, + "Str2html": templates.Str2html, + "DotEscape": templates.DotEscape, } var mailBody bytes.Buffer diff --git a/services/mailer/mail_repo.go b/services/mailer/mail_repo.go index a5343f8128..0abc666f1a 100644 --- a/services/mailer/mail_repo.go +++ b/services/mailer/mail_repo.go @@ -31,6 +31,10 @@ func SendRepoTransferNotifyMail(doer, newOwner *user_model.User, repo *repo_mode langMap := make(map[string][]string) for _, user := range users { + if !user.IsActive { + // don't send emails to inactive users + continue + } langMap[user.Language] = append(langMap[user.Language], user.Email) } @@ -69,8 +73,9 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U "Language": locale.Language(), "Destination": destination, // helper - "i18n": locale, - "Str2html": templates.Str2html, + "i18n": locale, + "Str2html": templates.Str2html, + "DotEscape": templates.DotEscape, } if err := bodyTemplates.ExecuteTemplate(&content, string(mailRepoTransferNotify), data); err != nil { diff --git a/services/mailer/mail_test.go b/services/mailer/mail_test.go index 6a175337ad..753c7adb7b 100644 --- a/services/mailer/mail_test.go +++ b/services/mailer/mail_test.go @@ -6,7 +6,9 @@ package mailer import ( "bytes" + "fmt" "html/template" + "strings" "testing" texttmpl "text/template" @@ -15,7 +17,6 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" - "github.com/stretchr/testify/assert" ) @@ -236,3 +237,115 @@ func TestGenerateAdditionalHeaders(t *testing.T) { } } } + +func Test_createReference(t *testing.T) { + _, _, issue, comment := prepareMailerTest(t) + _, _, pullIssue, _ := prepareMailerTest(t) + pullIssue.IsPull = true + + type args struct { + issue *models.Issue + comment *models.Comment + actionType models.ActionType + } + tests := []struct { + name string + args args + prefix string + suffix string + }{ + { + name: "Open Issue", + args: args{ + issue: issue, + actionType: models.ActionCreateIssue, + }, + prefix: fmt.Sprintf("%s/issues/%d@%s", issue.Repo.FullName(), issue.Index, setting.Domain), + }, + { + name: "Open Pull", + args: args{ + issue: pullIssue, + actionType: models.ActionCreatePullRequest, + }, + prefix: fmt.Sprintf("%s/pulls/%d@%s", issue.Repo.FullName(), issue.Index, setting.Domain), + }, + { + name: "Comment Issue", + args: args{ + issue: issue, + comment: comment, + actionType: models.ActionCommentIssue, + }, + prefix: fmt.Sprintf("%s/issues/%d/comment/%d@%s", issue.Repo.FullName(), issue.Index, comment.ID, setting.Domain), + }, + { + name: "Comment Pull", + args: args{ + issue: pullIssue, + comment: comment, + actionType: models.ActionCommentPull, + }, + prefix: fmt.Sprintf("%s/pulls/%d/comment/%d@%s", issue.Repo.FullName(), issue.Index, comment.ID, setting.Domain), + }, + { + name: "Close Issue", + args: args{ + issue: issue, + actionType: models.ActionCloseIssue, + }, + prefix: fmt.Sprintf("%s/issues/%d/close/", issue.Repo.FullName(), issue.Index), + }, + { + name: "Close Pull", + args: args{ + issue: pullIssue, + actionType: models.ActionClosePullRequest, + }, + prefix: fmt.Sprintf("%s/pulls/%d/close/", issue.Repo.FullName(), issue.Index), + }, + { + name: "Reopen Issue", + args: args{ + issue: issue, + actionType: models.ActionReopenIssue, + }, + prefix: fmt.Sprintf("%s/issues/%d/reopen/", issue.Repo.FullName(), issue.Index), + }, + { + name: "Reopen Pull", + args: args{ + issue: pullIssue, + actionType: models.ActionReopenPullRequest, + }, + prefix: fmt.Sprintf("%s/pulls/%d/reopen/", issue.Repo.FullName(), issue.Index), + }, + { + name: "Merge Pull", + args: args{ + issue: pullIssue, + actionType: models.ActionMergePullRequest, + }, + prefix: fmt.Sprintf("%s/pulls/%d/merge/", issue.Repo.FullName(), issue.Index), + }, + { + name: "Ready Pull", + args: args{ + issue: pullIssue, + actionType: models.ActionPullRequestReadyForReview, + }, + prefix: fmt.Sprintf("%s/pulls/%d/ready/", issue.Repo.FullName(), issue.Index), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := createReference(tt.args.issue, tt.args.comment, tt.args.actionType) + if !strings.HasPrefix(got, tt.prefix) { + t.Errorf("createReference() = %v, want %v", got, tt.prefix) + } + if !strings.HasSuffix(got, tt.suffix) { + t.Errorf("createReference() = %v, want %v", got, tt.prefix) + } + }) + } +} diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go index e5e6272f10..dfb7bab998 100644 --- a/services/mailer/mailer.go +++ b/services/mailer/mailer.go @@ -284,6 +284,7 @@ func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error { if err != nil { return err } + process.SetSysProcAttribute(cmd) if err = cmd.Start(); err != nil { _ = pipe.Close() diff --git a/services/migrations/dump.go b/services/migrations/dump.go index 1a8a3d296c..9a7aac82ab 100644 --- a/services/migrations/dump.go +++ b/services/migrations/dump.go @@ -22,14 +22,13 @@ import ( "code.gitea.io/gitea/modules/log" base "code.gitea.io/gitea/modules/migration" "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "gopkg.in/yaml.v2" ) -var ( - _ base.Uploader = &RepositoryDumper{} -) +var _ base.Uploader = &RepositoryDumper{} // RepositoryDumper implements an Uploader to the local directory type RepositoryDumper struct { @@ -151,9 +150,10 @@ func (g *RepositoryDumper) CreateRepo(repo *base.Repository, opts base.MigrateOp } err = git.Clone(remoteAddr, repoPath, git.CloneRepoOptions{ - Mirror: true, - Quiet: true, - Timeout: migrateTimeout, + Mirror: true, + Quiet: true, + Timeout: migrateTimeout, + SkipTLSVerify: setting.Migrations.SkipTLSVerify, }) if err != nil { return fmt.Errorf("Clone: %v", err) @@ -168,10 +168,11 @@ func (g *RepositoryDumper) CreateRepo(repo *base.Repository, opts base.MigrateOp } if err := git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{ - Mirror: true, - Quiet: true, - Timeout: migrateTimeout, - Branch: "master", + Mirror: true, + Quiet: true, + Timeout: migrateTimeout, + Branch: "master", + SkipTLSVerify: setting.Migrations.SkipTLSVerify, }); err != nil { log.Warn("Clone wiki: %v", err) if err := os.RemoveAll(wikiPath); err != nil { @@ -403,7 +404,7 @@ func (g *RepositoryDumper) createItems(dir string, itemFiles map[int64]*os.File, // CreateComments creates comments of issues func (g *RepositoryDumper) CreateComments(comments ...*base.Comment) error { - var commentsMap = make(map[int64][]interface{}, len(comments)) + commentsMap := make(map[int64][]interface{}, len(comments)) for _, comment := range comments { commentsMap[comment.IssueIndex] = append(commentsMap[comment.IssueIndex], comment) } @@ -532,7 +533,7 @@ func (g *RepositoryDumper) CreatePullRequests(prs ...*base.PullRequest) error { // CreateReviews create pull request reviews func (g *RepositoryDumper) CreateReviews(reviews ...*base.Review) error { - var reviewsMap = make(map[int64][]interface{}, len(reviews)) + reviewsMap := make(map[int64][]interface{}, len(reviews)) for _, review := range reviews { reviewsMap[review.IssueIndex] = append(reviewsMap[review.IssueIndex], review) } @@ -611,7 +612,7 @@ func RestoreRepository(ctx context.Context, baseDir, ownerName, repoName string, if err != nil { return err } - var uploader = NewGiteaLocalUploader(ctx, doer, ownerName, repoName) + uploader := NewGiteaLocalUploader(ctx, doer, ownerName, repoName) downloader, err := NewRepositoryRestorer(ctx, baseDir, ownerName, repoName) if err != nil { return err @@ -622,7 +623,7 @@ func RestoreRepository(ctx context.Context, baseDir, ownerName, repoName string, } tp, _ := strconv.Atoi(opts["service_type"]) - var migrateOpts = base.MigrateOptions{ + migrateOpts := base.MigrateOptions{ GitServiceType: structs.GitServiceType(tp), } updateOptionsUnits(&migrateOpts, units) diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index 035ca2e5a2..debe172414 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -7,6 +7,7 @@ package migrations import ( "context" + "errors" "fmt" "io" "os" @@ -33,9 +34,7 @@ import ( gouuid "github.com/google/uuid" ) -var ( - _ base.Uploader = &GiteaLocalUploader{} -) +var _ base.Uploader = &GiteaLocalUploader{} // GiteaLocalUploader implements an Uploader to gitea sites type GiteaLocalUploader struct { @@ -159,7 +158,7 @@ func (g *GiteaLocalUploader) CreateTopics(topics ...string) error { // CreateMilestones creates milestones func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) error { - var mss = make([]*models.Milestone, 0, len(milestones)) + mss := make([]*models.Milestone, 0, len(milestones)) for _, milestone := range milestones { var deadline timeutil.TimeStamp if milestone.Deadline != nil { @@ -182,7 +181,7 @@ func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) err milestone.Updated = &milestone.Created } - var ms = models.Milestone{ + ms := models.Milestone{ RepoID: g.repo.ID, Name: milestone.Title, Content: milestone.Description, @@ -210,7 +209,7 @@ func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) err // CreateLabels creates labels func (g *GiteaLocalUploader) CreateLabels(labels ...*base.Label) error { - var lbs = make([]*models.Label, 0, len(labels)) + lbs := make([]*models.Label, 0, len(labels)) for _, label := range labels { lbs = append(lbs, &models.Label{ RepoID: g.repo.ID, @@ -232,7 +231,7 @@ func (g *GiteaLocalUploader) CreateLabels(labels ...*base.Label) error { // CreateReleases creates releases func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error { - var rels = make([]*models.Release, 0, len(releases)) + rels := make([]*models.Release, 0, len(releases)) for _, release := range releases { if release.Created.IsZero() { if !release.Published.IsZero() { @@ -242,13 +241,12 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error { } } - var rel = models.Release{ + rel := models.Release{ RepoID: g.repo.ID, TagName: release.TagName, LowerTagName: strings.ToLower(release.TagName), Target: release.TargetCommitish, Title: release.Name, - Sha1: release.TargetCommitish, Note: release.Body, IsDraft: release.Draft, IsPrerelease: release.Prerelease, @@ -277,15 +275,18 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error { rel.OriginalAuthorID = release.PublisherID } - // calc NumCommits if no draft - if !release.Draft { + // calc NumCommits if possible + if rel.TagName != "" { commit, err := g.gitRepo.GetTagCommit(rel.TagName) - if err != nil { - return fmt.Errorf("GetTagCommit[%v]: %v", rel.TagName, err) - } - rel.NumCommits, err = commit.CommitsCount() - if err != nil { - return fmt.Errorf("CommitsCount: %v", err) + if !errors.Is(err, git.ErrNotExist{}) { + if err != nil { + return fmt.Errorf("GetTagCommit[%v]: %v", rel.TagName, err) + } + rel.Sha1 = commit.ID.String() + rel.NumCommits, err = commit.CommitsCount() + if err != nil { + return fmt.Errorf("CommitsCount: %v", err) + } } } @@ -297,7 +298,7 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error { asset.Created = release.Created } } - var attach = repo_model.Attachment{ + attach := repo_model.Attachment{ UUID: gouuid.New().String(), Name: asset.Name, DownloadCount: int64(*asset.DownloadCount), @@ -348,7 +349,7 @@ func (g *GiteaLocalUploader) SyncTags() error { // CreateIssues creates issues func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { - var iss = make([]*models.Issue, 0, len(issues)) + iss := make([]*models.Issue, 0, len(issues)) for _, issue := range issues { var labels []*models.Label for _, label := range issue.Labels { @@ -381,7 +382,7 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { } } - var is = models.Issue{ + is := models.Issue{ RepoID: g.repo.ID, Repo: g.repo, Index: issue.Number, @@ -433,7 +434,7 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { g.userMap[reaction.UserID] = userid } } - var res = models.Reaction{ + res := models.Reaction{ Type: reaction.Content, CreatedUnix: timeutil.TimeStampNow(), } @@ -464,7 +465,7 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { // CreateComments creates comments of issues func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { - var cms = make([]*models.Comment, 0, len(comments)) + cms := make([]*models.Comment, 0, len(comments)) for _, comment := range comments { var issue *models.Issue issueInter, ok := g.issues.Load(comment.IssueIndex) @@ -528,7 +529,7 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { g.userMap[reaction.UserID] = userid } } - var res = models.Reaction{ + res := models.Reaction{ Type: reaction.Content, CreatedUnix: timeutil.TimeStampNow(), } @@ -553,7 +554,7 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { // CreatePullRequests creates pull requests func (g *GiteaLocalUploader) CreatePullRequests(prs ...*base.PullRequest) error { - var gprs = make([]*models.PullRequest, 0, len(prs)) + gprs := make([]*models.PullRequest, 0, len(prs)) for _, pr := range prs { gpr, err := g.newPullRequest(pr) if err != nil { @@ -652,7 +653,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR return nil, err } - var head = "unknown repository" + head := "unknown repository" if pr.IsForkPullRequest() && pr.State != "closed" { if pr.Head.OwnerName != "" { remote := pr.Head.OwnerName @@ -669,7 +670,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR } if ok { - _, err = git.NewCommand("fetch", remote, pr.Head.Ref).RunInDir(g.repo.RepoPath()) + _, err = git.NewCommandContext(g.ctx, "fetch", "--no-tags", "--", remote, pr.Head.Ref).RunInDir(g.repo.RepoPath()) if err != nil { log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err) } else { @@ -723,7 +724,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR pr.Updated = pr.Created } - var issue = models.Issue{ + issue := models.Issue{ RepoID: g.repo.ID, Repo: g.repo, Title: pr.Title, @@ -773,7 +774,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR g.userMap[reaction.UserID] = userid } } - var res = models.Reaction{ + res := models.Reaction{ Type: reaction.Content, CreatedUnix: timeutil.TimeStampNow(), } @@ -787,7 +788,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR issue.Reactions = append(issue.Reactions, &res) } - var pullRequest = models.PullRequest{ + pullRequest := models.PullRequest{ HeadRepoID: g.repo.ID, HeadBranch: head, BaseRepoID: g.repo.ID, @@ -830,7 +831,7 @@ func convertReviewState(state string) models.ReviewType { // CreateReviews create pull request reviews func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error { - var cms = make([]*models.Review, 0, len(reviews)) + cms := make([]*models.Review, 0, len(reviews)) for _, review := range reviews { var issue *models.Issue issueInter, ok := g.issues.Load(review.IssueIndex) @@ -862,7 +863,7 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error { review.CreatedAt = time.Unix(int64(issue.CreatedUnix), 0) } - var cm = models.Review{ + cm := models.Review{ Type: convertReviewState(review.State), IssueID: issue.ID, Content: review.Content, @@ -926,7 +927,7 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error { comment.UpdatedAt = comment.CreatedAt } - var c = models.Comment{ + c := models.Comment{ Type: models.CommentTypeCode, PosterID: comment.PosterID, IssueID: issue.ID, diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index 7d4f77eac8..ed3e32952c 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -97,7 +97,7 @@ func TestGiteaUploadRepo(t *testing.T) { assert.Len(t, releases, 1) issues, err := models.Issues(&models.IssuesOptions{ - RepoIDs: []int64{repo.ID}, + RepoID: repo.ID, IsPull: util.OptionalBoolFalse, SortType: "oldest", }) diff --git a/services/migrations/gitlab.go b/services/migrations/gitlab.go index 4eb7e3e47c..97ebc4dd8b 100644 --- a/services/migrations/gitlab.go +++ b/services/migrations/gitlab.go @@ -32,8 +32,7 @@ func init() { } // GitlabDownloaderFactory defines a gitlab downloader factory -type GitlabDownloaderFactory struct { -} +type GitlabDownloaderFactory struct{} // New returns a Downloader related to this factory according MigrateOptions func (f *GitlabDownloaderFactory) New(ctx context.Context, opts base.MigrateOptions) (base.Downloader, error) { @@ -184,16 +183,17 @@ func (g *GitlabDownloader) GetTopics() ([]string, error) { // GetMilestones returns milestones func (g *GitlabDownloader) GetMilestones() ([]*base.Milestone, error) { - var perPage = g.maxPerPage - var state = "all" - var milestones = make([]*base.Milestone, 0, perPage) + perPage := g.maxPerPage + state := "all" + milestones := make([]*base.Milestone, 0, perPage) for i := 1; ; i++ { ms, _, err := g.client.Milestones.ListMilestones(g.repoID, &gitlab.ListMilestonesOptions{ State: &state, ListOptions: gitlab.ListOptions{ Page: i, PerPage: perPage, - }}, nil, gitlab.WithContext(g.ctx)) + }, + }, nil, gitlab.WithContext(g.ctx)) if err != nil { return nil, err } @@ -203,7 +203,7 @@ func (g *GitlabDownloader) GetMilestones() ([]*base.Milestone, error) { if m.Description != "" { desc = m.Description } - var state = "open" + state := "open" var closedAt *time.Time if m.State != "" { state = m.State @@ -255,8 +255,8 @@ func (g *GitlabDownloader) normalizeColor(val string) string { // GetLabels returns labels func (g *GitlabDownloader) GetLabels() ([]*base.Label, error) { - var perPage = g.maxPerPage - var labels = make([]*base.Label, 0, perPage) + perPage := g.maxPerPage + labels := make([]*base.Label, 0, perPage) for i := 1; ; i++ { ls, _, err := g.client.Labels.ListLabels(g.repoID, &gitlab.ListLabelsOptions{ListOptions: gitlab.ListOptions{ Page: i, @@ -327,8 +327,8 @@ func (g *GitlabDownloader) convertGitlabRelease(rel *gitlab.Release) *base.Relea // GetReleases returns releases func (g *GitlabDownloader) GetReleases() ([]*base.Release, error) { - var perPage = g.maxPerPage - var releases = make([]*base.Release, 0, perPage) + perPage := g.maxPerPage + releases := make([]*base.Release, 0, perPage) for i := 1; ; i++ { ls, _, err := g.client.Releases.ListReleases(g.repoID, &gitlab.ListReleasesOptions{ Page: i, @@ -381,7 +381,7 @@ func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, er }, } - var allIssues = make([]*base.Issue, 0, perPage) + allIssues := make([]*base.Issue, 0, perPage) issues, _, err := g.client.Issues.ListProjectIssues(g.repoID, opt, nil, gitlab.WithContext(g.ctx)) if err != nil { @@ -389,7 +389,7 @@ func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, er } for _, issue := range issues { - var labels = make([]*base.Label, 0, len(issue.Labels)) + labels := make([]*base.Label, 0, len(issue.Labels)) for _, l := range issue.Labels { labels = append(labels, &base.Label{ Name: l, @@ -402,7 +402,7 @@ func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, er } var reactions []*base.Reaction - var awardPage = 1 + awardPage := 1 for { awards, _, err := g.client.AwardEmoji.ListIssueAwardEmoji(g.repoID, issue.IID, &gitlab.ListAwardEmojiOptions{Page: awardPage, PerPage: perPage}, gitlab.WithContext(g.ctx)) if err != nil { @@ -456,9 +456,9 @@ func (g *GitlabDownloader) GetComments(opts base.GetCommentOptions) ([]*base.Com return nil, false, fmt.Errorf("unexpected context: %+v", opts.Context) } - var allComments = make([]*base.Comment, 0, g.maxPerPage) + allComments := make([]*base.Comment, 0, g.maxPerPage) - var page = 1 + page := 1 for { var comments []*gitlab.Discussion @@ -503,7 +503,6 @@ func (g *GitlabDownloader) GetComments(opts base.GetCommentOptions) ([]*base.Com Created: *c.CreatedAt, }) } - } if resp.NextPage == 0 { break @@ -526,7 +525,7 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque }, } - var allPRs = make([]*base.PullRequest, 0, perPage) + allPRs := make([]*base.PullRequest, 0, perPage) prs, _, err := g.client.MergeRequests.ListProjectMergeRequests(g.repoID, opt, nil, gitlab.WithContext(g.ctx)) if err != nil { @@ -534,7 +533,7 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque } for _, pr := range prs { - var labels = make([]*base.Label, 0, len(pr.Labels)) + labels := make([]*base.Label, 0, len(pr.Labels)) for _, l := range pr.Labels { labels = append(labels, &base.Label{ Name: l, @@ -547,12 +546,12 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque pr.State = "closed" } - var mergeTime = pr.MergedAt + mergeTime := pr.MergedAt if merged && pr.MergedAt == nil { mergeTime = pr.UpdatedAt } - var closeTime = pr.ClosedAt + closeTime := pr.ClosedAt if merged && pr.ClosedAt == nil { closeTime = pr.UpdatedAt } @@ -568,7 +567,7 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque } var reactions []*base.Reaction - var awardPage = 1 + awardPage := 1 for { awards, _, err := g.client.AwardEmoji.ListMergeRequestAwardEmoji(g.repoID, pr.IID, &gitlab.ListAwardEmojiOptions{Page: awardPage, PerPage: perPage}, gitlab.WithContext(g.ctx)) if err != nil { @@ -641,13 +640,22 @@ func (g *GitlabDownloader) GetReviews(context base.IssueContext) ([]*base.Review return nil, err } - var reviews = make([]*base.Review, 0, len(approvals.ApprovedBy)) + var createdAt time.Time + if approvals.CreatedAt != nil { + createdAt = *approvals.CreatedAt + } else if approvals.UpdatedAt != nil { + createdAt = *approvals.UpdatedAt + } else { + createdAt = time.Now() + } + + reviews := make([]*base.Review, 0, len(approvals.ApprovedBy)) for _, user := range approvals.ApprovedBy { reviews = append(reviews, &base.Review{ IssueIndex: context.LocalID(), ReviewerID: int64(user.User.ID), ReviewerName: user.User.Username, - CreatedAt: *approvals.UpdatedAt, + CreatedAt: createdAt, // All we get are approvals State: base.ReviewStateApproved, }) diff --git a/services/migrations/gitlab_test.go b/services/migrations/gitlab_test.go index 6b77aa62ef..ad61577653 100644 --- a/services/migrations/gitlab_test.go +++ b/services/migrations/gitlab_test.go @@ -8,13 +8,16 @@ import ( "context" "fmt" "net/http" + "net/http/httptest" "os" + "strconv" "testing" "time" base "code.gitea.io/gitea/modules/migration" "github.com/stretchr/testify/assert" + "github.com/xanzy/go-gitlab" ) func TestGitlabDownloadRepo(t *testing.T) { @@ -310,12 +313,14 @@ func TestGitlabDownloadRepo(t *testing.T) { assert.NoError(t, err) assertReviewsEqual(t, []*base.Review{ { + IssueIndex: 1, ReviewerID: 4102996, ReviewerName: "zeripath", CreatedAt: time.Date(2019, 11, 28, 16, 2, 8, 377000000, time.UTC), State: "APPROVED", }, { + IssueIndex: 1, ReviewerID: 527793, ReviewerName: "axifive", CreatedAt: time.Date(2019, 11, 28, 16, 2, 8, 377000000, time.UTC), @@ -327,6 +332,7 @@ func TestGitlabDownloadRepo(t *testing.T) { assert.NoError(t, err) assertReviewsEqual(t, []*base.Review{ { + IssueIndex: 2, ReviewerID: 4575606, ReviewerName: "real6543", CreatedAt: time.Date(2020, 4, 19, 19, 24, 21, 108000000, time.UTC), @@ -334,3 +340,137 @@ func TestGitlabDownloadRepo(t *testing.T) { }, }, rvs) } + +func gitlabClientMockSetup(t *testing.T) (*http.ServeMux, *httptest.Server, *gitlab.Client) { + // mux is the HTTP request multiplexer used with the test server. + mux := http.NewServeMux() + + // server is a test HTTP server used to provide mock API responses. + server := httptest.NewServer(mux) + + // client is the Gitlab client being tested. + client, err := gitlab.NewClient("", gitlab.WithBaseURL(server.URL)) + if err != nil { + server.Close() + t.Fatalf("Failed to create client: %v", err) + } + + return mux, server, client +} + +func gitlabClientMockTeardown(server *httptest.Server) { + server.Close() +} + +type reviewTestCase struct { + repoID, prID, reviewerID int + reviewerName string + createdAt, updatedAt *time.Time + expectedCreatedAt time.Time +} + +func convertTestCase(t reviewTestCase) (func(w http.ResponseWriter, r *http.Request), base.Review) { + var updatedAtField string + if t.updatedAt == nil { + updatedAtField = "" + } else { + updatedAtField = `"updated_at": "` + t.updatedAt.Format(time.RFC3339) + `",` + } + + var createdAtField string + if t.createdAt == nil { + createdAtField = "" + } else { + createdAtField = `"created_at": "` + t.createdAt.Format(time.RFC3339) + `",` + } + + handler := func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, ` +{ + "id": 5, + "iid": `+strconv.Itoa(t.prID)+`, + "project_id": `+strconv.Itoa(t.repoID)+`, + "title": "Approvals API", + "description": "Test", + "state": "opened", + `+createdAtField+` + `+updatedAtField+` + "merge_status": "cannot_be_merged", + "approvals_required": 2, + "approvals_left": 1, + "approved_by": [ + { + "user": { + "name": "Administrator", + "username": "`+t.reviewerName+`", + "id": `+strconv.Itoa(t.reviewerID)+`, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url": "http://localhost:3000/root" + } + } + ] +}`) + } + review := base.Review{ + IssueIndex: int64(t.prID), + ReviewerID: int64(t.reviewerID), + ReviewerName: t.reviewerName, + CreatedAt: t.expectedCreatedAt, + State: "APPROVED", + } + + return handler, review +} + +func TestGitlabGetReviews(t *testing.T) { + mux, server, client := gitlabClientMockSetup(t) + defer gitlabClientMockTeardown(server) + + repoID := 1324 + + downloader := &GitlabDownloader{ + ctx: context.Background(), + client: client, + repoID: repoID, + } + + createdAt := time.Date(2020, 4, 19, 19, 24, 21, 0, time.UTC) + + for _, testCase := range []reviewTestCase{ + { + repoID: repoID, + prID: 1, + reviewerID: 801, + reviewerName: "someone1", + createdAt: nil, + updatedAt: &createdAt, + expectedCreatedAt: createdAt, + }, + { + repoID: repoID, + prID: 2, + reviewerID: 802, + reviewerName: "someone2", + createdAt: &createdAt, + updatedAt: nil, + expectedCreatedAt: createdAt, + }, + { + repoID: repoID, + prID: 3, + reviewerID: 803, + reviewerName: "someone3", + createdAt: nil, + updatedAt: nil, + expectedCreatedAt: time.Now(), + }, + } { + mock, review := convertTestCase(testCase) + mux.HandleFunc(fmt.Sprintf("/api/v4/projects/%d/merge_requests/%d/approvals", testCase.repoID, testCase.prID), mock) + + rvs, err := downloader.GetReviews(base.BasicIssueContext(testCase.prID)) + assert.NoError(t, err) + assertReviewsEqual(t, []*base.Review{&review}, rvs) + } +} diff --git a/services/migrations/main_test.go b/services/migrations/main_test.go index ddf73df98e..b040df83d1 100644 --- a/services/migrations/main_test.go +++ b/services/migrations/main_test.go @@ -223,15 +223,15 @@ func assertRepositoryEqual(t *testing.T, expected, actual *base.Repository) { } func assertReviewEqual(t *testing.T, expected, actual *base.Review) { - assert.Equal(t, expected.ID, actual.ID) - assert.Equal(t, expected.IssueIndex, actual.IssueIndex) - assert.Equal(t, expected.ReviewerID, actual.ReviewerID) - assert.Equal(t, expected.ReviewerName, actual.ReviewerName) - assert.Equal(t, expected.Official, actual.Official) - assert.Equal(t, expected.CommitID, actual.CommitID) - assert.Equal(t, expected.Content, actual.Content) - assertTimeEqual(t, expected.CreatedAt, actual.CreatedAt) - assert.Equal(t, expected.State, actual.State) + assert.Equal(t, expected.ID, actual.ID, "ID") + assert.Equal(t, expected.IssueIndex, actual.IssueIndex, "IsssueIndex") + assert.Equal(t, expected.ReviewerID, actual.ReviewerID, "ReviewerID") + assert.Equal(t, expected.ReviewerName, actual.ReviewerName, "ReviewerName") + assert.Equal(t, expected.Official, actual.Official, "Official") + assert.Equal(t, expected.CommitID, actual.CommitID, "CommitID") + assert.Equal(t, expected.Content, actual.Content, "Content") + assert.WithinDuration(t, expected.CreatedAt, actual.CreatedAt, 10*time.Second) + assert.Equal(t, expected.State, actual.State, "State") assertReviewCommentsEqual(t, expected.Comments, actual.Comments) } diff --git a/services/migrations/migrate.go b/services/migrations/migrate.go index 65ecceddbe..c07edfb8c0 100644 --- a/services/migrations/migrate.go +++ b/services/migrations/migrate.go @@ -81,10 +81,9 @@ func IsMigrateURLAllowed(remoteURL string, doer *user_model.User) error { err = nil //nolint hostName = u.Host } - addrList, err := net.LookupIP(hostName) - if err != nil { - return &models.ErrInvalidCloneAddr{Host: u.Host, NotResolvedIP: true} - } + + // some users only use proxy, there is no DNS resolver. it's safe to ignore the LookupIP error + addrList, _ := net.LookupIP(hostName) var ipAllowed bool var ipBlocked bool diff --git a/services/migrations/restore.go b/services/migrations/restore.go index 357e995423..d7f3b76c2d 100644 --- a/services/migrations/restore.go +++ b/services/migrations/restore.go @@ -97,6 +97,9 @@ func (r *RepositoryRestorer) GetTopics() ([]string, error) { bs, err := os.ReadFile(p) if err != nil { + if os.IsNotExist(err) { + return nil, nil + } return nil, err } diff --git a/services/mirror/mirror.go b/services/mirror/mirror.go index 2643200174..ac8d72906b 100644 --- a/services/mirror/mirror.go +++ b/services/mirror/mirror.go @@ -29,19 +29,23 @@ const ( // SyncRequest for the mirror queue type SyncRequest struct { - Type SyncType - RepoID int64 + Type SyncType + ReferenceID int64 // RepoID for pull mirror, MirrorID fro push mirror } // doMirrorSync causes this request to mirror itself func doMirrorSync(ctx context.Context, req *SyncRequest) { + if req.ReferenceID == 0 { + log.Warn("Skipping mirror sync request, no reference ID was specified") + return + } switch req.Type { case PushMirrorType: - _ = SyncPushMirror(ctx, req.RepoID) + _ = SyncPushMirror(ctx, req.ReferenceID) case PullMirrorType: - _ = SyncPullMirror(ctx, req.RepoID) + _ = SyncPullMirror(ctx, req.ReferenceID) default: - log.Error("Unknown Request type in queue: %v for RepoID[%d]", req.Type, req.RepoID) + log.Error("Unknown Request type in queue: %v for ReferenceID[%d]", req.Type, req.ReferenceID) } } @@ -59,23 +63,26 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { handler := func(idx int, bean interface{}, limit int) error { var item SyncRequest + var repo *repo_model.Repository if m, ok := bean.(*repo_model.Mirror); ok { if m.Repo == nil { log.Error("Disconnected mirror found: %d", m.ID) return nil } + repo = m.Repo item = SyncRequest{ - Type: PullMirrorType, - RepoID: m.RepoID, + Type: PullMirrorType, + ReferenceID: m.RepoID, } } else if m, ok := bean.(*repo_model.PushMirror); ok { if m.Repo == nil { log.Error("Disconnected push-mirror found: %d", m.ID) return nil } + repo = m.Repo item = SyncRequest{ - Type: PushMirrorType, - RepoID: m.RepoID, + Type: PushMirrorType, + ReferenceID: m.ID, } } else { log.Error("Unknown bean: %v", bean) @@ -89,17 +96,16 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { default: } - // Check if this request is already in the queue - has, err := mirrorQueue.Has(&item) - if err != nil { - return err - } - if has { - return nil - } - // Push to the Queue if err := mirrorQueue.Push(&item); err != nil { + if err == queue.ErrAlreadyInQueue { + if item.Type == PushMirrorType { + log.Trace("PushMirrors for %-v already queued for sync", repo) + } else { + log.Trace("PullMirrors for %-v already queued for sync", repo) + } + return nil + } return err } @@ -110,23 +116,29 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { return nil } + pullMirrorsRequested := 0 if pullLimit != 0 { + requested = 0 if err := repo_model.MirrorsIterate(func(idx int, bean interface{}) error { return handler(idx, bean, pullLimit) }); err != nil && err != errLimit { log.Error("MirrorsIterate: %v", err) return err } + pullMirrorsRequested, requested = requested, 0 } + pushMirrorsRequested := 0 if pushLimit != 0 { + requested = 0 if err := repo_model.PushMirrorsIterate(func(idx int, bean interface{}) error { return handler(idx, bean, pushLimit) }); err != nil && err != errLimit { log.Error("PushMirrorsIterate: %v", err) return err } + pushMirrorsRequested, requested = requested, 0 } - log.Trace("Finished: Update") + log.Trace("Finished: Update: %d pull mirrors and %d push mirrors queued", pullMirrorsRequested, pushMirrorsRequested) return nil } @@ -154,8 +166,8 @@ func StartToMirror(repoID int64) { } go func() { err := mirrorQueue.Push(&SyncRequest{ - Type: PullMirrorType, - RepoID: repoID, + Type: PullMirrorType, + ReferenceID: repoID, }) if err != nil { log.Error("Unable to push sync request for to the queue for push mirror repo[%d]: Error: %v", repoID, err) @@ -170,8 +182,8 @@ func AddPushMirrorToQueue(mirrorID int64) { } go func() { err := mirrorQueue.Push(&SyncRequest{ - Type: PushMirrorType, - RepoID: mirrorID, + Type: PushMirrorType, + ReferenceID: mirrorID, }) if err != nil { log.Error("Unable to push sync request to the queue for pull mirror repo[%d]: Error: %v", mirrorID, err) diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index da2221d915..754054d14d 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -39,7 +39,13 @@ func UpdateAddress(m *repo_model.Mirror, addr string) error { return err } - _, err = git.NewCommand("remote", "add", remoteName, "--mirror=fetch", addr).RunInDir(repoPath) + cmd := git.NewCommand("remote", "add", remoteName, "--mirror=fetch", addr) + if strings.Contains(addr, "://") && strings.Contains(addr, "@") { + cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, util.NewStringURLSanitizer(addr, true).Replace(addr), repoPath)) + } else { + cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, addr, repoPath)) + } + _, err = cmd.RunInDir(repoPath) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { return err } @@ -53,7 +59,13 @@ func UpdateAddress(m *repo_model.Mirror, addr string) error { return err } - _, err = git.NewCommand("remote", "add", remoteName, "--mirror=fetch", wikiRemotePath).RunInDir(wikiPath) + cmd = git.NewCommand("remote", "add", remoteName, "--mirror=fetch", wikiRemotePath) + if strings.Contains(wikiRemotePath, "://") && strings.Contains(wikiRemotePath, "@") { + cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, util.NewStringURLSanitizer(wikiRemotePath, true).Replace(wikiRemotePath), wikiPath)) + } else { + cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, wikiRemotePath, wikiPath)) + } + _, err = cmd.RunInDir(wikiPath) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { return err } @@ -150,8 +162,8 @@ func pruneBrokenReferences(ctx context.Context, timeout time.Duration, stdoutBuilder, stderrBuilder *strings.Builder, sanitizer *strings.Replacer, - isWiki bool) error { - + isWiki bool, +) error { wiki := "" if isWiki { wiki = "Wiki " @@ -188,6 +200,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second log.Trace("SyncMirrors [repo: %-v]: running git remote update...", m.Repo) + gitArgs := []string{"remote", "update"} if m.EnablePrune { gitArgs = append(gitArgs, "--prune") @@ -196,7 +209,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo remoteAddr, remoteErr := git.GetRemoteAddress(ctx, repoPath, m.GetRemoteName()) if remoteErr != nil { - log.Error("GetRemoteAddress Error %v", remoteErr) + log.Error("SyncMirrors [repo: %-v]: GetRemoteAddress Error %v", m.Repo, remoteErr) } stdoutBuilder := strings.Builder{} @@ -215,7 +228,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo // Now check if the error is a resolve reference due to broken reference if strings.Contains(stderr, "unable to resolve reference") && strings.Contains(stderr, "reference broken") { - log.Warn("Failed to update mirror repository %-v due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err) + log.Warn("SyncMirrors [repo: %-v]: failed to update mirror repository due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err) err = nil // Attempt prune @@ -240,7 +253,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo // If there is still an error (or there always was an error) if err != nil { - log.Error("Failed to update mirror repository %-v:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err) + log.Error("SyncMirrors [repo: %-v]: failed to update mirror repository:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err) desc := fmt.Sprintf("Failed to update mirror repository '%s': %s", repoPath, stderrMessage) if err = admin_model.CreateRepositoryNotice(desc); err != nil { log.Error("CreateRepositoryNotice: %v", err) @@ -250,15 +263,19 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo } output := stderrBuilder.String() - gitRepo, err := git.OpenRepository(repoPath) + if err := git.WriteCommitGraph(ctx, repoPath); err != nil { + log.Error("SyncMirrors [repo: %-v]: %v", m.Repo, err) + } + + gitRepo, err := git.OpenRepositoryCtx(ctx, repoPath) if err != nil { - log.Error("OpenRepository: %v", err) + log.Error("SyncMirrors [repo: %-v]: failed to OpenRepository: %v", m.Repo, err) return nil, false } log.Trace("SyncMirrors [repo: %-v]: syncing releases with tags...", m.Repo) if err = repo_module.SyncReleasesWithTags(m.Repo, gitRepo); err != nil { - log.Error("Failed to synchronize tags to releases for repository: %v", err) + log.Error("SyncMirrors [repo: %-v]: failed to synchronize tags to releases: %v", m.Repo, err) } if m.LFS && setting.LFS.StartServer { @@ -266,14 +283,14 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo endpoint := lfs.DetermineEndpoint(remoteAddr.String(), m.LFSEndpoint) lfsClient := lfs.NewClient(endpoint, nil) if err = repo_module.StoreMissingLfsObjectsInRepository(ctx, m.Repo, gitRepo, lfsClient); err != nil { - log.Error("Failed to synchronize LFS objects for repository: %v", err) + log.Error("SyncMirrors [repo: %-v]: failed to synchronize LFS objects for repository: %v", m.Repo, err) } } gitRepo.Close() log.Trace("SyncMirrors [repo: %-v]: updating size of repository", m.Repo) if err := models.UpdateRepoSize(db.DefaultContext, m.Repo); err != nil { - log.Error("Failed to update size for mirror repository: %v", err) + log.Error("SyncMirrors [repo: %-v]: failed to update size for mirror repository: %v", m.Repo, err) } if m.Repo.HasWiki() { @@ -291,7 +308,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo remoteAddr, remoteErr := git.GetRemoteAddress(ctx, wikiPath, m.GetRemoteName()) if remoteErr != nil { - log.Error("GetRemoteAddress Error %v", remoteErr) + log.Error("SyncMirrors [repo: %-v Wiki]: unable to get GetRemoteAddress Error %v", m.Repo, remoteErr) } // sanitize the output, since it may contain the remote address, which may @@ -302,7 +319,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo // Now check if the error is a resolve reference due to broken reference if strings.Contains(stderrMessage, "unable to resolve reference") && strings.Contains(stderrMessage, "reference broken") { - log.Warn("Failed to update mirror wiki repository %-v due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err) + log.Warn("SyncMirrors [repo: %-v Wiki]: failed to update mirror wiki repository due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err) err = nil // Attempt prune @@ -325,13 +342,17 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo // If there is still an error (or there always was an error) if err != nil { - log.Error("Failed to update mirror repository wiki %-v:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err) + log.Error("SyncMirrors [repo: %-v Wiki]: failed to update mirror repository wiki:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err) desc := fmt.Sprintf("Failed to update mirror repository wiki '%s': %s", wikiPath, stderrMessage) if err = admin_model.CreateRepositoryNotice(desc); err != nil { log.Error("CreateRepositoryNotice: %v", err) } return nil, false } + + if err := git.WriteCommitGraph(ctx, wikiPath); err != nil { + log.Error("SyncMirrors [repo: %-v]: %v", m.Repo, err) + } } log.Trace("SyncMirrors [repo: %-v Wiki]: git remote update complete", m.Repo) } @@ -339,7 +360,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo log.Trace("SyncMirrors [repo: %-v]: invalidating mirror branch caches...", m.Repo) branches, _, err := git.GetBranchesByPath(m.Repo.RepoPath(), 0, 0) if err != nil { - log.Error("GetBranches: %v", err) + log.Error("SyncMirrors [repo: %-v]: failed to GetBranches: %v", m.Repo, err) return nil, false } @@ -360,12 +381,12 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { return } // There was a panic whilst syncMirrors... - log.Error("PANIC whilst syncMirrors[%d] Panic: %v\nStacktrace: %s", repoID, err, log.Stack(2)) + log.Error("PANIC whilst SyncMirrors[repo_id: %d] Panic: %v\nStacktrace: %s", repoID, err, log.Stack(2)) }() m, err := repo_model.GetMirrorByRepoID(repoID) if err != nil { - log.Error("GetMirrorByRepoID [%d]: %v", repoID, err) + log.Error("SyncMirrors [repo_id: %v]: unable to GetMirrorByRepoID: %v", repoID, err) return false } @@ -375,13 +396,16 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Trace("SyncMirrors [repo: %-v]: Running Sync", m.Repo) results, ok := runSync(ctx, m) if !ok { + if err = repo_model.TouchMirror(ctx, m); err != nil { + log.Error("SyncMirrors [repo: %-v]: failed to TouchMirror: %v", m.Repo, err) + } return false } log.Trace("SyncMirrors [repo: %-v]: Scheduling next update", m.Repo) m.ScheduleNextUpdate() if err = repo_model.UpdateMirror(m); err != nil { - log.Error("UpdateMirror [%d]: %v", m.RepoID, err) + log.Error("SyncMirrors [repo: %-v]: failed to UpdateMirror with next update date: %v", m.Repo, err) return false } @@ -392,7 +416,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results)) gitRepo, err = git.OpenRepositoryCtx(ctx, m.Repo.RepoPath()) if err != nil { - log.Error("OpenRepository [%d]: %v", m.RepoID, err) + log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err) return false } defer gitRepo.Close() @@ -419,7 +443,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { } commitID, err := gitRepo.GetRefCommitID(result.refName) if err != nil { - log.Error("gitRepo.GetRefCommitID [repo_id: %d, ref_name: %s]: %v", m.RepoID, result.refName, err) + log.Error("SyncMirrors [repo: %-v]: unable to GetRefCommitID [ref_name: %s]: %v", m.Repo, result.refName, err) continue } notification.NotifySyncPushCommits(m.Repo.MustOwner(), m.Repo, &repo_module.PushUpdateOptions{ @@ -440,17 +464,17 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { // Push commits oldCommitID, err := git.GetFullCommitID(gitRepo.Path, result.oldCommitID) if err != nil { - log.Error("GetFullCommitID [%d]: %v", m.RepoID, err) + log.Error("SyncMirrors [repo: %-v]: unable to get GetFullCommitID[%s]: %v", m.Repo, result.oldCommitID, err) continue } newCommitID, err := git.GetFullCommitID(gitRepo.Path, result.newCommitID) if err != nil { - log.Error("GetFullCommitID [%d]: %v", m.RepoID, err) + log.Error("SyncMirrors [repo: %-v]: unable to get GetFullCommitID [%s]: %v", m.Repo, result.newCommitID, err) continue } commits, err := gitRepo.CommitsBetweenIDs(newCommitID, oldCommitID) if err != nil { - log.Error("CommitsBetweenIDs [repo_id: %d, new_commit_id: %s, old_commit_id: %s]: %v", m.RepoID, newCommitID, oldCommitID, err) + log.Error("SyncMirrors [repo: %-v]: unable to get CommitsBetweenIDs [new_commit_id: %s, old_commit_id: %s]: %v", m.Repo, newCommitID, oldCommitID, err) continue } @@ -472,12 +496,12 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { // Get latest commit date and update to current repository updated time commitDate, err := git.GetLatestCommitTime(m.Repo.RepoPath()) if err != nil { - log.Error("GetLatestCommitDate [%d]: %v", m.RepoID, err) + log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err) return false } if err = repo_model.UpdateRepositoryUpdatedTime(m.RepoID, commitDate); err != nil { - log.Error("Update repository 'updated_unix' [%d]: %v", m.RepoID, err) + log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err) return false } diff --git a/services/mirror/mirror_push.go b/services/mirror/mirror_push.go index e1c395ea74..c6a50dc50b 100644 --- a/services/mirror/mirror_push.go +++ b/services/mirror/mirror_push.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "regexp" + "strings" "time" repo_model "code.gitea.io/gitea/models/repo" @@ -28,7 +29,13 @@ var stripExitStatus = regexp.MustCompile(`exit status \d+ - `) // AddPushMirrorRemote registers the push mirror remote. func AddPushMirrorRemote(m *repo_model.PushMirror, addr string) error { addRemoteAndConfig := func(addr, path string) error { - if _, err := git.NewCommand("remote", "add", "--mirror=push", m.RemoteName, addr).RunInDir(path); err != nil { + cmd := git.NewCommand("remote", "add", "--mirror=push", m.RemoteName, addr) + if strings.Contains(addr, "://") && strings.Contains(addr, "@") { + cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, util.NewStringURLSanitizer(addr, true).Replace(addr), path)) + } else { + cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, addr, path)) + } + if _, err := cmd.RunInDir(path); err != nil { return err } if _, err := git.NewCommand("config", "--add", "remote."+m.RemoteName+".push", "+refs/heads/*:refs/heads/*").RunInDir(path); err != nil { diff --git a/services/pull/check.go b/services/pull/check.go index 363a716b28..93e539e587 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -7,6 +7,7 @@ package pull import ( "context" + "errors" "fmt" "os" "strconv" @@ -24,11 +25,22 @@ import ( "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" + asymkey_service "code.gitea.io/gitea/services/asymkey" ) // prQueue represents a queue to handle update pull request tests var prQueue queue.UniqueQueue +var ( + ErrIsClosed = errors.New("pull is closed") + ErrUserNotAllowedToMerge = models.ErrNotAllowedToMerge{} + ErrHasMerged = errors.New("has already been merged") + ErrIsWorkInProgress = errors.New("work in progress PRs cannot be merged") + ErrIsChecking = errors.New("cannot merge while conflict checking is in progress") + ErrNotMergableState = errors.New("not in mergeable state") + ErrDependenciesLeft = errors.New("is blocked by an open dependency") +) + // AddToTaskQueue adds itself to pull request test task queue. func AddToTaskQueue(pr *models.PullRequest) { err := prQueue.PushFunc(strconv.FormatInt(pr.ID, 10), func() error { @@ -46,6 +58,83 @@ func AddToTaskQueue(pr *models.PullRequest) { } } +// CheckPullMergable check if the pull mergable based on all conditions (branch protection, merge options, ...) +func CheckPullMergable(ctx context.Context, doer *user_model.User, perm *models.Permission, pr *models.PullRequest, manuallMerge, force bool) error { + if pr.HasMerged { + return ErrHasMerged + } + + if err := pr.LoadIssue(); err != nil { + return err + } else if pr.Issue.IsClosed { + return ErrIsClosed + } + + if allowedMerge, err := IsUserAllowedToMerge(pr, *perm, doer); err != nil { + return err + } else if !allowedMerge { + return ErrUserNotAllowedToMerge + } + + if manuallMerge { + // don't check rules to "auto merge", doer is going to mark this pull as merged manually + return nil + } + + if pr.IsWorkInProgress() { + return ErrIsWorkInProgress + } + + if !pr.CanAutoMerge() { + return ErrNotMergableState + } + + if pr.IsChecking() { + return ErrIsChecking + } + + if err := CheckPRReadyToMerge(pr, false); err != nil { + if models.IsErrNotAllowedToMerge(err) { + if force { + if isRepoAdmin, err2 := models.IsUserRepoAdmin(pr.BaseRepo, doer); err2 != nil { + return err2 + } else if !isRepoAdmin { + return err + } + } + } else { + return err + } + } + + if _, err := isSignedIfRequired(ctx, pr, doer); err != nil { + return err + } + + if noDeps, err := models.IssueNoDependenciesLeft(pr.Issue); err != nil { + return err + } else if !noDeps { + return ErrDependenciesLeft + } + + return nil +} + +// isSignedIfRequired check if merge will be signed if required +func isSignedIfRequired(ctx context.Context, pr *models.PullRequest, doer *user_model.User) (bool, error) { + if err := pr.LoadProtectedBranch(); err != nil { + return false, err + } + + if pr.ProtectedBranch == nil || !pr.ProtectedBranch.RequireSignedCommits { + return true, nil + } + + sign, _, _, err := asymkey_service.SignMerge(pr, doer, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName()) + + return sign, err +} + // checkAndUpdateStatus checks if pull request is possible to leaving checking status, // and set to be either conflict or mergeable. func checkAndUpdateStatus(pr *models.PullRequest) { diff --git a/services/pull/merge.go b/services/pull/merge.go index f6a6415bff..37269b0c78 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -164,13 +164,13 @@ func rawMerge(pr *models.PullRequest, doer *user_model.User, mergeStyle repo_mod } infoPath := filepath.Join(tmpBasePath, ".git", "info") - if err := os.MkdirAll(infoPath, 0700); err != nil { + if err := os.MkdirAll(infoPath, 0o700); err != nil { log.Error("Unable to create .git/info in %s: %v", tmpBasePath, err) return "", fmt.Errorf("Unable to create .git/info in tmpBasePath: %v", err) } sparseCheckoutListPath := filepath.Join(infoPath, "sparse-checkout") - if err := os.WriteFile(sparseCheckoutListPath, []byte(sparseCheckoutList), 0600); err != nil { + if err := os.WriteFile(sparseCheckoutListPath, []byte(sparseCheckoutList), 0o600); err != nil { log.Error("Unable to write .git/info/sparse-checkout file in %s: %v", tmpBasePath, err) return "", fmt.Errorf("Unable to write .git/info/sparse-checkout file in tmpBasePath: %v", err) } @@ -561,21 +561,6 @@ func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) { return out.String(), nil } -// IsSignedIfRequired check if merge will be signed if required -func IsSignedIfRequired(pr *models.PullRequest, doer *user_model.User) (bool, error) { - if err := pr.LoadProtectedBranch(); err != nil { - return false, err - } - - if pr.ProtectedBranch == nil || !pr.ProtectedBranch.RequireSignedCommits { - return true, nil - } - - sign, _, _, err := asymkey_service.SignMerge(pr, doer, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName()) - - return sign, err -} - // IsUserAllowedToMerge check if user is allowed to merge PR with given permissions and branch protections func IsUserAllowedToMerge(pr *models.PullRequest, p models.Permission, user *user_model.User) (bool, error) { if user == nil { diff --git a/services/pull/patch.go b/services/pull/patch.go index 0eba3f86ed..e2851709e0 100644 --- a/services/pull/patch.go +++ b/services/pull/patch.go @@ -339,8 +339,10 @@ func checkConflicts(pr *models.PullRequest, gitRepo *git.Repository, tmpBasePath if prConfig.IgnoreWhitespaceConflicts { args = append(args, "--ignore-whitespace") } + is3way := false if git.CheckGitVersionAtLeast("2.32.0") == nil { args = append(args, "--3way") + is3way = true } args = append(args, patchPath) pr.ConflictedFiles = make([]string, 0, 5) @@ -379,6 +381,9 @@ func checkConflicts(pr *models.PullRequest, gitRepo *git.Repository, tmpBasePath const prefix = "error: patch failed:" const errorPrefix = "error: " + const threewayFailed = "Failed to perform three-way merge..." + const appliedPatchPrefix = "Applied patch to '" + const withConflicts = "' with conflicts." conflictMap := map[string]bool{} @@ -390,6 +395,8 @@ func checkConflicts(pr *models.PullRequest, gitRepo *git.Repository, tmpBasePath conflict = true filepath := strings.TrimSpace(strings.Split(line[len(prefix):], ":")[0]) conflictMap[filepath] = true + } else if is3way && line == threewayFailed { + conflict = true } else if strings.HasPrefix(line, errorPrefix) { conflict = true for _, suffix := range patchErrorSuffices { @@ -401,6 +408,12 @@ func checkConflicts(pr *models.PullRequest, gitRepo *git.Repository, tmpBasePath break } } + } else if is3way && strings.HasPrefix(line, appliedPatchPrefix) && strings.HasSuffix(line, withConflicts) { + conflict = true + filepath := strings.TrimPrefix(strings.TrimSuffix(line, withConflicts), appliedPatchPrefix) + if filepath != "" { + conflictMap[filepath] = true + } } // only list 10 conflicted files if len(conflictMap) >= 10 { @@ -418,14 +431,16 @@ func checkConflicts(pr *models.PullRequest, gitRepo *git.Repository, tmpBasePath return nil }) - // 8. If there is a conflict the `git apply` command will return a non-zero error code - so there will be a positive error. - if err != nil { + // 9. Check if the found conflictedfiles is non-zero, "err" could be non-nil, so we should ignore it if we found conflicts. + // Note: `"err" could be non-nil` is due that if enable 3-way merge, it doesn't return any error on found conflicts. + if len(pr.ConflictedFiles) > 0 { if conflict { pr.Status = models.PullRequestStatusConflict log.Trace("Found %d files conflicted: %v", len(pr.ConflictedFiles), pr.ConflictedFiles) return true, nil } + } else if err != nil { return false, fmt.Errorf("git apply --check: %v", err) } return false, nil diff --git a/services/pull/review.go b/services/pull/review.go index 42292ac209..b80c55aeae 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -271,7 +271,7 @@ func SubmitReview(doer *user_model.User, gitRepo *git.Repository, issue *models. } // DismissReview dismissing stale review by repo admin -func DismissReview(reviewID int64, message string, doer *user_model.User, isDismiss bool) (comment *models.Comment, err error) { +func DismissReview(reviewID, repoID int64, message string, doer *user_model.User, isDismiss bool) (comment *models.Comment, err error) { review, err := models.GetReviewByID(reviewID) if err != nil { return @@ -281,6 +281,16 @@ func DismissReview(reviewID int64, message string, doer *user_model.User, isDism return nil, fmt.Errorf("not need to dismiss this review because it's type is not Approve or change request") } + // load data for notify + if err = review.LoadAttributes(); err != nil { + return nil, err + } + + // Check if the review's repoID is the one we're currently expecting. + if review.Issue.RepoID != repoID { + return nil, fmt.Errorf("reviews's repository is not the same as the one we expect") + } + if err = models.DismissReview(review, isDismiss); err != nil { return } @@ -289,10 +299,6 @@ func DismissReview(reviewID int64, message string, doer *user_model.User, isDism return nil, nil } - // load data for notify - if err = review.LoadAttributes(); err != nil { - return - } if err = review.Issue.LoadPullRequest(); err != nil { return } diff --git a/services/release/release.go b/services/release/release.go index 5fa506bc61..4314b64ae7 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -295,6 +295,20 @@ func DeleteReleaseByID(id int64, doer *user_model.User, delTag bool) error { } if delTag { + protectedTags, err := models.GetProtectedTags(rel.RepoID) + if err != nil { + return fmt.Errorf("GetProtectedTags: %v", err) + } + isAllowed, err := models.IsUserAllowedToControlTag(protectedTags, rel.TagName, rel.PublisherID) + if err != nil { + return err + } + if !isAllowed { + return models.ErrProtectedTagName{ + TagName: rel.TagName, + } + } + if stdout, err := git.NewCommand("tag", "-d", rel.TagName). SetDescription(fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID)). RunInDir(repo.RepoPath()); err != nil && !strings.Contains(err.Error(), "not found") { diff --git a/services/repository/adopt.go b/services/repository/adopt.go index fc3fdc608f..d91e6a20e6 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -335,6 +335,13 @@ func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, in } repoNamesToCheck = append(repoNamesToCheck, name) + if len(repoNamesToCheck) > setting.Database.IterateBufferSize { + if err = checkUnadoptedRepositories(userName, repoNamesToCheck, unadopted); err != nil { + return err + } + repoNamesToCheck = repoNamesToCheck[:0] + + } return filepath.SkipDir }); err != nil { return nil, 0, err diff --git a/services/repository/archiver/archiver.go b/services/repository/archiver/archiver.go index 16ee532f78..7f0390b501 100644 --- a/services/repository/archiver/archiver.go +++ b/services/repository/archiver/archiver.go @@ -169,7 +169,7 @@ func doArchive(r *ArchiveRequest) (*repo_model.RepoArchiver, error) { w.Close() rd.Close() }() - var done = make(chan error) + done := make(chan error, 1) // Ensure that there is some capacity which will ensure that the goroutine below can always finish repo, err := repo_model.GetRepositoryByID(archiver.RepoID) if err != nil { return nil, fmt.Errorf("archiver.LoadRepo failed: %v", err) diff --git a/services/repository/branch.go b/services/repository/branch.go index e1775fc12b..272970c629 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -35,7 +35,7 @@ func CreateNewBranch(doer *user_model.User, repo *repo_model.Repository, oldBran if err := git.Push(git.DefaultContext, repo.RepoPath(), git.PushOptions{ Remote: repo.RepoPath(), - Branch: fmt.Sprintf("%s:%s%s", oldBranchName, git.BranchPrefix, branchName), + Branch: fmt.Sprintf("%s%s:%s%s", git.BranchPrefix, oldBranchName, git.BranchPrefix, branchName), Env: models.PushingEnvironment(doer, repo), }); err != nil { if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) { @@ -69,7 +69,7 @@ func GetBranches(repo *repo_model.Repository, skip, limit int) ([]*git.Branch, i // checkBranchName validates branch name with existing repository branches func checkBranchName(ctx context.Context, repo *repo_model.Repository, name string) error { - _, err := git.WalkReferences(ctx, repo.RepoPath(), func(refName string) error { + _, err := git.WalkReferences(ctx, repo.RepoPath(), func(_, refName string) error { branchRefName := strings.TrimPrefix(refName, git.BranchPrefix) switch { case branchRefName == name: diff --git a/services/repository/fork.go b/services/repository/fork.go index b091ca8fdc..493a955e06 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -143,7 +143,17 @@ func ForkRepository(doer, owner *user_model.User, opts ForkRepoOptions) (_ *repo log.Error("Failed to update size for repository: %v", err) } if err := repo_model.CopyLanguageStat(opts.BaseRepo, repo); err != nil { - log.Error("Copy language stat from oldRepo failed") + log.Error("Copy language stat from oldRepo failed: %v", err) + } + + gitRepo, err := git.OpenRepositoryCtx(git.DefaultContext, repo.RepoPath()) + if err != nil { + log.Error("Open created git repository failed: %v", err) + } else { + defer gitRepo.Close() + if err := repo_module.SyncReleasesWithTags(repo, gitRepo); err != nil { + log.Error("Sync releases from git tags failed: %v", err) + } } notification.NotifyForkRepository(doer, opts.BaseRepo, repo) diff --git a/services/repository/push.go b/services/repository/push.go index 11854ccb39..b1dbe7d7f0 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -216,7 +216,34 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { if len(commits.Commits) > setting.UI.FeedMaxCommitNum { commits.Commits = commits.Commits[:setting.UI.FeedMaxCommitNum] } - commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID) + + oldCommitID := opts.OldCommitID + if oldCommitID == git.EmptySHA && len(commits.Commits) > 0 { + oldCommit, err := gitRepo.GetCommit(commits.Commits[len(commits.Commits)-1].Sha1) + if err != nil && !git.IsErrNotExist(err) { + log.Error("unable to GetCommit %s from %-v: %v", oldCommitID, repo, err) + } + if oldCommit != nil { + for i := 0; i < oldCommit.ParentCount(); i++ { + commitID, _ := oldCommit.ParentID(i) + if !commitID.IsZero() { + oldCommitID = commitID.String() + break + } + } + } + } + + if oldCommitID == git.EmptySHA && repo.DefaultBranch != branch { + oldCommitID = repo.DefaultBranch + } + + if oldCommitID != git.EmptySHA { + commits.CompareURL = repo.ComposeCompareURL(oldCommitID, opts.NewCommitID) + } else { + commits.CompareURL = "" + } + notification.NotifyPushCommits(pusher, repo, opts, commits) if err = models.RemoveDeletedBranchByName(repo.ID, branch); err != nil { diff --git a/services/webhook/deliver.go b/services/webhook/deliver.go index 36169baad4..08e1581512 100644 --- a/services/webhook/deliver.go +++ b/services/webhook/deliver.go @@ -148,6 +148,8 @@ func Deliver(t *webhook_model.HookTask) error { t.Delivered = time.Now().UnixNano() if t.IsSucceed { log.Trace("Hook delivered: %s", t.UUID) + } else if !w.IsActive { + log.Trace("Hook delivery skipped as webhook is inactive: %s", t.UUID) } else { log.Trace("Hook delivery failed: %s", t.UUID) } @@ -172,6 +174,10 @@ func Deliver(t *webhook_model.HookTask) error { return fmt.Errorf("webhook task skipped (webhooks disabled): [%d]", t.ID) } + if !w.IsActive { + return nil + } + resp, err := webhookHTTPClient.Do(req.WithContext(graceful.GetManager().ShutdownContext())) if err != nil { t.ResponseInfo.Body = fmt.Sprintf("Delivery: %v", err) diff --git a/services/webhook/webhook.go b/services/webhook/webhook.go index f284a20c30..a4f353e5f5 100644 --- a/services/webhook/webhook.go +++ b/services/webhook/webhook.go @@ -212,7 +212,7 @@ func prepareWebhooks(repo *repo_model.Repository, event webhook_model.HookEventT } // Add any admin-defined system webhooks - systemHooks, err := webhook_model.GetSystemWebhooks() + systemHooks, err := webhook_model.GetSystemWebhooks(util.OptionalBoolTrue) if err != nil { return fmt.Errorf("GetSystemWebhooks: %v", err) } diff --git a/templates/admin/auth/edit.tmpl b/templates/admin/auth/edit.tmpl index a9942354c0..69cc516746 100644 --- a/templates/admin/auth/edit.tmpl +++ b/templates/admin/auth/edit.tmpl @@ -27,7 +27,7 @@
+
+
+
diff --git a/templates/admin/auth/new.tmpl b/templates/admin/auth/new.tmpl index b8e80dbcaa..9882cde03b 100644 --- a/templates/admin/auth/new.tmpl +++ b/templates/admin/auth/new.tmpl @@ -14,7 +14,7 @@