diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..6288e4d367c --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,34 @@ +{ + "name": "Gitea DevContainer", + "image": "mcr.microsoft.com/devcontainers/go:1.20", + "features": { + // installs nodejs into container + "ghcr.io/devcontainers/features/node:1": { + "version":"20" + } + }, + "customizations": { + "vscode": { + "settings": {}, + // same extensions as Gitpod, should match /.gitpod.yml + "extensions": [ + "editorconfig.editorconfig", + "dbaeumer.vscode-eslint", + "golang.go", + "stylelint.vscode-stylelint", + "DavidAnson.vscode-markdownlint", + "Vue.volar", + "ms-azuretools.vscode-docker", + "zixuanchen.vitest-explorer", + "alexcvzz.vscode-sqlite" + ] + } + }, + "portsAttributes": { + "3000": { + "label": "Gitea Web", + "onAutoForward": "notify" + } + }, + "postCreateCommand": "make deps" +} diff --git a/.drone.yml b/.drone.yml index 4e7789ef923..5d4e13038ba 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,138 +1,3 @@ ---- -kind: pipeline -type: docker -name: release-latest - -platform: - os: linux - arch: amd64 - -workspace: - base: /source - path: / - -trigger: - branch: - - main - - "release/*" - event: - - push - paths: - exclude: - - "docs/**" - -volumes: - - name: deps - temp: {} - -steps: - - name: fetch-tags - image: docker:git - pull: always - commands: - - git fetch --tags --force - - - name: deps-frontend - image: node:20 - pull: always - commands: - - make deps-frontend - - - name: deps-backend - image: gitea/test_env:linux-1.20-amd64 - pull: always - commands: - - make deps-backend - volumes: - - name: deps - path: /go - - - name: static - image: techknowlogick/xgo:go-1.20.x - pull: always - commands: - # Upgrade to node 20 once https://github.com/techknowlogick/xgo/issues/163 is resolved - - curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get -qqy install nodejs - - export PATH=$PATH:$GOPATH/bin - - make release - environment: - GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not - TAGS: bindata sqlite sqlite_unlock_notify - DEBIAN_FRONTEND: noninteractive - volumes: - - name: deps - path: /go - - - name: gpg-sign - image: plugins/gpgsign:1 - pull: always - settings: - detach_sign: true - excludes: - - "dist/release/*.sha256" - files: - - "dist/release/*" - environment: - GPGSIGN_KEY: - from_secret: gpgsign_key - GPGSIGN_PASSPHRASE: - from_secret: gpgsign_passphrase - - - name: release-branch - image: woodpeckerci/plugin-s3:latest - pull: always - settings: - acl: - from_secret: aws_s3_acl - region: - from_secret: aws_s3_region - bucket: - from_secret: aws_s3_bucket - endpoint: - from_secret: aws_s3_endpoint - path_style: - from_secret: aws_s3_path_style - source: "dist/release/*" - strip_prefix: dist/release/ - target: "/gitea/${DRONE_BRANCH##release/v}" - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - when: - branch: - - "release/*" - event: - - push - - - name: release-main - image: woodpeckerci/plugin-s3:latest - settings: - acl: - from_secret: aws_s3_acl - region: - from_secret: aws_s3_region - bucket: - from_secret: aws_s3_bucket - endpoint: - from_secret: aws_s3_endpoint - path_style: - from_secret: aws_s3_path_style - source: "dist/release/*" - strip_prefix: dist/release/ - target: /gitea/main - environment: - AWS_ACCESS_KEY_ID: - from_secret: aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: aws_secret_access_key - when: - branch: - - main - event: - - push - --- kind: pipeline name: release-version @@ -379,133 +244,6 @@ steps: exclude: - pull_request ---- -kind: pipeline -type: docker -name: docker-linux-amd64-release - -platform: - os: linux - arch: amd64 - -trigger: - ref: - - refs/heads/main - -steps: - - name: fetch-tags - image: docker:git - pull: always - commands: - - git fetch --tags --force - - - name: publish - image: plugins/docker:latest - pull: always - settings: - auto_tag: false - tags: nightly-linux-amd64 - repo: gitea/gitea - build_args: - - GOPROXY=https://goproxy.io - password: - from_secret: docker_password - username: - from_secret: docker_username - environment: - PLUGIN_MIRROR: - from_secret: plugin_mirror - DOCKER_BUILDKIT: 1 - when: - event: - exclude: - - pull_request - - - name: publish-rootless - image: plugins/docker:latest - settings: - dockerfile: Dockerfile.rootless - auto_tag: false - tags: nightly-linux-amd64-rootless - repo: gitea/gitea - build_args: - - GOPROXY=https://goproxy.io - password: - from_secret: docker_password - username: - from_secret: docker_username - environment: - PLUGIN_MIRROR: - from_secret: plugin_mirror - DOCKER_BUILDKIT: 1 - when: - event: - exclude: - - pull_request - ---- -kind: pipeline -name: docker-linux-amd64-release-branch - -platform: - os: linux - arch: amd64 - -trigger: - ref: - - "refs/heads/release/v*" - -steps: - - name: fetch-tags - image: docker:git - pull: always - commands: - - git fetch --tags --force - - - name: publish - image: plugins/docker:latest - pull: always - settings: - auto_tag: false - tags: ${DRONE_BRANCH##release/v}-nightly-linux-amd64 - repo: gitea/gitea - build_args: - - GOPROXY=https://goproxy.io - password: - from_secret: docker_password - username: - from_secret: docker_username - environment: - PLUGIN_MIRROR: - from_secret: plugin_mirror - DOCKER_BUILDKIT: 1 - when: - event: - exclude: - - pull_request - - - name: publish-rootless - image: plugins/docker:latest - settings: - dockerfile: Dockerfile.rootless - auto_tag: false - tags: ${DRONE_BRANCH##release/v}-nightly-linux-amd64-rootless - repo: gitea/gitea - build_args: - - GOPROXY=https://goproxy.io - password: - from_secret: docker_password - username: - from_secret: docker_username - environment: - PLUGIN_MIRROR: - from_secret: plugin_mirror - DOCKER_BUILDKIT: 1 - when: - event: - exclude: - - pull_request - --- kind: pipeline type: docker @@ -641,136 +379,6 @@ steps: exclude: - pull_request ---- -kind: pipeline -type: docker -name: docker-linux-arm64-release - -platform: - os: linux - arch: arm64 - -trigger: - ref: - - refs/heads/main - paths: - exclude: - - "docs/**" - -steps: - - name: fetch-tags - image: docker:git - pull: always - commands: - - git fetch --tags --force - - - name: publish - image: plugins/docker:latest - pull: always - settings: - auto_tag: false - tags: nightly-linux-arm64 - repo: gitea/gitea - build_args: - - GOPROXY=https://goproxy.io - password: - from_secret: docker_password - username: - from_secret: docker_username - environment: - PLUGIN_MIRROR: - from_secret: plugin_mirror - DOCKER_BUILDKIT: 1 - when: - event: - exclude: - - pull_request - - - name: publish-rootless - image: plugins/docker:latest - settings: - dockerfile: Dockerfile.rootless - auto_tag: false - tags: nightly-linux-arm64-rootless - repo: gitea/gitea - build_args: - - GOPROXY=https://goproxy.io - password: - from_secret: docker_password - username: - from_secret: docker_username - environment: - PLUGIN_MIRROR: - from_secret: plugin_mirror - DOCKER_BUILDKIT: 1 - when: - event: - exclude: - - pull_request - ---- -kind: pipeline -name: docker-linux-arm64-release-branch - -platform: - os: linux - arch: arm64 - -trigger: - ref: - - "refs/heads/release/v*" - -steps: - - name: fetch-tags - image: docker:git - pull: always - commands: - - git fetch --tags --force - - - name: publish - image: plugins/docker:latest - pull: always - settings: - auto_tag: false - tags: ${DRONE_BRANCH##release/v}-nightly-linux-arm64 - repo: gitea/gitea - build_args: - - GOPROXY=https://goproxy.io - password: - from_secret: docker_password - username: - from_secret: docker_username - environment: - PLUGIN_MIRROR: - from_secret: plugin_mirror - DOCKER_BUILDKIT: 1 - when: - event: - exclude: - - pull_request - - - name: publish-rootless - image: plugins/docker:latest - settings: - dockerfile: Dockerfile.rootless - auto_tag: false - tags: ${DRONE_BRANCH##release/v}-nightly-linux-arm64-rootless - repo: gitea/gitea - build_args: - - GOPROXY=https://goproxy.io - password: - from_secret: docker_password - username: - from_secret: docker_username - environment: - PLUGIN_MIRROR: - from_secret: plugin_mirror - DOCKER_BUILDKIT: 1 - when: - event: - exclude: - - pull_request - --- kind: pipeline type: docker @@ -816,50 +424,3 @@ depends_on: - docker-linux-amd64-release-candidate-version - docker-linux-arm64-release-version - docker-linux-arm64-release-candidate-version - ---- -kind: pipeline -type: docker -name: docker-manifest - -platform: - os: linux - arch: amd64 - -steps: - - name: manifest-rootless - image: plugins/manifest - pull: always - settings: - auto_tag: false - ignore_missing: true - spec: docker/manifest.rootless.tmpl - password: - from_secret: docker_password - username: - from_secret: docker_username - - - name: manifest - image: plugins/manifest - settings: - auto_tag: false - ignore_missing: true - spec: docker/manifest.tmpl - password: - from_secret: docker_password - username: - from_secret: docker_username - -trigger: - ref: - - refs/heads/main - - "refs/heads/release/v*" - paths: - exclude: - - "docs/**" - -depends_on: - - docker-linux-amd64-release - - docker-linux-arm64-release - - docker-linux-amd64-release-branch - - docker-linux-arm64-release-branch diff --git a/.gitattributes b/.gitattributes index 6d4698d6a8c..7e7a139c9a4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,5 +5,6 @@ /templates/swagger/v1_json.tmpl linguist-generated /vendor/** -text -eol linguist-vendored /web_src/fomantic/build/** linguist-generated +/web_src/fomantic/_site/globals/site.variables linguist-language=Less /web_src/js/vendor/** -text -eol linguist-vendored Dockerfile.* linguist-language=Dockerfile diff --git a/.github/workflows/cron-licenses.yml b/.github/workflows/cron-licenses.yml index 8642049117e..700d45a3c8b 100644 --- a/.github/workflows/cron-licenses.yml +++ b/.github/workflows/cron-licenses.yml @@ -3,6 +3,7 @@ name: cron-licenses on: schedule: - cron: "7 0 * * 1" # every Monday at 00:07 UTC + workflow_dispatch: jobs: cron-licenses: diff --git a/.github/workflows/cron-translations.yml b/.github/workflows/cron-translations.yml index a7c9ceabd34..3f147c685d8 100644 --- a/.github/workflows/cron-translations.yml +++ b/.github/workflows/cron-translations.yml @@ -3,6 +3,7 @@ name: cron-translations on: schedule: - cron: "7 0 * * *" # every day at 00:07 UTC + workflow_dispatch: jobs: crowdin-pull: diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml index 9a9c54720b4..398fb6eae39 100644 --- a/.github/workflows/files-changed.yml +++ b/.github/workflows/files-changed.yml @@ -4,21 +4,20 @@ on: workflow_call: outputs: backend: - description: "whether backend files changed" value: ${{ jobs.detect.outputs.backend }} frontend: - description: "whether frontend files changed" value: ${{ jobs.detect.outputs.frontend }} docs: - description: "whether docs files changed" value: ${{ jobs.detect.outputs.docs }} actions: - description: "whether actions files changed" value: ${{ jobs.detect.outputs.actions }} + templates: + value: ${{ jobs.detect.outputs.templates }} + docker: + value: ${{ jobs.detect.outputs.docker }} jobs: detect: - name: detect which files changed runs-on: ubuntu-latest timeout-minutes: 3 # Map a step output to a job output @@ -27,6 +26,8 @@ jobs: frontend: ${{ steps.changes.outputs.frontend }} docs: ${{ steps.changes.outputs.docs }} actions: ${{ steps.changes.outputs.actions }} + templates: ${{ steps.changes.outputs.templates }} + docker: ${{ steps.changes.outputs.docker }} steps: - uses: actions/checkout@v3 - uses: dorny/paths-filter@v2 @@ -35,7 +36,7 @@ jobs: filters: | backend: - "**/*.go" - - "**/*.tmpl" + - "templates/**/*.tmpl" - "go.mod" - "go.sum" @@ -51,3 +52,11 @@ jobs: actions: - ".github/workflows/*" + + templates: + - "templates/**/*.tmpl" + - "poetry.lock" + docker: + - "Dockerfile" + - "Dockerfile.rootless" + - "docker/**" diff --git a/.github/workflows/pull-compliance.yml b/.github/workflows/pull-compliance.yml index daee522c274..5e094f02c19 100644 --- a/.github/workflows/pull-compliance.yml +++ b/.github/workflows/pull-compliance.yml @@ -26,6 +26,19 @@ jobs: env: TAGS: bindata sqlite sqlite_unlock_notify + lint-templates: + if: needs.files-changed.outputs.templates == 'true' + needs: files-changed + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.11" + - run: pip install poetry + - run: make deps-py + - run: make lint-templates + lint-go-windows: if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' needs: files-changed diff --git a/.github/workflows/pull-docker-dryrun.yml b/.github/workflows/pull-docker-dryrun.yml index 916de6b27d3..61f1fd5632e 100644 --- a/.github/workflows/pull-docker-dryrun.yml +++ b/.github/workflows/pull-docker-dryrun.yml @@ -11,8 +11,8 @@ jobs: files-changed: uses: ./.github/workflows/files-changed.yml - docker-dryrun: - if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true' + regular: + if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.actions == 'true' needs: files-changed runs-on: ubuntu-latest steps: @@ -21,3 +21,15 @@ jobs: with: push: false tags: gitea/gitea:linux-amd64 + + rootless: + if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.actions == 'true' + needs: files-changed + runs-on: ubuntu-latest + steps: + - uses: docker/setup-buildx-action@v2 + - uses: docker/build-push-action@v4 + with: + push: false + file: Dockerfile.rootless + tags: gitea/gitea:linux-amd64 diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml new file mode 100644 index 00000000000..71ec6dae841 --- /dev/null +++ b/.github/workflows/release-nightly.yml @@ -0,0 +1,87 @@ +name: release-nightly-assets + +on: + push: + branches: [ main, release/v* ] + +jobs: + nightly-binary: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + # fetch all commits instead of only the last as some branches are long lived and could have many between versions + # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 + - run: git fetch --unshallow --quiet --tags --force + - uses: actions/setup-go@v4 + with: + go-version: ">=1.20" + check-latest: true + - uses: actions/setup-node@v3 + with: + node-version: 20 + - run: make deps-frontend deps-backend + # xgo build + - run: make release + env: + TAGS: bindata sqlite sqlite_unlock_notify + - name: import gpg key + id: import_gpg + uses: crazy-max/ghaction-import-gpg@v5 + with: + gpg_private_key: ${{ secrets.GPGSIGN_KEY }} + passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} + - name: sign binaries + run: | + for f in dist/release/*; do + echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f" + done + # clean branch name to get the folder name in S3 + - name: Get cleaned branch name + id: clean_name + run: | + REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//') + echo "Cleaned name is ${REF_NAME}" + echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT" + - name: upload binaries to s3 + uses: jakejarvis/s3-sync-action@master + env: + AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_REGION: ${{ secrets.AWS_REGION }} + SOURCE_DIR: dist/release + DEST_DIR: gitea/${{ steps.clean_name.outputs.branch }} + nightly-docker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: docker/setup-qemu-action@v2 + - uses: docker/setup-buildx-action@v2 + - name: Get cleaned branch name + id: clean_name + run: | + # if main then say nightly otherwise cleanup name + if [ "${{ github.ref }}" = "refs/heads/main" ]; then + echo "branch=nightly" >> "$GITHUB_OUTPUT" + exit 0 + fi + REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//') + echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT" + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: build rootful docker image + uses: docker/build-push-action@v4 + with: + platforms: linux/amd64,linux/arm64 + push: true + tags: gitea/gitea:${{ steps.clean_name.outputs.branch }} + - name: build rootless docker image + uses: docker/build-push-action@v4 + with: + platforms: linux/amd64,linux/arm64 + push: true + file: Dockerfile.rootless + tags: gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless diff --git a/.gitignore b/.gitignore index 804fe87c04e..581417df610 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ cpu.out /tests/*.ini /tests/**/*.git/**/*.sample /node_modules +/.venv /yarn.lock /yarn-error.log /npm-debug.log* diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml index 4e2315ac958..8aeb7061825 100644 --- a/.stylelintrc.yaml +++ b/.stylelintrc.yaml @@ -1,5 +1,7 @@ plugins: - stylelint-declaration-strict-value + - stylelint-declaration-block-no-ignored-properties + - stylelint-stylistic ignoreFiles: - "**/*.go" @@ -80,6 +82,7 @@ rules: media-feature-name-no-vendor-prefix: true media-feature-name-unit-allowed-list: null media-feature-name-value-allowed-list: null + media-feature-name-value-no-unknown: true media-feature-range-notation: null named-grid-areas-no-invalid: true no-descending-specificity: null @@ -92,6 +95,7 @@ rules: no-unknown-animations: null no-unknown-custom-properties: null number-max-precision: null + plugin/declaration-block-no-ignored-properties: true property-allowed-list: null property-disallowed-list: null property-no-unknown: true @@ -132,6 +136,82 @@ rules: selector-type-no-unknown: [true, {ignore: [custom-elements]}] shorthand-property-no-redundant-values: true string-no-newline: true + stylistic/at-rule-name-case: null + stylistic/at-rule-name-newline-after: null + stylistic/at-rule-name-space-after: null + stylistic/at-rule-semicolon-newline-after: null + stylistic/at-rule-semicolon-space-before: null + stylistic/block-closing-brace-empty-line-before: null + stylistic/block-closing-brace-newline-after: null + stylistic/block-closing-brace-newline-before: null + stylistic/block-closing-brace-space-after: null + stylistic/block-closing-brace-space-before: null + stylistic/block-opening-brace-newline-after: null + stylistic/block-opening-brace-newline-before: null + stylistic/block-opening-brace-space-after: null + stylistic/block-opening-brace-space-before: null + stylistic/color-hex-case: lower + stylistic/declaration-bang-space-after: never + stylistic/declaration-bang-space-before: null + stylistic/declaration-block-semicolon-newline-after: null + stylistic/declaration-block-semicolon-newline-before: null + stylistic/declaration-block-semicolon-space-after: null + stylistic/declaration-block-semicolon-space-before: never + stylistic/declaration-block-trailing-semicolon: null + stylistic/declaration-colon-newline-after: null + stylistic/declaration-colon-space-after: null + stylistic/declaration-colon-space-before: never + stylistic/function-comma-newline-after: null + stylistic/function-comma-newline-before: null + stylistic/function-comma-space-after: null + stylistic/function-comma-space-before: null + stylistic/function-max-empty-lines: 0 + stylistic/function-parentheses-newline-inside: never-multi-line + stylistic/function-parentheses-space-inside: null + stylistic/function-whitespace-after: null + stylistic/indentation: 2 + stylistic/linebreaks: null + stylistic/max-empty-lines: 1 + stylistic/max-line-length: null + stylistic/media-feature-colon-space-after: null + stylistic/media-feature-colon-space-before: never + stylistic/media-feature-name-case: null + stylistic/media-feature-parentheses-space-inside: null + stylistic/media-feature-range-operator-space-after: always + stylistic/media-feature-range-operator-space-before: always + stylistic/media-query-list-comma-newline-after: null + stylistic/media-query-list-comma-newline-before: null + stylistic/media-query-list-comma-space-after: null + stylistic/media-query-list-comma-space-before: null + stylistic/no-empty-first-line: null + stylistic/no-eol-whitespace: true + stylistic/no-extra-semicolons: true + stylistic/no-missing-end-of-source-newline: null + stylistic/number-leading-zero: null + stylistic/number-no-trailing-zeros: null + stylistic/property-case: lower + stylistic/selector-attribute-brackets-space-inside: null + stylistic/selector-attribute-operator-space-after: null + stylistic/selector-attribute-operator-space-before: null + stylistic/selector-combinator-space-after: null + stylistic/selector-combinator-space-before: null + stylistic/selector-descendant-combinator-no-non-space: null + stylistic/selector-list-comma-newline-after: null + stylistic/selector-list-comma-newline-before: null + stylistic/selector-list-comma-space-after: always-single-line + stylistic/selector-list-comma-space-before: never-single-line + stylistic/selector-max-empty-lines: 0 + stylistic/selector-pseudo-class-case: lower + stylistic/selector-pseudo-class-parentheses-space-inside: never + stylistic/selector-pseudo-element-case: lower + stylistic/string-quotes: double + stylistic/unicode-bom: null + stylistic/unit-case: lower + stylistic/value-list-comma-newline-after: null + stylistic/value-list-comma-newline-before: null + stylistic/value-list-comma-space-after: null + stylistic/value-list-comma-space-before: null + stylistic/value-list-max-empty-lines: 0 time-min-milliseconds: null unit-allowed-list: null unit-disallowed-list: null diff --git a/Makefile b/Makefile index 664839273b5..f6d9b9d04fe 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,7 @@ endif EXTRA_GOFLAGS ?= -MAKE_VERSION := $(shell "$(MAKE)" -v | head -n 1) +MAKE_VERSION := $(shell "$(MAKE)" -v | cat | head -n 1) MAKE_EVIDENCE_DIR := .make_evidence ifeq ($(RACE_ENABLED),true) @@ -79,12 +79,12 @@ endif STORED_VERSION_FILE := VERSION HUGO_VERSION ?= 0.111.3 -ifneq ($(DRONE_TAG),) - VERSION ?= $(subst v,,$(DRONE_TAG)) - GITEA_VERSION ?= $(VERSION) +ifneq ($(GITHUB_REF_TYPE),branch) + VERSION ?= $(subst v,,$(GITHUB_REF_NAME)) + GITEA_VERSION ?= $(GITHUB_REF_NAME) else - ifneq ($(DRONE_BRANCH),) - VERSION ?= $(subst release/v,,$(DRONE_BRANCH)) + ifneq ($(GITHUB_REF_NAME),) + VERSION ?= $(subst release/v,,$(GITHUB_REF_NAME)) else VERSION ?= main endif @@ -198,6 +198,7 @@ help: @echo " - deps-frontend install frontend dependencies" @echo " - deps-backend install backend dependencies" @echo " - deps-tools install tool dependencies" + @echo " - deps-py install python dependencies" @echo " - lint lint everything" @echo " - lint-fix lint everything and fix issues" @echo " - lint-actions lint action workflow files" @@ -214,6 +215,7 @@ help: @echo " - lint-css-fix lint css files and fix issues" @echo " - lint-md lint markdown files" @echo " - lint-swagger lint swagger files" + @echo " - lint-templates lint template files" @echo " - checks run various consistency checks" @echo " - checks-frontend check frontend files" @echo " - checks-backend check backend files" @@ -417,6 +419,10 @@ lint-editorconfig: lint-actions: $(GO) run $(ACTIONLINT_PACKAGE) +.PHONY: lint-templates +lint-templates: .venv + @poetry run djlint $(shell find templates -type f -iname '*.tmpl') + .PHONY: watch watch: @bash build/watch.sh @@ -831,30 +837,18 @@ release-windows: | $(DIST_DIRS) ifeq (,$(findstring gogit,$(TAGS))) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit . endif -ifeq ($(CI),true) - cp /build/* $(DIST)/binaries -endif .PHONY: release-linux release-linux: | $(DIST_DIRS) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) . -ifeq ($(CI),true) - cp /build/* $(DIST)/binaries -endif .PHONY: release-darwin release-darwin: | $(DIST_DIRS) 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),true) - cp /build/* $(DIST)/binaries -endif .PHONY: release-freebsd release-freebsd: | $(DIST_DIRS) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) . -ifeq ($(CI),true) - cp /build/* $(DIST)/binaries -endif .PHONY: release-copy release-copy: | $(DIST_DIRS) @@ -893,7 +887,10 @@ deps-docs: fi .PHONY: deps -deps: deps-frontend deps-backend deps-tools deps-docs +deps: deps-frontend deps-backend deps-tools deps-docs deps-py + +.PHONY: deps-py +deps-py: .venv .PHONY: deps-frontend deps-frontend: node_modules @@ -920,6 +917,10 @@ node_modules: package-lock.json npm install --no-save @touch node_modules +.venv: poetry.lock + poetry install + @touch .venv + .PHONY: npm-update npm-update: node-check | node_modules npx updates -cu diff --git a/cmd/web.go b/cmd/web.go index da6c987ff84..3a46b909114 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -191,7 +191,7 @@ func runWeb(ctx *cli.Context) error { } // Set up Chi routes - c := routers.NormalRoutes(graceful.GetManager().HammerContext()) + c := routers.NormalRoutes() err := listen(c, true) <-graceful.GetManager().Done() log.Info("PID: %d Gitea Web Finished", os.Getpid()) diff --git a/docs/content/doc/development/hacking-on-gitea.en-us.md b/docs/content/doc/development/hacking-on-gitea.en-us.md index 0f999215d9b..c13f2239192 100644 --- a/docs/content/doc/development/hacking-on-gitea.en-us.md +++ b/docs/content/doc/development/hacking-on-gitea.en-us.md @@ -48,6 +48,9 @@ Gitea uses `gofmt` to format source code. However, the results of recommended to install the version of Go that our continuous integration is running. As of last update, the Go version should be {{< go-version >}}. +To lint the template files, ensure [Python](https://www.python.org/) and +[Poetry](https://python-poetry.org/) are installed. + ## Installing Make Gitea makes heavy use of Make to automate tasks and improve development. This diff --git a/docs/content/doc/help/support.en-us.md b/docs/content/doc/help/support.en-us.md index eb0e1865823..2b285ce6ea8 100644 --- a/docs/content/doc/help/support.en-us.md +++ b/docs/content/doc/help/support.en-us.md @@ -17,6 +17,7 @@ menu: # Support Options +- [Paid Commercial Support](https://about.gitea.com/) - [Discord](https://discord.gg/Gitea) - [Discourse Forum](https://discourse.gitea.io/) diff --git a/docs/content/doc/installation/on-cloud-provider.en-us.md b/docs/content/doc/installation/on-cloud-provider.en-us.md index 20ca812effe..bf3bf4c3124 100644 --- a/docs/content/doc/installation/on-cloud-provider.en-us.md +++ b/docs/content/doc/installation/on-cloud-provider.en-us.md @@ -56,3 +56,13 @@ To deploy Gitea to Linode, have a look at the [Linode Marketplace](https://www.l [alwaysdata](https://www.alwaysdata.com/) has Gitea as an app in their marketplace. To deploy Gitea to alwaysdata, have a look at the [alwaysdata Marketplace](https://www.alwaysdata.com/en/marketplace/gitea/). + +## Exoscale + +[Exoscale](https://www.exoscale.com/) provides Gitea managed by [Glasskube](https://glasskube.eu/) in their marketplace. + +Exoscale is a European cloud service provider. + +The package is maintained and update via the open source [Glasskube Kubernetes Operator](https://github.com/glasskube/operator). + +To deploy Gitea to Exoscale, have a look at the [Exoscale Marketplace](https://www.exoscale.com/marketplace/listing/glasskube-gitea/). diff --git a/docs/content/doc/usage/actions/act-runner.en-us.md b/docs/content/doc/usage/actions/act-runner.en-us.md index b654fe2efa4..ddab43530e2 100644 --- a/docs/content/doc/usage/actions/act-runner.en-us.md +++ b/docs/content/doc/usage/actions/act-runner.en-us.md @@ -76,6 +76,12 @@ The default configuration is safe to use without any modification, so you can ju ./act_runner --config config.yaml [command] ``` +You could also generate config file with docker: + +```bash +docker run --entrypoint="" --rm -it gitea/act_runner:latest act_runner generate-config > config.yaml +``` + When you are using the docker image, you can specify the configuration file by using the `CONFIG_FILE` environment variable. Make sure that the file is mounted into the container as a volume: ```bash @@ -172,6 +178,27 @@ It is because the act runner will run jobs in docker containers, so it needs to As mentioned, you can remove it if you want to run jobs in the host directly. To be clear, the "host" actually means the container which is running the act runner now, instead of the host machine. +### Set up the runner using docker compose + +You could also set up the runner using the following `docker-compose.yml`: + +```yml +version: "3.8" +services: + runner: + image: gitea/act_runner:nightly + environment: + CONFIG_FILE: /config.yaml + GITEA_INSTANCE_URL: "${INSTANCE_URL}" + GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}" + GITEA_RUNNER_NAME: "${RUNNER_NAME}" + GITEA_RUNNER_LABELS: "${RUNNER_LABELS}" + volumes: + - ./config.yaml:/config.yaml + - ./data:/data + - /var/run/docker.sock:/var/run/docker.sock +``` + ### Configuring cache when starting a Runner using docker image If you do not intend to use `actions/cache` in workflow, you can ignore this section. diff --git a/docs/content/doc/usage/actions/act-runner.zh-cn.md b/docs/content/doc/usage/actions/act-runner.zh-cn.md index 8d0899feac7..fb202e30782 100644 --- a/docs/content/doc/usage/actions/act-runner.zh-cn.md +++ b/docs/content/doc/usage/actions/act-runner.zh-cn.md @@ -76,6 +76,12 @@ docker pull gitea/act_runner:nightly # for the latest nightly build ./act_runner --config config.yaml [command] ``` +您亦可以如下使用 docker 创建配置文件: + +```bash +docker run --entrypoint="" --rm -it gitea/act_runner:latest act_runner generate-config > config.yaml +``` + 当使用Docker镜像时,可以使用`CONFIG_FILE`环境变量指定配置文件。确保将文件作为卷挂载到容器中: ```bash @@ -169,6 +175,27 @@ docker run \ 如前所述,如果要在主机上直接运行Job,可以将其移除。 需要明确的是,这里的 "主机" 实际上指的是当前运行 Act Runner的容器,而不是主机机器本身。 +### 使用 Docker compose 运行 Runner + +您亦可使用如下的 `docker-compose.yml`: + +```yml +version: "3.8" +services: + runner: + image: gitea/act_runner:nightly + environment: + CONFIG_FILE: /config.yaml + GITEA_INSTANCE_URL: "${INSTANCE_URL}" + GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}" + GITEA_RUNNER_NAME: "${RUNNER_NAME}" + GITEA_RUNNER_LABELS: "${RUNNER_LABELS}" + volumes: + - ./config.yaml:/config.yaml + - ./data:/data + - /var/run/docker.sock:/var/run/docker.sock +``` + ### 当您使用 Docker 镜像启动 Runner,如何配置 Cache 如果你不打算在工作流中使用 `actions/cache`,你可以忽略本段。 diff --git a/models/db/index.go b/models/db/index.go index 259ddd6ade7..29254b1f07a 100644 --- a/models/db/index.go +++ b/models/db/index.go @@ -89,6 +89,33 @@ func mysqlGetNextResourceIndex(ctx context.Context, tableName string, groupID in return idx, nil } +func mssqlGetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { + if _, err := GetEngine(ctx).Exec(fmt.Sprintf(` +MERGE INTO %s WITH (HOLDLOCK) AS target +USING (SELECT %d AS group_id) AS source +(group_id) +ON target.group_id = source.group_id +WHEN MATCHED + THEN UPDATE + SET max_index = max_index + 1 +WHEN NOT MATCHED + THEN INSERT (group_id, max_index) + VALUES (%d, 1); +`, tableName, groupID, groupID)); err != nil { + return 0, err + } + + var idx int64 + _, err := GetEngine(ctx).SQL(fmt.Sprintf("SELECT max_index FROM %s WHERE group_id = ?", tableName), groupID).Get(&idx) + if err != nil { + return 0, err + } + if idx == 0 { + return 0, errors.New("cannot get the correct index") + } + return idx, nil +} + // GetNextResourceIndex generates a resource index, it must run in the same transaction where the resource is created func GetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { switch { @@ -96,6 +123,8 @@ func GetNextResourceIndex(ctx context.Context, tableName string, groupID int64) return postgresGetNextResourceIndex(ctx, tableName, groupID) case setting.Database.Type.IsMySQL(): return mysqlGetNextResourceIndex(ctx, tableName, groupID) + case setting.Database.Type.IsMSSQL(): + return mssqlGetNextResourceIndex(ctx, tableName, groupID) } e := GetEngine(ctx) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index a018bb0553a..49143a87e83 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -83,13 +83,47 @@ func mysqlGetCommitStatusIndex(ctx context.Context, repoID int64, sha string) (i return idx, nil } +func mssqlGetCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { + if _, err := db.GetEngine(ctx).Exec(` +MERGE INTO commit_status_index WITH (HOLDLOCK) AS target +USING (SELECT ? AS repo_id, ? AS sha) AS source +(repo_id, sha) +ON target.repo_id = source.repo_id AND target.sha = source.sha +WHEN MATCHED + THEN UPDATE + SET max_index = max_index + 1 +WHEN NOT MATCHED + THEN INSERT (repo_id, sha, max_index) + VALUES (?, ?, 1); +`, repoID, sha, repoID, sha); err != nil { + return 0, err + } + + var idx int64 + _, err := db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ?", + repoID, sha).Get(&idx) + if err != nil { + return 0, err + } + if idx == 0 { + return 0, errors.New("cannot get the correct index") + } + return idx, nil +} + // GetNextCommitStatusIndex retried 3 times to generate a resource index func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { + if !git.IsValidSHAPattern(sha) { + return 0, git.ErrInvalidSHA{SHA: sha} + } + switch { case setting.Database.Type.IsPostgreSQL(): return postgresGetCommitStatusIndex(ctx, repoID, sha) case setting.Database.Type.IsMySQL(): return mysqlGetCommitStatusIndex(ctx, repoID, sha) + case setting.Database.Type.IsMSSQL(): + return mssqlGetCommitStatusIndex(ctx, repoID, sha) } e := db.GetEngine(ctx) diff --git a/modules/context/api.go b/modules/context/api.go index 092ad73f311..3c4d0204133 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -20,6 +20,8 @@ import ( "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/web" + web_types "code.gitea.io/gitea/modules/web/types" "gitea.com/go-chi/cache" ) @@ -41,6 +43,12 @@ type APIContext struct { Package *Package } +func init() { + web.RegisterResponseStatusProvider[*APIContext](func(req *http.Request) web_types.ResponseStatusProvider { + return req.Context().Value(apiContextKey).(*APIContext) + }) +} + // Currently, we have the following common fields in error response: // * message: the message for end users (it shouldn't be used for error type detection) // if we need to indicate some errors, we should introduce some new fields like ErrorCode or ErrorType diff --git a/modules/context/base.go b/modules/context/base.go index 5ae5e65d3ed..45f33feb080 100644 --- a/modules/context/base.go +++ b/modules/context/base.go @@ -96,7 +96,11 @@ func (b *Base) SetTotalCountHeader(total int64) { // Written returns true if there are something sent to web browser func (b *Base) Written() bool { - return b.Resp.Status() > 0 + return b.Resp.WrittenStatus() != 0 +} + +func (b *Base) WrittenStatus() int { + return b.Resp.WrittenStatus() } // Status writes status code @@ -136,6 +140,10 @@ func (b *Base) JSONRedirect(redirect string) { b.JSON(http.StatusOK, map[string]any{"redirect": redirect}) } +func (b *Base) JSONError(msg string) { + b.JSON(http.StatusBadRequest, map[string]any{"errorMessage": msg}) +} + // RemoteAddr returns the client machine ip address func (b *Base) RemoteAddr() string { return b.Req.RemoteAddr diff --git a/modules/context/context.go b/modules/context/context.go index 9e351432c4c..93d448fca55 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -21,7 +21,9 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" + web_types "code.gitea.io/gitea/modules/web/types" "gitea.com/go-chi/cache" "gitea.com/go-chi/session" @@ -58,6 +60,12 @@ type Context struct { Package *Package } +func init() { + web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider { + return req.Context().Value(WebContextKey).(*Context) + }) +} + // TrHTMLEscapeArgs runs ".Locale.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 { diff --git a/modules/context/context_response.go b/modules/context/context_response.go index 1f215eb8ad5..88e375986cd 100644 --- a/modules/context/context_response.go +++ b/modules/context/context_response.go @@ -16,6 +16,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" @@ -49,14 +50,7 @@ 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[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))) { + if httplib.IsRiskyRedirectURL(loc) { continue } diff --git a/modules/context/private.go b/modules/context/private.go index 41ca8a4709c..2e9b31140ab 100644 --- a/modules/context/private.go +++ b/modules/context/private.go @@ -11,6 +11,8 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/web" + web_types "code.gitea.io/gitea/modules/web/types" ) // PrivateContext represents a context for private routes @@ -21,6 +23,12 @@ type PrivateContext struct { Repo *Repository } +func init() { + web.RegisterResponseStatusProvider[*PrivateContext](func(req *http.Request) web_types.ResponseStatusProvider { + return req.Context().Value(privateContextKey).(*PrivateContext) + }) +} + // Deadline is part of the interface for context.Context and we pass this to the request context func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) { if ctx.Override != nil { diff --git a/modules/context/response.go b/modules/context/response.go index 8708d77da0a..2f271f211b8 100644 --- a/modules/context/response.go +++ b/modules/context/response.go @@ -5,15 +5,20 @@ package context import ( "net/http" + + web_types "code.gitea.io/gitea/modules/web/types" ) // ResponseWriter represents a response writer for HTTP type ResponseWriter interface { http.ResponseWriter http.Flusher - Status() int + web_types.ResponseStatusProvider + Before(func(ResponseWriter)) - Size() int // used by access logger template + + Status() int // used by access logger template + Size() int // used by access logger template } var _ ResponseWriter = &Response{} @@ -46,6 +51,10 @@ func (r *Response) Write(bs []byte) (int, error) { return size, nil } +func (r *Response) Status() int { + return r.status +} + func (r *Response) Size() int { return r.written } @@ -71,8 +80,8 @@ func (r *Response) Flush() { } } -// Status returned status code written -func (r *Response) Status() int { +// WrittenStatus returned status code written +func (r *Response) WrittenStatus() int { return r.status } diff --git a/modules/git/sha1.go b/modules/git/sha1.go index 4d69653e09a..7d9d9776da9 100644 --- a/modules/git/sha1.go +++ b/modules/git/sha1.go @@ -28,6 +28,14 @@ func IsValidSHAPattern(sha string) bool { return shaPattern.MatchString(sha) } +type ErrInvalidSHA struct { + SHA string +} + +func (err ErrInvalidSHA) Error() string { + return fmt.Sprintf("invalid sha: %s", err.SHA) +} + // MustID always creates a new SHA1 from a [20]byte array with no validation of input. func MustID(b []byte) SHA1 { var id SHA1 diff --git a/modules/httplib/url.go b/modules/httplib/url.go new file mode 100644 index 00000000000..14b95898f5b --- /dev/null +++ b/modules/httplib/url.go @@ -0,0 +1,27 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package httplib + +import ( + "net/url" + "strings" + + "code.gitea.io/gitea/modules/setting" +) + +// IsRiskyRedirectURL returns true if the URL is considered risky for redirects +func IsRiskyRedirectURL(s string) bool { + // 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(s) > 1 && (s[0] == '/' || s[0] == '\\') && (s[1] == '/' || s[1] == '\\') { + return true + } + + u, err := url.Parse(s) + if err != nil || ((u.Scheme != "" || u.Host != "") && !strings.HasPrefix(strings.ToLower(s), strings.ToLower(setting.AppURL))) { + return true + } + + return false +} diff --git a/modules/httplib/url_test.go b/modules/httplib/url_test.go new file mode 100644 index 00000000000..72033b1208c --- /dev/null +++ b/modules/httplib/url_test.go @@ -0,0 +1,38 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package httplib + +import ( + "testing" + + "code.gitea.io/gitea/modules/setting" + + "github.com/stretchr/testify/assert" +) + +func TestIsRiskyRedirectURL(t *testing.T) { + setting.AppURL = "http://localhost:3000/" + tests := []struct { + input string + want bool + }{ + {"", false}, + {"foo", false}, + {"/", false}, + {"/foo?k=%20#abc", false}, + + {"//", true}, + {"\\\\", true}, + {"/\\", true}, + {"\\/", true}, + {"mail:a@b.com", true}, + {"https://test.com", true}, + {setting.AppURL + "/foo", false}, + } + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + assert.Equal(t, tt.want, IsRiskyRedirectURL(tt.input)) + }) + } +} diff --git a/modules/setting/mirror.go b/modules/setting/mirror.go index cd6b8d45624..3aa530a1f48 100644 --- a/modules/setting/mirror.go +++ b/modules/setting/mirror.go @@ -30,7 +30,7 @@ func loadMirrorFrom(rootCfg ConfigProvider) { // DEPRECATED should not be removed because users maybe upgrade from lower version to the latest version // if these are removed, the warning will not be shown deprecatedSetting(rootCfg, "repository", "DISABLE_MIRRORS", "mirror", "ENABLED", "v1.19.0") - if rootCfg.Section("repository").Key("DISABLE_MIRRORS").MustBool(false) { + if ConfigSectionKeyBool(rootCfg.Section("repository"), "DISABLE_MIRRORS") { Mirror.DisableNewPull = true } diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 4dab468c102..836a2bb25f4 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -120,18 +120,20 @@ func loadOAuth2From(rootCfg ConfigProvider) { OAuth2.JWTSigningPrivateKeyFile = filepath.Join(AppDataPath, OAuth2.JWTSigningPrivateKeyFile) } - key := make([]byte, 32) - n, err := base64.RawURLEncoding.Decode(key, []byte(OAuth2.JWTSecretBase64)) - if err != nil || n != 32 { - key, err = generate.NewJwtSecret() - if err != nil { - log.Fatal("error generating JWT secret: %v", err) - } + if InstallLock { + key := make([]byte, 32) + n, err := base64.RawURLEncoding.Decode(key, []byte(OAuth2.JWTSecretBase64)) + if err != nil || n != 32 { + key, err = generate.NewJwtSecret() + if err != nil { + log.Fatal("error generating JWT secret: %v", err) + } - secretBase64 := base64.RawURLEncoding.EncodeToString(key) - rootCfg.Section("oauth2").Key("JWT_SECRET").SetValue(secretBase64) - if err := rootCfg.Save(); err != nil { - log.Fatal("save oauth2.JWT_SECRET failed: %v", err) + secretBase64 := base64.RawURLEncoding.EncodeToString(key) + rootCfg.Section("oauth2").Key("JWT_SECRET").SetValue(secretBase64) + if err := rootCfg.Save(); err != nil { + log.Fatal("save oauth2.JWT_SECRET failed: %v", err) + } } } } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 293333a95bc..539eb4b1976 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -262,7 +262,7 @@ func loadRunModeFrom(rootCfg ConfigProvider) { RunUser = rootSec.Key("RUN_USER").MustString(user.CurrentUsername()) // 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 := rootSec.Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false) + unsafeAllowRunAsRoot := ConfigSectionKeyBool(rootSec, "I_AM_BEING_UNSAFE_RUNNING_AS_ROOT") RunMode = os.Getenv("GITEA_RUN_MODE") if RunMode == "" { RunMode = rootSec.Key("RUN_MODE").MustString("prod") diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index 349c7e3e804..cf8af32fc69 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -9,6 +9,7 @@ import ( "net/http" "net/http/httptest" "net/url" + "strings" "testing" access_model "code.gitea.io/gitea/models/perm/access" @@ -25,19 +26,26 @@ import ( "github.com/stretchr/testify/assert" ) -// MockContext mock context for unit tests -// TODO: move this function to other packages, because it depends on "models" package -func MockContext(t *testing.T, path string) *context.Context { - resp := httptest.NewRecorder() +func mockRequest(t *testing.T, reqPath string) *http.Request { + method, path, found := strings.Cut(reqPath, " ") + if !found { + method = "GET" + path = reqPath + } requestURL, err := url.Parse(path) assert.NoError(t, err) - req := &http.Request{ - URL: requestURL, - Form: url.Values{}, - } + req := &http.Request{Method: method, URL: requestURL, Form: url.Values{}} + req = req.WithContext(middleware.WithContextData(req.Context())) + return req +} +// MockContext mock context for unit tests +// TODO: move this function to other packages, because it depends on "models" package +func MockContext(t *testing.T, reqPath string) (*context.Context, *httptest.ResponseRecorder) { + resp := httptest.NewRecorder() + req := mockRequest(t, reqPath) base, baseCleanUp := context.NewBaseContext(resp, req) - base.Data = middleware.ContextData{} + base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} ctx := &context.Context{ Base: base, @@ -48,29 +56,23 @@ func MockContext(t *testing.T, path string) *context.Context { chiCtx := chi.NewRouteContext() ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) - return ctx + return ctx, resp } // MockAPIContext mock context for unit tests // TODO: move this function to other packages, because it depends on "models" package -func MockAPIContext(t *testing.T, path string) *context.APIContext { +func MockAPIContext(t *testing.T, reqPath string) (*context.APIContext, *httptest.ResponseRecorder) { resp := httptest.NewRecorder() - requestURL, err := url.Parse(path) - assert.NoError(t, err) - req := &http.Request{ - URL: requestURL, - Form: url.Values{}, - } - + req := mockRequest(t, reqPath) base, baseCleanUp := context.NewBaseContext(resp, req) - base.Data = middleware.ContextData{} + base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} ctx := &context.APIContext{Base: base} _ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later chiCtx := chi.NewRouteContext() ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) - return ctx + return ctx, resp } // LoadRepo load a repo into a test context. diff --git a/modules/test/utils.go b/modules/test/utils.go index 282895eaa90..2917741c45a 100644 --- a/modules/test/utils.go +++ b/modules/test/utils.go @@ -5,12 +5,29 @@ package test import ( "net/http" + "net/http/httptest" "strings" + + "code.gitea.io/gitea/modules/json" ) // RedirectURL returns the redirect URL of a http response. +// It also works for JSONRedirect: `{"redirect": "..."}` func RedirectURL(resp http.ResponseWriter) string { - return resp.Header().Get("Location") + loc := resp.Header().Get("Location") + if loc != "" { + return loc + } + if r, ok := resp.(*httptest.ResponseRecorder); ok { + m := map[string]any{} + err := json.Unmarshal(r.Body.Bytes(), &m) + if err == nil { + if loc, ok := m["redirect"].(string); ok { + return loc + } + } + } + return "" } func IsNormalPageCompleted(s string) bool { diff --git a/modules/web/handler.go b/modules/web/handler.go index c8aebd90518..26b7428016c 100644 --- a/modules/web/handler.go +++ b/modules/web/handler.go @@ -9,25 +9,15 @@ import ( "net/http" "reflect" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/web/routing" + "code.gitea.io/gitea/modules/web/types" ) -// ResponseStatusProvider is an interface to check whether the response has been written by the handler -type ResponseStatusProvider interface { - Written() bool -} +var responseStatusProviders = map[reflect.Type]func(req *http.Request) types.ResponseStatusProvider{} -// TODO: decouple this from the context package, let the context package register these providers -var argTypeProvider = map[reflect.Type]func(req *http.Request) ResponseStatusProvider{ - reflect.TypeOf(&context.APIContext{}): func(req *http.Request) ResponseStatusProvider { return context.GetAPIContext(req) }, - reflect.TypeOf(&context.Context{}): func(req *http.Request) ResponseStatusProvider { return context.GetWebContext(req) }, - reflect.TypeOf(&context.PrivateContext{}): func(req *http.Request) ResponseStatusProvider { return context.GetPrivateContext(req) }, -} - -func RegisterHandleTypeProvider[T any](fn func(req *http.Request) ResponseStatusProvider) { - argTypeProvider[reflect.TypeOf((*T)(nil)).Elem()] = fn +func RegisterResponseStatusProvider[T any](fn func(req *http.Request) types.ResponseStatusProvider) { + responseStatusProviders[reflect.TypeOf((*T)(nil)).Elem()] = fn } // responseWriter is a wrapper of http.ResponseWriter, to check whether the response has been written @@ -36,10 +26,10 @@ type responseWriter struct { status int } -var _ ResponseStatusProvider = (*responseWriter)(nil) +var _ types.ResponseStatusProvider = (*responseWriter)(nil) -func (r *responseWriter) Written() bool { - return r.status > 0 +func (r *responseWriter) WrittenStatus() int { + return r.status } func (r *responseWriter) Header() http.Header { @@ -68,7 +58,7 @@ var ( func preCheckHandler(fn reflect.Value, argsIn []reflect.Value) { hasStatusProvider := false for _, argIn := range argsIn { - if _, hasStatusProvider = argIn.Interface().(ResponseStatusProvider); hasStatusProvider { + if _, hasStatusProvider = argIn.Interface().(types.ResponseStatusProvider); hasStatusProvider { break } } @@ -101,7 +91,7 @@ func prepareHandleArgsIn(resp http.ResponseWriter, req *http.Request, fn reflect case httpReqType: argsIn[i] = reflect.ValueOf(req) default: - if argFn, ok := argTypeProvider[argTyp]; ok { + if argFn, ok := responseStatusProviders[argTyp]; ok { if isPreCheck { argsIn[i] = reflect.ValueOf(&responseWriter{}) } else { @@ -129,8 +119,8 @@ func handleResponse(fn reflect.Value, ret []reflect.Value) goctx.CancelFunc { func hasResponseBeenWritten(argsIn []reflect.Value) bool { for _, argIn := range argsIn { - if statusProvider, ok := argIn.Interface().(ResponseStatusProvider); ok { - if statusProvider.Written() { + if statusProvider, ok := argIn.Interface().(types.ResponseStatusProvider); ok { + if statusProvider.WrittenStatus() != 0 { return true } } @@ -161,7 +151,7 @@ func toHandlerProvider(handler any) func(next http.Handler) http.Handler { return http.HandlerFunc(func(respOrig http.ResponseWriter, req *http.Request) { // wrap the response writer to check whether the response has been written resp := respOrig - if _, ok := resp.(ResponseStatusProvider); !ok { + if _, ok := resp.(types.ResponseStatusProvider); !ok { resp = &responseWriter{respWriter: resp} } diff --git a/modules/web/middleware/data.go b/modules/web/middleware/data.go index c1f0516d7d2..9497dc02e23 100644 --- a/modules/web/middleware/data.go +++ b/modules/web/middleware/data.go @@ -17,7 +17,7 @@ type ContextDataStore interface { type ContextData map[string]any -func (ds ContextData) GetData() map[string]any { +func (ds ContextData) GetData() ContextData { return ds } diff --git a/modules/web/route.go b/modules/web/route.go index d801f1025c9..db511aeb185 100644 --- a/modules/web/route.go +++ b/modules/web/route.go @@ -7,31 +7,31 @@ import ( "net/http" "strings" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web/middleware" "gitea.com/go-chi/binding" - chi "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5" ) -// Bind binding an obj to a handler -func Bind[T any](_ T) any { - return func(ctx *context.Context) { +// Bind binding an obj to a handler's context data +func Bind[T any](_ T) http.HandlerFunc { + return func(resp http.ResponseWriter, req *http.Request) { theObj := new(T) // 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) + data := middleware.GetContextData(req.Context()) + binding.Bind(req, theObj) + SetForm(data, theObj) + middleware.AssignForm(theObj, data) } } // SetForm set the form object -func SetForm(data middleware.ContextDataStore, obj interface{}) { - data.GetData()["__form"] = obj +func SetForm(dataStore middleware.ContextDataStore, obj interface{}) { + dataStore.GetData()["__form"] = obj } // GetForm returns the validate form information -func GetForm(data middleware.ContextDataStore) interface{} { - return data.GetData()["__form"] +func GetForm(dataStore middleware.ContextDataStore) interface{} { + return dataStore.GetData()["__form"] } // Route defines a route based on chi's router diff --git a/modules/web/routing/logger.go b/modules/web/routing/logger.go index b58065aa736..6a4dae66f79 100644 --- a/modules/web/routing/logger.go +++ b/modules/web/routing/logger.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/web/types" ) // NewLoggerHandler is a handler that will log routing to the router log taking account of @@ -86,8 +86,8 @@ func logPrinter(logger log.Logger) func(trigger Event, record *requestRecord) { } var status int - if v, ok := record.responseWriter.(context.ResponseWriter); ok { - status = v.Status() + if v, ok := record.responseWriter.(types.ResponseStatusProvider); ok { + status = v.WrittenStatus() } logf := log.Info if strings.HasPrefix(req.RequestURI, "/assets/") { diff --git a/modules/web/types/response.go b/modules/web/types/response.go new file mode 100644 index 00000000000..834f4912f4d --- /dev/null +++ b/modules/web/types/response.go @@ -0,0 +1,10 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package types + +// ResponseStatusProvider is an interface to get the written status in the response +// Many packages need this interface, so put it in the separate package to avoid import cycle +type ResponseStatusProvider interface { + WrittenStatus() int +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 738c1ecd71c..59364514395 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1159,6 +1159,7 @@ video_not_supported_in_browser = Your browser does not support the HTML5 'video' audio_not_supported_in_browser = Your browser does not support the HTML5 'audio' tag. stored_lfs = Stored with Git LFS symbolic_link = Symbolic link +executable_file = Executable File commit_graph = Commit Graph commit_graph.select = Select branches commit_graph.hide_pr_refs = Hide Pull Requests @@ -2904,7 +2905,7 @@ auths.sspi_default_language = Default user language auths.sspi_default_language_helper = Default language for users automatically created by SSPI auth method. Leave empty if you prefer language to be automatically detected. auths.tips = Tips auths.tips.oauth2.general = OAuth2 Authentication -auths.tips.oauth2.general.tip = When registering a new OAuth2 authentication, the callback/redirect URL should be: /user/oauth2//callback +auths.tips.oauth2.general.tip = When registering a new OAuth2 authentication, the callback/redirect URL should be: auths.tip.oauth2_provider = OAuth2 Provider auths.tip.bitbucket = Register a new OAuth consumer on https://bitbucket.org/account/user//oauth-consumers/new and add the permission 'Account' - 'Read' auths.tip.nextcloud = Register a new OAuth consumer on your instance using the following menu "Settings -> Security -> OAuth 2.0 client" diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 1633a5a805b..1818343f92f 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -79,6 +79,8 @@ milestones=マイルストーン ok=OK cancel=キャンセル +rerun=再実行 +rerun_all=すべてのジョブを再実行 save=保存 add=追加 add_all=すべて追加 @@ -113,11 +115,19 @@ unknown=不明 rss_feed=RSSフィード +pin=ピン留め +unpin=ピン留め解除 +artifacts=成果物 +concept_system_global=グローバル +concept_user_individual=個人 concept_code_repository=リポジトリ concept_user_organization=組織 +show_timestamps=タイムスタンプを表示 +show_log_seconds=秒数を表示 +show_full_screen=フルスクリーン表示 [aria] navbar=ナビゲーションバー @@ -314,6 +324,7 @@ repos=リポジトリ users=ユーザー organizations=組織 search=検索 +go_to=開く code=コード search.type.tooltip=検索タイプ search.fuzzy=あいまい @@ -517,6 +528,7 @@ lang_select_error=言語をリストから選択してください。 username_been_taken=ユーザー名が既に使用されています。 username_change_not_local_user=非ローカルユーザーのユーザー名は変更できません。 +username_has_not_been_changed=ユーザー名は変更されていません repo_name_been_taken=リポジトリ名が既に使用されています。 repository_force_private=強制プライベートが有効です。プライベートリポジトリはパブリックにできません。 repository_files_already_exist=このリポジトリのファイルはすでに存在します。システム管理者に問い合わせてください。 @@ -565,6 +577,7 @@ target_branch_not_exist=ターゲットのブランチが存在していませ [user] change_avatar=アバターを変更… +joined_on=%sに登録 repositories=リポジトリ activity=公開アクティビティ followers=フォロワー @@ -760,6 +773,8 @@ ssh_principal_deletion_desc=SSH証明書プリンシパルを削除して、ア ssh_key_deletion_success=SSHキーを削除しました。 gpg_key_deletion_success=GPGキーを削除しました。 ssh_principal_deletion_success=プリンシパルを削除しました。 +added_on=%sに追加 +valid_until_date=%sまで有効 valid_forever=永久に有効 last_used=最終使用日 no_activity=使用されていません @@ -791,6 +806,13 @@ access_token_deletion_cancel_action=キャンセル access_token_deletion_confirm_action=削除 access_token_deletion_desc=トークンを削除すると、それを使用しているアプリケーションは、アカウントへのアクセスができなくなります。これは元に戻せません。続行しますか? delete_token_success=トークンを削除しました。 削除したトークンを使用しているアプリケーションは、今後あなたのアカウントにアクセスできません。 +repo_and_org_access=リポジトリと組織へのアクセス +permissions_public_only=公開のみ +permissions_access_all=すべて (公開、プライベート、限定) +select_permissions=許可の選択 +scoped_token_desc=認証は、選択したトークンスコープに対応するAPIルートのみに制限されます。 詳細はドキュメントを参照してください。 +at_least_one_permission=トークンを作成するには、少なくともひとつの許可を選択する必要があります +permissions_list=許可: manage_oauth2_applications=OAuth2アプリケーションの管理 edit_oauth2_application=OAuth2アプリケーションの編集 @@ -804,6 +826,7 @@ create_oauth2_application_success=新しいOAuth2アプリケーションを作 update_oauth2_application_success=OAuth2アプリケーションを更新しました。 oauth2_application_name=アプリケーション名 oauth2_confidential_client=コンフィデンシャルクライアント。 ウェブアプリのように秘密情報を機密にできるアプリの場合に選択します。 デスクトップアプリやモバイルアプリなどのネイティブアプリには選択しないでください。 +oauth2_redirect_uris=リダイレクトURI (複数可)。 URIごとに改行してください。 save_application=保存 oauth2_client_id=クライアントID oauth2_client_secret=クライアント シークレット @@ -912,7 +935,7 @@ repo_desc=説明 repo_desc_helper=簡単な説明を入力してください (オプション) repo_lang=言語 repo_gitignore_helper=.gitignoreテンプレートを選択してください。 -repo_gitignore_helper_desc=追跡しないファイルの設定を、一般的な言語について用意されたテンプレートから選択します。 .gitignoreには、それぞれの言語のビルドツールが生成するファイルで、よくあるものがデフォルトで含まれています。 +repo_gitignore_helper_desc=一般的な言語のテンプレートリストから、追跡しないファイルの設定を選択します。 各言語のビルドツールが生成する典型的なファイルが、デフォルトで.gitignoreに含まれます。 issue_labels=イシューラベル issue_labels_helper=イシューのラベルセットを選択 license=ライセンス @@ -949,6 +972,7 @@ mirror_password_blank_placeholder=(未設定) mirror_password_help=ユーザー名を変更すると保存されているパスワードは消去されます。 watchers=ウォッチャー stargazers=スターゲイザー +stars_remove_warning=これを指定すると、このリポジトリのスターはすべて削除されます。 forks=フォーク reactions_more=さらに %d 件 unit_disabled=サイト管理者がこのリポジトリセクションを無効にしています。 @@ -992,6 +1016,7 @@ template.one_item=最低一つはテンプレート項目を選択する必要 template.invalid=テンプレートリポジトリを選択する必要があります archive.title=このリポジトリはアーカイブされています。 ファイルの閲覧とクローンは可能ですが、プッシュや、イシュー・プルリクエストのオープンはできません。 +archive.title_date=このリポジトリは%sにアーカイブされています。 ファイルの閲覧やリポジトリのクローンは可能ですが、プッシュしたり、イシューやプルリクエストを作成することはできません。 archive.issue.nocomment=このリポジトリはアーカイブされています。 イシューにコメントを追加することはできません。 archive.pull.nocomment=このリポジトリはアーカイブされています。 プルリクエストにコメントを追加することはできません。 @@ -1033,6 +1058,7 @@ migrated_from_fake=%[1]sから移行 migrate.migrate=%s からの移行 migrate.migrating=%s から移行しています ... migrate.migrating_failed=%s からの移行が失敗しました。 +migrate.migrating_failed.error=移行に失敗しました: %s migrate.migrating_failed_no_addr=移行に失敗しました。 migrate.github.description=github.com やその他の GitHub インスタンスからデータを移行します。 migrate.git.description=Git サービスからリポジトリのみを移行します。 @@ -1049,6 +1075,8 @@ migrate.migrating_labels=ラベル移行中 migrate.migrating_releases=リリース移行中 migrate.migrating_issues=イシュー移行中 migrate.migrating_pulls=プルリクエスト移行中 +migrate.cancel_migrating_title=移行のキャンセル +migrate.cancel_migrating_confirm=この移行をキャンセルしますか? mirror_from=ミラー元 forked_from=フォーク元 @@ -1178,6 +1206,8 @@ editor.filename_is_invalid=`ファイル名が不正です: "%s"` editor.branch_does_not_exist=このリポジトリにブランチ "%s" は存在しません。 editor.branch_already_exists=ブランチ "%s" は、このリポジトリに既に存在します。 editor.directory_is_a_file=ディレクトリ名 "%s" はすでにリポジトリ内のファイルで使用されています。 +editor.file_is_a_symlink=`"%s" はシンボリックリンクです。 シンボリックリンクはWebエディターで編集できません。` +editor.filename_is_a_directory=ファイル名 "%s" は、このリポジトリ上でディレクトリ名としてすでに使用されています。 editor.file_editing_no_longer_exists=編集中のファイル "%s" が、もうリポジトリ内にありません。 editor.file_deleting_no_longer_exists=削除しようとしたファイル "%s" が、すでにリポジトリ内にありません。 editor.file_changed_while_editing=あなたが編集を開始したあと、ファイルの内容が変更されました。 ここをクリックして何が変更されたか確認するか、もう一度"変更をコミット"をクリックして上書きします。 @@ -1343,6 +1373,10 @@ issues.filter_label_exclude=`ラベルで除外するには alt + < issues.filter_label_no_select=すべてのラベル issues.filter_label_select_no_label=ラベルなし issues.filter_milestone=マイルストーン +issues.filter_milestone_all=すべてのマイルストーン +issues.filter_milestone_none=マイルストーンなし +issues.filter_milestone_open=オープン中のマイルストーン +issues.filter_milestone_closed=クローズ済みマイルストーン issues.filter_project=プロジェクト issues.filter_project_all=すべてのプロジェクト issues.filter_project_none=プロジェクトなし @@ -1402,6 +1436,8 @@ issues.context.edit=編集 issues.context.delete=削除 issues.no_content=まだ内容がありません issues.close=イシューをクローズ +issues.comment_pull_merged_at=がコミット %[1]s を %[2]s にマージ %[3]s +issues.comment_manually_pull_merged_at=がコミット %[1]s を %[2]s に手動マージ %[3]s issues.close_comment_issue=コメントしてクローズ issues.reopen_issue=再オープンする issues.reopen_comment_issue=コメントして再オープン @@ -1452,6 +1488,10 @@ issues.attachment.open_tab=`クリックして新しいタブで "%s" を見る` issues.attachment.download=`クリックして "%s" をダウンロード` issues.subscribe=購読する issues.unsubscribe=購読を解除 +issues.unpin_issue=イシューのピン留めを解除 +issues.max_pinned=これ以上イシューをピン留めできません +issues.pin_comment=がピン留め %s +issues.unpin_comment=がピン留めを解除 %s issues.lock=会話をロック issues.unlock=会話をアンロック issues.lock.unknown_reason=未定義の理由ではイシューをロックできません。 @@ -1531,6 +1571,7 @@ issues.dependency.issue_closing_blockedby=このイシューのクローズは issues.dependency.issue_close_blocks=このイシューは、これらのイシューのクローズをブロックしています issues.dependency.pr_close_blocks=このプルリクエストは、これらのイシューのクローズをブロックしています issues.dependency.issue_close_blocked=このイシューをクローズするには、ブロックしているイシューをすべてクローズする必要があります。 +issues.dependency.issue_batch_close_blocked=選択したイシューの一括クローズはできません。 イシュー #%d に、まだオープン中の依存関係があります。 issues.dependency.pr_close_blocked=このプルリクエストを操作するには、ブロックしているイシューをすべてクローズする必要があります。 issues.dependency.blocks_short=ブロック対象 issues.dependency.blocked_by_short=依存先 @@ -1876,6 +1917,16 @@ settings.hooks=Webhook settings.githooks=Gitフック settings.basic_settings=基本設定 settings.mirror_settings=ミラー設定 +settings.mirror_settings.docs=コミット、タグ、ブランチを他のリポジトリと自動的に同期するように、このリポジトリを設定します。 +settings.mirror_settings.docs.disabled_pull_mirror.instructions=コミット、タグ、ブランチを他のリポジトリに自動的にプッシュするように、このプロジェクトを設定します。 プル方式のミラーはサイト管理者により無効化されています。 +settings.mirror_settings.docs.disabled_push_mirror.instructions=コミット、タグ、ブランチを他のリポジトリから自動的にプルするように、このプロジェクトを設定します。 +settings.mirror_settings.docs.disabled_push_mirror.pull_mirror_warning=現在は「新しい移行」メニューでのみ対応しています。 詳細は次を参照: +settings.mirror_settings.docs.disabled_push_mirror.info=プッシュ方式のミラーはサイト管理者により無効化されています。 +settings.mirror_settings.docs.no_new_mirrors=このリポジトリは他のリポジトリと変更をミラーリングしています。 現時点では新しいミラーを作成することはできないことに留意してください。 +settings.mirror_settings.docs.can_still_use=既存ミラーを変更したりミラーを新規に作成することはできませんが、既存ミラーを利用することは可能です。 +settings.mirror_settings.docs.pull_mirror_instructions=プル方式のミラーを設定するには、次を参照: +settings.mirror_settings.docs.doc_link_title=リポジトリをミラーリングするには? +settings.mirror_settings.docs.pulling_remote_title=リモートリポジトリからのプル settings.mirror_settings.mirrored_repository=同期するリポジトリ settings.mirror_settings.direction=方向 settings.mirror_settings.direction.pull=プル @@ -1888,6 +1939,8 @@ settings.sync_mirror=今すぐ同期 settings.mirror_sync_in_progress=ミラー同期を実行しています。 しばらくあとでまた確認してください。 settings.site=Webサイト settings.update_settings=設定を更新 +settings.update_mirror_settings=ミラーリング設定を更新 +settings.branches.switch_default_branch=デフォルトブランチを切り替え settings.branches.update_default_branch=デフォルトブランチを更新 settings.branches.add_new_rule=新しいルールを追加 settings.advanced_settings=拡張設定 @@ -1986,6 +2039,7 @@ settings.delete_notices_2=- この操作は、リポジトリ %s%s' の保護ルール settings.protect_this_branch=ブランチの保護を有効にする settings.protect_this_branch_desc=ブランチの削除を防ぎ、ブランチへのプッシュやマージを制限します。 settings.protect_disable_push=プッシュ無効 settings.protect_disable_push_desc=このブランチへのプッシュは許可されません。 settings.protect_enable_push=プッシュ有効 settings.protect_enable_push_desc=誰でも書き込み権限があれば、このブランチへのプッシュが許可されます。(強制プッシュ以外) +settings.protect_enable_merge=マージ有効 +settings.protect_enable_merge_desc=誰でも書き込み権限があれば、このブランチへのプルリクエストのマージが許可されます。 settings.protect_whitelist_committers=ホワイトリストでプッシュを制限 settings.protect_whitelist_committers_desc=ホワイトリストに登録したユーザーまたはチームにのみ、このブランチへのプッシュが許可されます。(強制プッシュ以外) settings.protect_whitelist_deploy_keys=プッシュ可能な書き込み権限を持つデプロイキーをホワイトリストに含める。 @@ -2156,7 +2217,13 @@ settings.protect_merge_whitelist_committers_desc=ホワイトリストに登録 settings.protect_merge_whitelist_users=マージ・ホワイトリストに含むユーザー: settings.protect_merge_whitelist_teams=マージ・ホワイトリストに含むチーム: settings.protect_check_status_contexts=ステータスチェックを有効にする +settings.protect_status_check_patterns=ステータスチェック パターン: +settings.protect_status_check_patterns_desc=このルールの対象ブランチがマージ可能になる前に、どのステータスチェックがパスしなければならないかを、パターンで入力します。 各行にパターンを指定します。 この設定は空にできません。 +settings.protect_check_status_contexts_desc=マージの前にステータスチェックがパスしていることを必須にします。 有効にした場合、まず他のブランチにコミットをプッシュしておき、このルールの対象ブランチのステータスチェックがパスしたあとに、マージまたは直接プッシュする必要があります。 マッチするコンテキストが無い場合は、コンテキストに関係なく最後のコミットが成功している必要があります。 settings.protect_check_status_contexts_list=この1週間に、このリポジトリに対して行われたステータスチェック +settings.protect_status_check_matched=マッチ +settings.protect_invalid_status_check_pattern=`不正なステータスチェックパターン: "%s"` +settings.protect_no_valid_status_check_patterns=有効なステータスチェックパターンがありません。 settings.protect_required_approvals=必要な承認数: settings.protect_required_approvals_desc=肯定的なレビューの数を満たしたプルリクエストしかマージできないようにします。 settings.protect_approvals_whitelist_enabled=ホワイトリストに登録したユーザーやチームに承認を制限 @@ -2168,6 +2235,7 @@ settings.dismiss_stale_approvals_desc=プルリクエストの内容を変える settings.require_signed_commits=コミット署名必須 settings.require_signed_commits_desc=署名されていない場合、または署名が検証できなかった場合は、このブランチへのプッシュを拒否します。 settings.protect_branch_name_pattern=保護ブランチ名のパターン +settings.protect_patterns=パターン settings.protect_protected_file_patterns=保護されるファイルのパターン (セミコロン';'で区切る): settings.protect_protected_file_patterns_desc=保護されたファイルは、このブランチにファイルを追加・編集・削除する権限を持つユーザーであっても、直接変更することができなくなります。 セミコロン(';')で区切って複数のパターンを指定できます。 パターンの文法については github.com/gobwas/glob を参照してください。 例: .drone.yml, /docs/**/*.txt settings.protect_unprotected_file_patterns=保護しないファイルのパターン (セミコロン';'で区切る): @@ -2382,10 +2450,13 @@ branch.protected_deletion_failed=ブランチ "%s" は保護されています branch.default_deletion_failed=ブランチ "%s" はデフォルトブランチです。 削除できません。 branch.restore=ブランチ "%s" の復元 branch.download=ブランチ "%s" をダウンロード +branch.rename=ブランチ名 "%s" を変更 branch.included_desc=このブランチはデフォルトブランチに含まれています branch.included=埋没 branch.create_new_branch=このブランチをもとに作成します: branch.confirm_create_branch=ブランチを作成 +branch.warning_rename_default_branch=デフォルトブランチの名前を変更しようとしています。 +branch.rename_branch_to=`"%s" を変更:` branch.confirm_rename_branch=ブランチ名を変更 branch.create_branch_operation=ブランチを作成 branch.new_branch=新しいブランチの作成 @@ -2944,6 +3015,7 @@ config.mailer_sendmail_timeout=Sendmail のタイムアウト config.mailer_use_dummy=Dummy config.test_email_placeholder=Email (例 test@example.com) config.send_test_mail=テストメールを送信 +config.send_test_mail_submit=送信 config.test_mail_failed=`"%s" へのテストメール送信に失敗しました: %v` config.test_mail_sent=テストメールを "%s" へ送信しました。 @@ -2983,13 +3055,16 @@ config.git_pull_timeout=プル操作のタイムアウト config.git_gc_timeout=GC操作のタイムアウト config.log_config=ログ設定 +config.logger_name_fmt=ロガー: %s config.disabled_logger=無効 config.access_log_mode=アクセスログのモード +config.access_log_template=アクセスログ テンプレート config.xorm_log_sql=SQLのログ出力 config.get_setting_failed=%s の取得に失敗しました config.set_setting_failed=%s の設定に失敗しました +monitor.stats=統計 monitor.cron=Cronタスク monitor.name=名称 @@ -2999,6 +3074,8 @@ monitor.previous=前回 monitor.execute_times=実行回数 monitor.process=実行中のプロセス monitor.stacktrace=スタックトレース +monitor.processes_count=%d プロセス +monitor.download_diagnosis_report=診断レポートをダウンロード monitor.desc=説明 monitor.start=開始日時 monitor.execute_time=実行時間 @@ -3019,11 +3096,14 @@ monitor.queue.numberinqueue=キュー内の数 monitor.queue.review=設定確認 monitor.queue.review_add=確認/ワーカー追加 monitor.queue.settings.title=プール設定 +monitor.queue.settings.desc=プールはワーカーキューの待機状態に応じて動的に大きくなります。 monitor.queue.settings.maxnumberworkers=ワーカー数上限 monitor.queue.settings.maxnumberworkers.placeholder=現在の設定 %[1]d monitor.queue.settings.maxnumberworkers.error=ワーカー数上限は数値にしてください monitor.queue.settings.submit=設定を更新 monitor.queue.settings.changed=設定を更新しました +monitor.queue.settings.remove_all_items=すべて削除 +monitor.queue.settings.remove_all_items_done=キュー内のすべての項目を削除しました。 notices.system_notice_list=システム通知 notices.view_detail_header=通知の詳細を表示 @@ -3158,9 +3238,15 @@ versions=バージョン versions.view_all=すべて表示 dependency.id=ID dependency.version=バージョン +alpine.registry=あなたの /etc/apk/repositories ファイルにURLを追加して、このレジストリをセットアップします: +alpine.registry.key=インデックス署名の検証のため、レジストリのRSA公開鍵を /etc/apk/keys/ フォルダにダウンロードします: +alpine.registry.info=$branch と $repository は下にあるリストから選んでください。 alpine.install=パッケージをインストールするには、次のコマンドを実行します: -alpine.repository.branches=ブランチ -alpine.repository.repositories=リポジトリ +alpine.documentation=Alpine レジストリの詳細については、ドキュメント を参照してください。 +alpine.repository=リポジトリ情報 +alpine.repository.branches=Branches +alpine.repository.repositories=Repositories +alpine.repository.architectures=Architectures cargo.registry=Cargo 設定ファイルでこのレジストリをセットアップします。(例 ~/.cargo/config.toml): cargo.install=Cargo を使用してパッケージをインストールするには、次のコマンドを実行します: cargo.documentation=Cargoレジストリの詳細については、 ドキュメント を参照してください。 @@ -3193,11 +3279,21 @@ container.layers=イメージレイヤー container.labels=ラベル container.labels.key=キー container.labels.value=値 +cran.registry=あなたの Rprofile.site ファイルに、このレジストリをセットアップします: cran.install=パッケージをインストールするには、次のコマンドを実行します: +cran.documentation=CRAN レジストリの詳細については、ドキュメント を参照してください。 debian.registry=このレジストリをコマンドラインからセットアップします: +debian.registry.info=$distribution と $component は下にあるリストから選んでください。 debian.install=パッケージをインストールするには、次のコマンドを実行します: +debian.documentation=Debian レジストリの詳細については、ドキュメント を参照してください。 +debian.repository=リポジトリ情報 +debian.repository.distributions=Distributions +debian.repository.components=Components +debian.repository.architectures=Architectures generic.download=コマンドラインでパッケージをダウンロードします: generic.documentation=汎用 レジストリの詳細については、ドキュメント を参照してください。 +go.install=コマンドラインでパッケージをインストール: +go.documentation=Go レジストリの詳細については、ドキュメント を参照してください。 helm.registry=このレジストリをコマンドラインからセットアップします: helm.install=パッケージをインストールするには、次のコマンドを実行します: helm.documentation=Helm レジストリの詳細については、 ドキュメント を参照してください。 @@ -3226,6 +3322,7 @@ pypi.install=pip を使用してパッケージをインストールするには pypi.documentation=PyPI レジストリの詳細については、ドキュメント を参照してください。 rpm.registry=このレジストリをコマンドラインからセットアップします: rpm.install=パッケージをインストールするには、次のコマンドを実行します: +rpm.documentation=RPM レジストリの詳細については、ドキュメント を参照してください。 rubygems.install=gem を使用してパッケージをインストールするには、次のコマンドを実行します: rubygems.install2=または Gemfile に追加します: rubygems.dependencies.runtime=実行用依存関係 @@ -3298,6 +3395,7 @@ deletion=シークレットの削除 deletion.description=シークレットの削除は恒久的で元に戻すことはできません。 続行しますか? deletion.success=シークレットを削除しました。 deletion.failed=シークレットの削除に失敗しました。 +management=シークレット管理 [actions] actions=Actions diff --git a/package-lock.json b/package-lock.json index 76beea934e3..e808ccf2a8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,8 +4,6 @@ "requires": true, "packages": { "": { - "name": "gitea", - "license": "MIT", "dependencies": { "@citation-js/core": "0.6.8", "@citation-js/plugin-bibtex": "0.6.8", @@ -14,9 +12,9 @@ "@claviska/jquery-minicolors": "2.3.6", "@github/markdown-toolbar-element": "2.1.1", "@github/relative-time-element": "4.3.0", - "@github/text-expander-element": "2.3.0", + "@github/text-expander-element": "2.5.0", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "19.1.0", + "@primer/octicons": "19.3.0", "@webcomponents/custom-elements": "1.6.0", "add-asset-webpack-plugin": "2.0.1", "ansi-to-html": "0.7.2", @@ -32,7 +30,7 @@ "jquery.are-you-sure": "1.9.0", "katex": "0.16.7", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "10.2.2", + "mermaid": "10.2.3", "mini-css-extract-plugin": "2.7.6", "minimatch": "9.0.1", "monaco-editor": "0.39.0", @@ -40,7 +38,7 @@ "pdfobject": "2.2.12", "pretty-ms": "8.0.0", "sortablejs": "1.15.0", - "swagger-ui-dist": "4.19.0", + "swagger-ui-dist": "5.0.0", "throttle-debounce": "5.0.0", "tippy.js": "6.3.7", "tributejs": "5.1.3", @@ -49,17 +47,17 @@ "vue-bar-graph": "2.0.0", "vue-loader": "17.2.2", "vue3-calendar-heatmap": "2.0.5", - "webpack": "5.86.0", + "webpack": "5.87.0", "webpack-cli": "5.1.4", "wrap-ansi": "8.1.0" }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "3.2.1", - "@playwright/test": "1.34.3", + "@playwright/test": "1.35.1", "@rollup/pluginutils": "5.0.2", "@stoplight/spectral-cli": "6.8.0", "@vitejs/plugin-vue": "4.2.3", - "eslint": "8.42.0", + "eslint": "8.43.0", "eslint-plugin-array-func": "3.1.8", "eslint-plugin-custom-elements": "0.0.8", "eslint-plugin-import": "2.27.5", @@ -72,13 +70,15 @@ "eslint-plugin-vue": "9.14.1", "eslint-plugin-wc": "1.5.0", "jsdom": "22.1.0", - "markdownlint-cli": "0.34.0", + "markdownlint-cli": "0.35.0", "postcss-html": "1.5.0", - "stylelint": "15.7.0", + "stylelint": "15.8.0", + "stylelint-declaration-block-no-ignored-properties": "2.7.0", "stylelint-declaration-strict-value": "1.9.2", + "stylelint-stylistic": "0.4.2", "svgo": "3.0.2", - "updates": "14.1.1", - "vitest": "0.32.0" + "updates": "14.2.4", + "vitest": "0.32.2" }, "engines": { "node": ">= 16.0.0" @@ -94,33 +94,33 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -197,9 +197,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.4.tgz", - "integrity": "sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", + "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", "bin": { "parser": "bin/babel-parser.js" }, @@ -208,9 +208,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz", - "integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", + "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -886,9 +886,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz", - "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", + "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -910,9 +910,9 @@ "integrity": "sha512-+tFjX9//HRS1HnBa5cNgfEtE52arwiutYg1TOF+Trk40SPxst9Q8Rtc3BKD6aKsvfbtub68vfhipgchGjj9o7g==" }, "node_modules/@github/text-expander-element": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@github/text-expander-element/-/text-expander-element-2.3.0.tgz", - "integrity": "sha512-E1KCxTOA/7Y4dP5g7vXbfRDFU6/SjU0TuJxx6JMwvxzI/NlBrXyXsx/fjFskD2T/un6i6CNKnXu1ZwExDLjcqw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@github/text-expander-element/-/text-expander-element-2.5.0.tgz", + "integrity": "sha512-BjCxTshkUCgNXo/8iXUSK1sJ7kMJqhVsw6LAzIFtgaYrm4q2068WnPKjngfR+/QPhxN1nSvgd7CozblEIYjUZA==", "dependencies": { "@github/combobox-nav": "^2.0.2" } @@ -1207,19 +1207,19 @@ } }, "node_modules/@playwright/test": { - "version": "1.34.3", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.34.3.tgz", - "integrity": "sha512-zPLef6w9P6T/iT6XDYG3mvGOqOyb6eHaV9XtkunYs0+OzxBtrPAAaHotc0X+PJ00WPPnLfFBTl7mf45Mn8DBmw==", + "version": "1.35.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.35.1.tgz", + "integrity": "sha512-b5YoFe6J9exsMYg0pQAobNDR85T1nLumUYgUTtKm4d21iX2L7WqKq9dW8NGJ+2vX0etZd+Y7UeuqsxDXm9+5ZA==", "dev": true, "dependencies": { "@types/node": "*", - "playwright-core": "1.34.3" + "playwright-core": "1.35.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=14" + "node": ">=16" }, "optionalDependencies": { "fsevents": "2.3.2" @@ -1235,9 +1235,9 @@ } }, "node_modules/@primer/octicons": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-19.1.0.tgz", - "integrity": "sha512-5o90F89gNPnAk1qfzl3hb/TcsUjk5g0WFI+fBRHLkBKzB3uc9EvxTpgzjXhhjyriOkrBOjFo58D0sjtwttaQww==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-19.3.0.tgz", + "integrity": "sha512-hyIo54VPC3VI7ZyAgosiJcbhxq1gZLbBspZwN9cg1uImRd2E8T9JST3kGeezezJYPjG367FuF7p1L+gmLmeESw==", "dependencies": { "object-assign": "^4.1.1" } @@ -1521,14 +1521,14 @@ } }, "node_modules/@stoplight/spectral-formatters": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-formatters/-/spectral-formatters-1.0.0.tgz", - "integrity": "sha512-stdapKMnzEkpnefLUa7FnB++YxFM+Xlo17jxpcRpL+Ld6mHLs41AWoUzEfXDRzW5rHejVFTU/9Ld/ymzlyse8A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-formatters/-/spectral-formatters-1.1.0.tgz", + "integrity": "sha512-KUOKOF0Wz9iFS4pKHO8mSx0OZc9J5ziFJfbxFOL8xDGlxYTfBIQsaOjwi6GItcar7wK8S2ksAIUS2ijzAygZ5A==", "dev": true, "dependencies": { "@stoplight/path": "^1.3.2", - "@stoplight/spectral-core": "^1.18.0", - "@stoplight/spectral-runtime": "^1.1.2", + "@stoplight/spectral-core": "^1.15.1", + "@stoplight/spectral-runtime": "^1.1.0", "@stoplight/types": "^13.15.0", "chalk": "4.1.2", "cliui": "7.0.4", @@ -1800,9 +1800,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-nbq2mvc/tBrK9zQQuItvjJl++GTN5j06DaPtp3hZCpngmG6Q3xoyEmd0TwZI0gAy/G1X0zhGBbr2imsGFdFV0g==", + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.2.tgz", + "integrity": "sha512-PRVjQ4Eh9z9pmmtaq8nTjZjQwKFk7YIHIud3lRoKRBgUQjgjRmoGxxGEPXQkF+lH7QkHJRNr5F4aBgYCW0lqpQ==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -1858,9 +1858,9 @@ "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" }, "node_modules/@types/node": { - "version": "20.2.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", - "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==" + "version": "20.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", + "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -1901,13 +1901,13 @@ } }, "node_modules/@vitest/expect": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.0.tgz", - "integrity": "sha512-VxVHhIxKw9Lux+O9bwLEEk2gzOUe93xuFHy9SzYWnnoYZFYg1NfBtnfnYWiJN7yooJ7KNElCK5YtA7DTZvtXtg==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz", + "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==", "dev": true, "dependencies": { - "@vitest/spy": "0.32.0", - "@vitest/utils": "0.32.0", + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", "chai": "^4.3.7" }, "funding": { @@ -1915,12 +1915,12 @@ } }, "node_modules/@vitest/runner": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.0.tgz", - "integrity": "sha512-QpCmRxftHkr72xt5A08xTEs9I4iWEXIOCHWhQQguWOKE4QH7DXSKZSOFibuwEIMAD7G0ERvtUyQn7iPWIqSwmw==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz", + "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==", "dev": true, "dependencies": { - "@vitest/utils": "0.32.0", + "@vitest/utils": "0.32.2", "concordance": "^5.0.4", "p-limit": "^4.0.0", "pathe": "^1.1.0" @@ -1957,9 +1957,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.32.0.tgz", - "integrity": "sha512-yCKorPWjEnzpUxQpGlxulujTcSPgkblwGzAUEL+z01FTUg/YuCDZ8dxr9sHA08oO2EwxzHXNLjQKWJ2zc2a19Q==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.32.2.tgz", + "integrity": "sha512-JwhpeH/PPc7GJX38vEfCy9LtRzf9F4er7i4OsAJyV7sjPwjj+AIR8cUgpMTWK4S3TiamzopcTyLsZDMuldoi5A==", "dev": true, "dependencies": { "magic-string": "^0.30.0", @@ -1983,9 +1983,9 @@ } }, "node_modules/@vitest/spy": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.0.tgz", - "integrity": "sha512-MruAPlM0uyiq3d53BkwTeShXY0rYEfhNGQzVO5GHBmmX3clsxcWp79mMnkOVcV244sNTeDcHbcPFWIjOI4tZvw==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz", + "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==", "dev": true, "dependencies": { "tinyspy": "^2.1.0" @@ -1995,12 +1995,12 @@ } }, "node_modules/@vitest/utils": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.0.tgz", - "integrity": "sha512-53yXunzx47MmbuvcOPpLaVljHaeSu1G2dHdmy7+9ngMnQIkBQcvwOcoclWFnxDMxFbnq8exAfh3aKSZaK71J5A==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", + "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", "dev": true, "dependencies": { - "concordance": "^5.0.4", + "diff-sequences": "^29.4.3", "loupe": "^2.3.6", "pretty-format": "^27.5.1" }, @@ -2338,9 +2338,9 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", + "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", "bin": { "acorn": "bin/acorn" }, @@ -2739,9 +2739,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", - "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", + "version": "4.21.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", + "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", "funding": [ { "type": "opencollective", @@ -2757,8 +2757,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001489", - "electron-to-chromium": "^1.4.411", + "caniuse-lite": "^1.0.30001503", + "electron-to-chromium": "^1.4.431", "node-releases": "^2.0.12", "update-browserslist-db": "^1.0.11" }, @@ -2882,9 +2882,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001495", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", - "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==", + "version": "1.0.30001504", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001504.tgz", + "integrity": "sha512-5uo7eoOp2mKbWyfMXnGO9rJWOGU8duvzEiYITW+wivukL7yHH4gX9yuRaobu6El4jPxo6jKZfG+N6fB621GD/Q==", "funding": [ { "type": "opencollective", @@ -4023,6 +4023,15 @@ "node": ">=0.3.1" } }, + "node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4158,9 +4167,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.425", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.425.tgz", - "integrity": "sha512-wv1NufHxu11zfDbY4fglYQApMswleE9FL/DSeyOyauVXDZ+Kco96JK/tPfBUaDqfRarYp2WH2hJ/5UnVywp9Jg==" + "version": "1.4.433", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.433.tgz", + "integrity": "sha512-MGO1k0w1RgrfdbLVwmXcDhHHuxCn2qRgR7dYsJvWFKDttvYPx6FNzCGG0c/fBBvzK2LDh3UV7Tt9awnHnvAAUQ==" }, "node_modules/elkjs": { "version": "0.8.2", @@ -4190,9 +4199,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", - "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -4299,9 +4308,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", - "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==" }, "node_modules/es-set-tostringtag": { "version": "2.0.1", @@ -4507,15 +4516,15 @@ } }, "node_modules/eslint": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz", - "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", + "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.42.0", + "@eslint/js": "8.43.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -6899,48 +6908,48 @@ } }, "node_modules/markdownlint": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.28.2.tgz", - "integrity": "sha512-yYaQXoKKPV1zgrFsyAuZPEQoe+JrY9GDag9ObKpk09twx4OCU5lut+0/kZPrQ3W7w82SmgKhd7D8m34aG1unVw==", + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.29.0.tgz", + "integrity": "sha512-ASAzqpODstu/Qsk0xW5BPgWnK/qjpBQ4e7IpsSvvFXcfYIjanLTdwFRJK1SIEEh0fGSMKXcJf/qhaZYHyME0wA==", "dev": true, "dependencies": { "markdown-it": "13.0.1", - "markdownlint-micromark": "0.1.2" + "markdownlint-micromark": "0.1.5" }, "engines": { - "node": ">=14.18.0" + "node": ">=16" } }, "node_modules/markdownlint-cli": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.34.0.tgz", - "integrity": "sha512-4G9I++VBTZkaye6Yfc/7dU6HQHcyldZEVB+bYyQJLcpJOHKk/q5ZpGqK80oKMIdlxzsA3aWOJLZ4DkoaoUWXbQ==", + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.35.0.tgz", + "integrity": "sha512-lVIIIV1MrUtjoocgDqXLxUCxlRbn7Ve8rsWppfwciUNwLlNS28AhNiyQ3PU7jjj4Qvj+rWTTvwkqg7AcdG988g==", "dev": true, "dependencies": { - "commander": "~10.0.1", + "commander": "~11.0.0", "get-stdin": "~9.0.0", - "glob": "~10.2.2", + "glob": "~10.2.7", "ignore": "~5.2.4", "js-yaml": "^4.1.0", "jsonc-parser": "~3.2.0", - "markdownlint": "~0.28.2", - "minimatch": "~9.0.0", + "markdownlint": "~0.29.0", + "minimatch": "~9.0.1", "run-con": "~1.2.11" }, "bin": { "markdownlint": "markdownlint.js" }, "engines": { - "node": ">=14" + "node": ">=16" } }, "node_modules/markdownlint-cli/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", "dev": true, "engines": { - "node": ">=14" + "node": ">=16" } }, "node_modules/markdownlint-cli/node_modules/glob": { @@ -6972,12 +6981,12 @@ "dev": true }, "node_modules/markdownlint-micromark": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.2.tgz", - "integrity": "sha512-jRxlQg8KpOfM2IbCL9RXM8ZiYWz2rv6DlZAnGv8ASJQpUh6byTBnEsbuMZ6T2/uIgntyf7SKg/mEaEBo1164fQ==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.5.tgz", + "integrity": "sha512-HvofNU4QCvfUCWnocQP1IAWaqop5wpWrB0mKB6SSh0fcpV0PdmQNS6tdUuFew1utpYlUvYYzz84oDkrD76GB9A==", "dev": true, "engines": { - "node": ">=14.18.0" + "node": ">=16" } }, "node_modules/marked": { @@ -7157,9 +7166,9 @@ } }, "node_modules/mermaid": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.2.2.tgz", - "integrity": "sha512-ifYKlCcZKYq48hxC1poJXnvk/PbCdgqqbg5B4qsybb8nIItPM1ATKqVEDkyde6BBJxVFhVJr9hoUjipzniQJZg==", + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.2.3.tgz", + "integrity": "sha512-cMVE5s9PlQvOwfORkyVpr5beMsLdInrycAosdr+tpZ0WFjG4RJ/bUHST7aTgHNJbujHkdBRAm+N50P3puQOfPw==", "dependencies": { "@braintree/sanitize-url": "^6.0.2", "cytoscape": "^3.23.0", @@ -8345,15 +8354,15 @@ "dev": true }, "node_modules/playwright-core": { - "version": "1.34.3", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.34.3.tgz", - "integrity": "sha512-2pWd6G7OHKemc5x1r1rp8aQcpvDh7goMBZlJv6Co5vCNLVcQJdhxRL09SGaY6HcyHH9aT4tiynZabMofVasBYw==", + "version": "1.35.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.35.1.tgz", + "integrity": "sha512-pNXb6CQ7OqmGDRspEjlxE49w+4YtR6a3X6mT1hZXeJHWmsEz7SunmvZeiG/+y1yyMZdHnnn73WKYdtV1er0Xyg==", "dev": true, "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=14" + "node": ">=16" } }, "node_modules/pluralize": { @@ -9185,9 +9194,9 @@ } }, "node_modules/schema-utils": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.1.0.tgz", - "integrity": "sha512-Jw+GZVbP5IggB2WAn6UHI02LBwGmsIeYN/lNbSMZyDziQ7jmtAUrqKqDja+W89YHVs+KL/3IkIMltAklqB1vAw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -9214,9 +9223,9 @@ } }, "node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -9717,9 +9726,9 @@ "dev": true }, "node_modules/stylelint": { - "version": "15.7.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-15.7.0.tgz", - "integrity": "sha512-fQRwHwWuZsDn4ENyE9AsKkOkV9WlD2CmYiVDbdZPdS3iZh0ceypOn1EuwTNuZ8xTrHF+jVeIEzLtFFSlD/nJHg==", + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-15.8.0.tgz", + "integrity": "sha512-x9qBk84F3MEjMEUNCE7MtWmfj9G9y5XzJ0cpQeJdy2l/IoqjC8Ih0N0ytmOTnXE4Yv0J7I1cmVRQUVNSPCxTsA==", "dev": true, "dependencies": { "@csstools/css-parser-algorithms": "^2.2.0", @@ -9762,7 +9771,6 @@ "supports-hyperlinks": "^3.0.0", "svg-tags": "^1.0.0", "table": "^6.8.1", - "v8-compile-cache": "^2.3.0", "write-file-atomic": "^5.0.1" }, "bin": { @@ -9776,6 +9784,18 @@ "url": "https://opencollective.com/stylelint" } }, + "node_modules/stylelint-declaration-block-no-ignored-properties": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/stylelint-declaration-block-no-ignored-properties/-/stylelint-declaration-block-no-ignored-properties-2.7.0.tgz", + "integrity": "sha512-44SpI9+9Oc1ICuwwRfwS/3npQ2jPobDSTnwWdNgZGryGqQCp17CgEIWjCv1BgUOSzND3RqywNCNLKvO1AOxbfg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "stylelint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0" + } + }, "node_modules/stylelint-declaration-strict-value": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/stylelint-declaration-strict-value/-/stylelint-declaration-strict-value-1.9.2.tgz", @@ -9789,6 +9809,21 @@ "stylelint": ">=7 <=15" } }, + "node_modules/stylelint-stylistic": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/stylelint-stylistic/-/stylelint-stylistic-0.4.2.tgz", + "integrity": "sha512-WF/fLvotTklG8LZ+fO0nxhu5swVENHhSat2l5ckrmtXpij1P9ybYa56XivOg/E02CH+Ygui5pd2hQrlli3NCDQ==", + "dev": true, + "dependencies": { + "postcss": "^8.4.21", + "postcss-media-query-parser": "^0.2.3", + "postcss-value-parser": "^4.2.0", + "style-search": "^0.1.0" + }, + "peerDependencies": { + "stylelint": "^15.0.0" + } + }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", @@ -9889,9 +9924,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.19.0.tgz", - "integrity": "sha512-9C9fJGI18gK5AhaU5YRyPY1lXJH4lmWh8h9zFMrJBkYzdRjCbAzYl1ayWPYgwFvag/Luqi3Co599OK/39IS2QQ==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.0.0.tgz", + "integrity": "sha512-bwl6og9I9CAHKGSnYLKydjhBuH7d3oU6RX6uKN8oDCkLusTHXOW3sZMyBWjRtjGFnCMmN085oZoaR/4Wm9nIaQ==" }, "node_modules/symbol-tree": { "version": "3.2.4", @@ -9900,9 +9935,9 @@ "dev": true }, "node_modules/sync-fetch": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.4.2.tgz", - "integrity": "sha512-vilDD6yTGwyUjm7/W5WUUOCw1GH1aV591zC21XhbV6MJNZqfZcNMs9DVPHzy1UAmQ2GAg6S03F5TQ3paegKSdg==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.4.5.tgz", + "integrity": "sha512-esiWJ7ixSKGpd9DJPBTC4ckChqdOjIwJfYhVHkcQ2Gnm41323p1TRmEI+esTQ9ppD+b5opps2OTEGTCGX5kF+g==", "dependencies": { "buffer": "^5.7.1", "node-fetch": "^2.6.1" @@ -9936,9 +9971,9 @@ } }, "node_modules/terser": { - "version": "5.17.7", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.7.tgz", - "integrity": "sha512-/bi0Zm2C6VAexlGgLlVxA0P2lru/sdLyfCVaRMfKVo9nWxbmz7f/sD8VPybPeSUJaJcwmCJis9pBIhcVcG1QcQ==", + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.18.0.tgz", + "integrity": "sha512-pdL757Ig5a0I+owA42l6tIuEycRuM7FPY4n62h44mRLRfnOxJkkOHd6i89dOpwZlpF6JXBwaAHF6yWzFrt+QyA==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -10014,9 +10049,9 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.2.0.tgz", - "integrity": "sha512-0zTyLGyDJYd/MBxG1AhJkKa6fpEBds4OQO2ut0w7OYG+ZGhGea09lijvzsqegYSik88zc7cUtIlnnO+/BvD6gQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -10342,9 +10377,9 @@ } }, "node_modules/updates": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/updates/-/updates-14.1.1.tgz", - "integrity": "sha512-FRaSNMgs3T24w92GrIyspY//2gaAXyoNg+nHaYZMv6MT5xJEFYT25RLnKQIJuz0CW2l1OOnMxooTn+LzN/2NIw==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/updates/-/updates-14.2.4.tgz", + "integrity": "sha512-r54h4Q12lUAmQ9dENy7BnY22AnTfW4YGEZw73gv6RvNEWgcZ3qS88jPLc1ckPAzt/8TPKWwLkSVpbEpgGwglJw==", "dev": true, "bin": { "updates": "bin/updates.js" @@ -10416,12 +10451,6 @@ "node": ">=8" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -10490,9 +10519,9 @@ } }, "node_modules/vite-node": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.0.tgz", - "integrity": "sha512-220P/y8YacYAU+daOAqiGEFXx2A8AwjadDzQqos6wSukjvvTWNqleJSwoUn0ckyNdjHIKoxn93Nh1vWBqEKr3Q==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz", + "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -10513,9 +10542,9 @@ } }, "node_modules/vite/node_modules/rollup": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.24.0.tgz", - "integrity": "sha512-OgraHOIg2YpHQTjl0/ymWfFNBEyPucB7lmhXrQUh38qNOegxLapSPFs9sNr0qKR75awW41D93XafoR2QfhBdUQ==", + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz", + "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -10529,19 +10558,19 @@ } }, "node_modules/vitest": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.0.tgz", - "integrity": "sha512-SW83o629gCqnV3BqBnTxhB10DAwzwEx3z+rqYZESehUB+eWsJxwcBQx7CKy0otuGMJTYh7qCVuUX23HkftGl/Q==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz", + "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==", "dev": true, "dependencies": { "@types/chai": "^4.3.5", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.32.0", - "@vitest/runner": "0.32.0", - "@vitest/snapshot": "0.32.0", - "@vitest/spy": "0.32.0", - "@vitest/utils": "0.32.0", + "@vitest/expect": "0.32.2", + "@vitest/runner": "0.32.2", + "@vitest/snapshot": "0.32.2", + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", "acorn": "^8.8.2", "acorn-walk": "^8.2.0", "cac": "^6.7.14", @@ -10557,7 +10586,7 @@ "tinybench": "^2.5.0", "tinypool": "^0.5.0", "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.32.0", + "vite-node": "0.32.2", "why-is-node-running": "^2.2.2" }, "bin": { @@ -10656,9 +10685,9 @@ } }, "node_modules/vue-eslint-parser": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.0.tgz", - "integrity": "sha512-48IxT9d0+wArT1+3wNIy0tascRoywqSUe2E1YalIC1L8jsUGe5aJQItWfRok7DVFGz3UYvzEI7n5wiTXsCMAcQ==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz", + "integrity": "sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==", "dev": true, "dependencies": { "debug": "^4.3.4", @@ -10751,9 +10780,9 @@ } }, "node_modules/webpack": { - "version": "5.86.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", - "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "version": "5.87.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.87.0.tgz", + "integrity": "sha512-GOu1tNbQ7p1bDEoFRs2YPcfyGs8xq52yyPBZ3m2VGnXGtV9MxjrkABHm4V9Ia280OefsSLzvbVoXcfLxjKY/Iw==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", @@ -10764,7 +10793,7 @@ "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.1", + "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -10774,7 +10803,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", @@ -10918,9 +10947,9 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/webpack/node_modules/schema-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.2.0.tgz", - "integrity": "sha512-0zTyLGyDJYd/MBxG1AhJkKa6fpEBds4OQO2ut0w7OYG+ZGhGea09lijvzsqegYSik88zc7cUtIlnnO+/BvD6gQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", diff --git a/package.json b/package.json index 41d834771aa..0701862cc2a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,4 @@ { - "name": "gitea", - "license": "MIT", - "private": true, "type": "module", "engines": { "node": ">= 16.0.0" @@ -14,9 +11,9 @@ "@claviska/jquery-minicolors": "2.3.6", "@github/markdown-toolbar-element": "2.1.1", "@github/relative-time-element": "4.3.0", - "@github/text-expander-element": "2.3.0", + "@github/text-expander-element": "2.5.0", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "19.1.0", + "@primer/octicons": "19.3.0", "@webcomponents/custom-elements": "1.6.0", "add-asset-webpack-plugin": "2.0.1", "ansi-to-html": "0.7.2", @@ -32,7 +29,7 @@ "jquery.are-you-sure": "1.9.0", "katex": "0.16.7", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "10.2.2", + "mermaid": "10.2.3", "mini-css-extract-plugin": "2.7.6", "minimatch": "9.0.1", "monaco-editor": "0.39.0", @@ -40,7 +37,7 @@ "pdfobject": "2.2.12", "pretty-ms": "8.0.0", "sortablejs": "1.15.0", - "swagger-ui-dist": "4.19.0", + "swagger-ui-dist": "5.0.0", "throttle-debounce": "5.0.0", "tippy.js": "6.3.7", "tributejs": "5.1.3", @@ -49,17 +46,17 @@ "vue-bar-graph": "2.0.0", "vue-loader": "17.2.2", "vue3-calendar-heatmap": "2.0.5", - "webpack": "5.86.0", + "webpack": "5.87.0", "webpack-cli": "5.1.4", "wrap-ansi": "8.1.0" }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "3.2.1", - "@playwright/test": "1.34.3", + "@playwright/test": "1.35.1", "@rollup/pluginutils": "5.0.2", "@stoplight/spectral-cli": "6.8.0", "@vitejs/plugin-vue": "4.2.3", - "eslint": "8.42.0", + "eslint": "8.43.0", "eslint-plugin-array-func": "3.1.8", "eslint-plugin-custom-elements": "0.0.8", "eslint-plugin-import": "2.27.5", @@ -72,13 +69,15 @@ "eslint-plugin-vue": "9.14.1", "eslint-plugin-wc": "1.5.0", "jsdom": "22.1.0", - "markdownlint-cli": "0.34.0", + "markdownlint-cli": "0.35.0", "postcss-html": "1.5.0", - "stylelint": "15.7.0", + "stylelint": "15.8.0", + "stylelint-declaration-block-no-ignored-properties": "2.7.0", "stylelint-declaration-strict-value": "1.9.2", + "stylelint-stylistic": "0.4.2", "svgo": "3.0.2", - "updates": "14.1.1", - "vitest": "0.32.0" + "updates": "14.2.4", + "vitest": "0.32.2" }, "browserslist": [ "defaults", diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000000..69258f749c9 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,331 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + +[[package]] +name = "click" +version = "8.1.3" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cssbeautifier" +version = "1.14.8" +description = "CSS unobfuscator and beautifier." +optional = false +python-versions = "*" +files = [ + {file = "cssbeautifier-1.14.8.tar.gz", hash = "sha256:9ad4c5b2ffe0b439a4bed278bc440b6a89c40823c3f19db38f808d256216a592"}, +] + +[package.dependencies] +editorconfig = ">=0.12.2" +jsbeautifier = "*" +six = ">=1.13.0" + +[[package]] +name = "djlint" +version = "1.31.0" +description = "HTML Template Linter and Formatter" +optional = false +python-versions = ">=3.8.0,<4.0.0" +files = [ + {file = "djlint-1.31.0-py3-none-any.whl", hash = "sha256:2b9200c67103b79835b7547ff732e910888d1f0ef684f5b329eb64b14d09c046"}, + {file = "djlint-1.31.0.tar.gz", hash = "sha256:8acb4b751b429c5aabb1aef5b6007bdf53224eceda25c5fbe04c42cc57c0a7ba"}, +] + +[package.dependencies] +click = ">=8.0.1,<9.0.0" +colorama = ">=0.4.4,<0.5.0" +cssbeautifier = ">=1.14.4,<2.0.0" +html-tag-names = ">=0.1.2,<0.2.0" +html-void-elements = ">=0.1.0,<0.2.0" +jsbeautifier = ">=1.14.4,<2.0.0" +json5 = ">=0.9.11,<0.10.0" +pathspec = ">=0.11.0,<0.12.0" +PyYAML = ">=6.0,<7.0" +regex = ">=2023.0.0,<2024.0.0" +tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} +tqdm = ">=4.62.2,<5.0.0" + +[[package]] +name = "editorconfig" +version = "0.12.3" +description = "EditorConfig File Locator and Interpreter for Python" +optional = false +python-versions = "*" +files = [ + {file = "EditorConfig-0.12.3-py3-none-any.whl", hash = "sha256:6b0851425aa875b08b16789ee0eeadbd4ab59666e9ebe728e526314c4a2e52c1"}, + {file = "EditorConfig-0.12.3.tar.gz", hash = "sha256:57f8ce78afcba15c8b18d46b5170848c88d56fd38f05c2ec60dbbfcb8996e89e"}, +] + +[[package]] +name = "html-tag-names" +version = "0.1.2" +description = "List of known HTML tag names" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "html-tag-names-0.1.2.tar.gz", hash = "sha256:04924aca48770f36b5a41c27e4d917062507be05118acb0ba869c97389084297"}, + {file = "html_tag_names-0.1.2-py3-none-any.whl", hash = "sha256:eeb69ef21078486b615241f0393a72b41352c5219ee648e7c61f5632d26f0420"}, +] + +[[package]] +name = "html-void-elements" +version = "0.1.0" +description = "List of HTML void tag names." +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "html-void-elements-0.1.0.tar.gz", hash = "sha256:931b88f84cd606fee0b582c28fcd00e41d7149421fb673e1e1abd2f0c4f231f0"}, + {file = "html_void_elements-0.1.0-py3-none-any.whl", hash = "sha256:784cf39db03cdeb017320d9301009f8f3480f9d7b254d0974272e80e0cb5e0d2"}, +] + +[[package]] +name = "jsbeautifier" +version = "1.14.8" +description = "JavaScript unobfuscator and beautifier." +optional = false +python-versions = "*" +files = [ + {file = "jsbeautifier-1.14.8.tar.gz", hash = "sha256:d4c4e263a42dd6194afb9dbe54710be3c5604492cbec3e89c92dd98513f98b9f"}, +] + +[package.dependencies] +editorconfig = ">=0.12.2" +six = ">=1.13.0" + +[[package]] +name = "json5" +version = "0.9.14" +description = "A Python implementation of the JSON5 data format." +optional = false +python-versions = "*" +files = [ + {file = "json5-0.9.14-py2.py3-none-any.whl", hash = "sha256:740c7f1b9e584a468dbb2939d8d458db3427f2c93ae2139d05f47e453eae964f"}, + {file = "json5-0.9.14.tar.gz", hash = "sha256:9ed66c3a6ca3510a976a9ef9b8c0787de24802724ab1860bc0153c7fdd589b02"}, +] + +[package.extras] +dev = ["hypothesis"] + +[[package]] +name = "pathspec" +version = "0.11.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, + {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, +] + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] + +[[package]] +name = "regex" +version = "2023.6.3" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.6" +files = [ + {file = "regex-2023.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:824bf3ac11001849aec3fa1d69abcb67aac3e150a933963fb12bda5151fe1bfd"}, + {file = "regex-2023.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:05ed27acdf4465c95826962528f9e8d41dbf9b1aa8531a387dee6ed215a3e9ef"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b49c764f88a79160fa64f9a7b425620e87c9f46095ef9c9920542ab2495c8bc"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8e3f1316c2293e5469f8f09dc2d76efb6c3982d3da91ba95061a7e69489a14ef"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43e1dd9d12df9004246bacb79a0e5886b3b6071b32e41f83b0acbf293f820ee8"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4959e8bcbfda5146477d21c3a8ad81b185cd252f3d0d6e4724a5ef11c012fb06"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af4dd387354dc83a3bff67127a124c21116feb0d2ef536805c454721c5d7993d"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2239d95d8e243658b8dbb36b12bd10c33ad6e6933a54d36ff053713f129aa536"}, + {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:890e5a11c97cf0d0c550eb661b937a1e45431ffa79803b942a057c4fb12a2da2"}, + {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a8105e9af3b029f243ab11ad47c19b566482c150c754e4c717900a798806b222"}, + {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:25be746a8ec7bc7b082783216de8e9473803706723b3f6bef34b3d0ed03d57e2"}, + {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:3676f1dd082be28b1266c93f618ee07741b704ab7b68501a173ce7d8d0d0ca18"}, + {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:10cb847aeb1728412c666ab2e2000ba6f174f25b2bdc7292e7dd71b16db07568"}, + {file = "regex-2023.6.3-cp310-cp310-win32.whl", hash = "sha256:dbbbfce33cd98f97f6bffb17801b0576e653f4fdb1d399b2ea89638bc8d08ae1"}, + {file = "regex-2023.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:c5f8037000eb21e4823aa485149f2299eb589f8d1fe4b448036d230c3f4e68e0"}, + {file = "regex-2023.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c123f662be8ec5ab4ea72ea300359023a5d1df095b7ead76fedcd8babbedf969"}, + {file = "regex-2023.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9edcbad1f8a407e450fbac88d89e04e0b99a08473f666a3f3de0fd292badb6aa"}, + {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcba6dae7de533c876255317c11f3abe4907ba7d9aa15d13e3d9710d4315ec0e"}, + {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29cdd471ebf9e0f2fb3cac165efedc3c58db841d83a518b082077e612d3ee5df"}, + {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12b74fbbf6cbbf9dbce20eb9b5879469e97aeeaa874145517563cca4029db65c"}, + {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c29ca1bd61b16b67be247be87390ef1d1ef702800f91fbd1991f5c4421ebae8"}, + {file = "regex-2023.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77f09bc4b55d4bf7cc5eba785d87001d6757b7c9eec237fe2af57aba1a071d9"}, + {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ea353ecb6ab5f7e7d2f4372b1e779796ebd7b37352d290096978fea83c4dba0c"}, + {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:10590510780b7541969287512d1b43f19f965c2ece6c9b1c00fc367b29d8dce7"}, + {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e2fbd6236aae3b7f9d514312cdb58e6494ee1c76a9948adde6eba33eb1c4264f"}, + {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:6b2675068c8b56f6bfd5a2bda55b8accbb96c02fd563704732fd1c95e2083461"}, + {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74419d2b50ecb98360cfaa2974da8689cb3b45b9deff0dcf489c0d333bcc1477"}, + {file = "regex-2023.6.3-cp311-cp311-win32.whl", hash = "sha256:fb5ec16523dc573a4b277663a2b5a364e2099902d3944c9419a40ebd56a118f9"}, + {file = "regex-2023.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:09e4a1a6acc39294a36b7338819b10baceb227f7f7dbbea0506d419b5a1dd8af"}, + {file = "regex-2023.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0654bca0cdf28a5956c83839162692725159f4cda8d63e0911a2c0dc76166525"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:463b6a3ceb5ca952e66550a4532cef94c9a0c80dc156c4cc343041951aec1697"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87b2a5bb5e78ee0ad1de71c664d6eb536dc3947a46a69182a90f4410f5e3f7dd"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6343c6928282c1f6a9db41f5fd551662310e8774c0e5ebccb767002fcf663ca9"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6192d5af2ccd2a38877bfef086d35e6659566a335b1492786ff254c168b1693"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74390d18c75054947e4194019077e243c06fbb62e541d8817a0fa822ea310c14"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:742e19a90d9bb2f4a6cf2862b8b06dea5e09b96c9f2df1779e53432d7275331f"}, + {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8abbc5d54ea0ee80e37fef009e3cec5dafd722ed3c829126253d3e22f3846f1e"}, + {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:c2b867c17a7a7ae44c43ebbeb1b5ff406b3e8d5b3e14662683e5e66e6cc868d3"}, + {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:d831c2f8ff278179705ca59f7e8524069c1a989e716a1874d6d1aab6119d91d1"}, + {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ee2d1a9a253b1729bb2de27d41f696ae893507c7db224436abe83ee25356f5c1"}, + {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:61474f0b41fe1a80e8dfa70f70ea1e047387b7cd01c85ec88fa44f5d7561d787"}, + {file = "regex-2023.6.3-cp36-cp36m-win32.whl", hash = "sha256:0b71e63226e393b534105fcbdd8740410dc6b0854c2bfa39bbda6b0d40e59a54"}, + {file = "regex-2023.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bbb02fd4462f37060122e5acacec78e49c0fbb303c30dd49c7f493cf21fc5b27"}, + {file = "regex-2023.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b862c2b9d5ae38a68b92e215b93f98d4c5e9454fa36aae4450f61dd33ff48487"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:976d7a304b59ede34ca2921305b57356694f9e6879db323fd90a80f865d355a3"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:83320a09188e0e6c39088355d423aa9d056ad57a0b6c6381b300ec1a04ec3d16"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9427a399501818a7564f8c90eced1e9e20709ece36be701f394ada99890ea4b3"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178bbc1b2ec40eaca599d13c092079bf529679bf0371c602edaa555e10b41c3"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:837328d14cde912af625d5f303ec29f7e28cdab588674897baafaf505341f2fc"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d44dc13229905ae96dd2ae2dd7cebf824ee92bc52e8cf03dcead37d926da019"}, + {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d54af539295392611e7efbe94e827311eb8b29668e2b3f4cadcfe6f46df9c777"}, + {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7117d10690c38a622e54c432dfbbd3cbd92f09401d622902c32f6d377e2300ee"}, + {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bb60b503ec8a6e4e3e03a681072fa3a5adcbfa5479fa2d898ae2b4a8e24c4591"}, + {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:65ba8603753cec91c71de423a943ba506363b0e5c3fdb913ef8f9caa14b2c7e0"}, + {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:271f0bdba3c70b58e6f500b205d10a36fb4b58bd06ac61381b68de66442efddb"}, + {file = "regex-2023.6.3-cp37-cp37m-win32.whl", hash = "sha256:9beb322958aaca059f34975b0df135181f2e5d7a13b84d3e0e45434749cb20f7"}, + {file = "regex-2023.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fea75c3710d4f31389eed3c02f62d0b66a9da282521075061ce875eb5300cf23"}, + {file = "regex-2023.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f56fcb7ff7bf7404becdfc60b1e81a6d0561807051fd2f1860b0d0348156a07"}, + {file = "regex-2023.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d2da3abc88711bce7557412310dfa50327d5769a31d1c894b58eb256459dc289"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a99b50300df5add73d307cf66abea093304a07eb017bce94f01e795090dea87c"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5708089ed5b40a7b2dc561e0c8baa9535b77771b64a8330b684823cfd5116036"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:687ea9d78a4b1cf82f8479cab23678aff723108df3edeac098e5b2498879f4a7"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3850beab9f527f06ccc94b446c864059c57651b3f911fddb8d9d3ec1d1b25d"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8915cc96abeb8983cea1df3c939e3c6e1ac778340c17732eb63bb96247b91d2"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:841d6e0e5663d4c7b4c8099c9997be748677d46cbf43f9f471150e560791f7ff"}, + {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9edce5281f965cf135e19840f4d93d55b3835122aa76ccacfd389e880ba4cf82"}, + {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b956231ebdc45f5b7a2e1f90f66a12be9610ce775fe1b1d50414aac1e9206c06"}, + {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:36efeba71c6539d23c4643be88295ce8c82c88bbd7c65e8a24081d2ca123da3f"}, + {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:cf67ca618b4fd34aee78740bea954d7c69fdda419eb208c2c0c7060bb822d747"}, + {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b4598b1897837067a57b08147a68ac026c1e73b31ef6e36deeeb1fa60b2933c9"}, + {file = "regex-2023.6.3-cp38-cp38-win32.whl", hash = "sha256:f415f802fbcafed5dcc694c13b1292f07fe0befdb94aa8a52905bd115ff41e88"}, + {file = "regex-2023.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:d4f03bb71d482f979bda92e1427f3ec9b220e62a7dd337af0aa6b47bf4498f72"}, + {file = "regex-2023.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ccf91346b7bd20c790310c4147eee6ed495a54ddb6737162a36ce9dbef3e4751"}, + {file = "regex-2023.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b28f5024a3a041009eb4c333863d7894d191215b39576535c6734cd88b0fcb68"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0bb18053dfcfed432cc3ac632b5e5e5c5b7e55fb3f8090e867bfd9b054dbcbf"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a5bfb3004f2144a084a16ce19ca56b8ac46e6fd0651f54269fc9e230edb5e4a"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c6b48d0fa50d8f4df3daf451be7f9689c2bde1a52b1225c5926e3f54b6a9ed1"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:051da80e6eeb6e239e394ae60704d2b566aa6a7aed6f2890a7967307267a5dc6"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4c3b7fa4cdaa69268748665a1a6ff70c014d39bb69c50fda64b396c9116cf77"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:457b6cce21bee41ac292d6753d5e94dcbc5c9e3e3a834da285b0bde7aa4a11e9"}, + {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aad51907d74fc183033ad796dd4c2e080d1adcc4fd3c0fd4fd499f30c03011cd"}, + {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0385e73da22363778ef2324950e08b689abdf0b108a7d8decb403ad7f5191938"}, + {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c6a57b742133830eec44d9b2290daf5cbe0a2f1d6acee1b3c7b1c7b2f3606df7"}, + {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3e5219bf9e75993d73ab3d25985c857c77e614525fac9ae02b1bebd92f7cecac"}, + {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e5087a3c59eef624a4591ef9eaa6e9a8d8a94c779dade95d27c0bc24650261cd"}, + {file = "regex-2023.6.3-cp39-cp39-win32.whl", hash = "sha256:20326216cc2afe69b6e98528160b225d72f85ab080cbdf0b11528cbbaba2248f"}, + {file = "regex-2023.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:bdff5eab10e59cf26bc479f565e25ed71a7d041d1ded04ccf9aee1d9f208487a"}, + {file = "regex-2023.6.3.tar.gz", hash = "sha256:72d1a25bf36d2050ceb35b517afe13864865268dfb45910e2e17a84be6cbfeb0"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tqdm" +version = "4.65.0" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tqdm-4.65.0-py3-none-any.whl", hash = "sha256:c4f53a17fe37e132815abceec022631be8ffe1b9381c2e6e30aa70edc99e9671"}, + {file = "tqdm-4.65.0.tar.gz", hash = "sha256:1871fb68a86b8fb3b59ca4cdd3dcccbc7e6d613eeed31f4c332531977b89beb5"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["py-make (>=0.1.0)", "twine", "wheel"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "22c4af11eadd8784b613951d6160d67be0f33500238a450741c3d75beb218dad" diff --git a/poetry.toml b/poetry.toml new file mode 100644 index 00000000000..0299355b5dd --- /dev/null +++ b/poetry.toml @@ -0,0 +1,4 @@ +[virtualenvs] +in-project = true +options.no-pip = true +options.no-setuptools = true diff --git a/public/img/svg/octicon-copilot.svg b/public/img/svg/octicon-copilot.svg index 64eddfa1d5d..b2a143c5c63 100644 --- a/public/img/svg/octicon-copilot.svg +++ b/public/img/svg/octicon-copilot.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/img/svg/octicon-pivot-column.svg b/public/img/svg/octicon-pivot-column.svg new file mode 100644 index 00000000000..34370c20600 --- /dev/null +++ b/public/img/svg/octicon-pivot-column.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-redo.svg b/public/img/svg/octicon-redo.svg new file mode 100644 index 00000000000..a4fbeabeaa2 --- /dev/null +++ b/public/img/svg/octicon-redo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-tracked-by-closed-completed.svg b/public/img/svg/octicon-tracked-by-closed-completed.svg new file mode 100644 index 00000000000..7a3af6dee2b --- /dev/null +++ b/public/img/svg/octicon-tracked-by-closed-completed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-tracked-by-closed-not-planned.svg b/public/img/svg/octicon-tracked-by-closed-not-planned.svg new file mode 100644 index 00000000000..bbeb817b822 --- /dev/null +++ b/public/img/svg/octicon-tracked-by-closed-not-planned.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-undo.svg b/public/img/svg/octicon-undo.svg new file mode 100644 index 00000000000..53ac6464147 --- /dev/null +++ b/public/img/svg/octicon-undo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000000..ce5f475b272 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poetry] +name = "gitea" +version = "0.0.0" +description = "" +authors = [] + +[tool.poetry.dependencies] +python = "^3.8" + +[tool.poetry.group.dev.dependencies] +djlint = "1.31.0" + +[tool.djlint] +profile="golang" +ignore="H005,H006,H008,H013,H014,H016,H020,H021,H023,H026,H030,H031,T027" diff --git a/routers/api/actions/actions.go b/routers/api/actions/actions.go index bdcac412068..a418b3a1c45 100644 --- a/routers/api/actions/actions.go +++ b/routers/api/actions/actions.go @@ -4,7 +4,6 @@ package actions import ( - "context" "net/http" "code.gitea.io/gitea/modules/web" @@ -12,7 +11,7 @@ import ( "code.gitea.io/gitea/routers/api/actions/runner" ) -func Routes(_ context.Context, prefix string) *web.Route { +func Routes(prefix string) *web.Route { m := web.NewRoute() path, handler := ping.NewPingServiceHandler() diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go index 4b10cd7ad11..060f7bc3d4b 100644 --- a/routers/api/actions/artifacts.go +++ b/routers/api/actions/artifacts.go @@ -82,6 +82,7 @@ import ( "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + web_types "code.gitea.io/gitea/modules/web/types" ) const ( @@ -102,7 +103,7 @@ type ArtifactContext struct { } func init() { - web.RegisterHandleTypeProvider[*ArtifactContext](func(req *http.Request) web.ResponseStatusProvider { + web.RegisterResponseStatusProvider[*ArtifactContext](func(req *http.Request) web_types.ResponseStatusProvider { return req.Context().Value(artifactContextKey).(*ArtifactContext) }) } diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 4f0f637fa57..fa7f66f3ab3 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -4,7 +4,6 @@ package packages import ( - gocontext "context" "net/http" "regexp" "strings" @@ -96,7 +95,7 @@ func verifyAuth(r *web.Route, authMethods []auth.Method) { // CommonRoutes provide endpoints for most package managers (except containers - see below) // These are mounted on `/api/packages` (not `/api/v1/packages`) -func CommonRoutes(ctx gocontext.Context) *web.Route { +func CommonRoutes() *web.Route { r := web.NewRoute() r.Use(context.PackageContexter()) @@ -590,7 +589,7 @@ func CommonRoutes(ctx gocontext.Context) *web.Route { // ContainerRoutes provides endpoints that implement the OCI API to serve containers // These have to be mounted on `/v2/...` to comply with the OCI spec: // https://github.com/opencontainers/distribution-spec/blob/main/spec.md -func ContainerRoutes(ctx gocontext.Context) *web.Route { +func ContainerRoutes() *web.Route { r := web.NewRoute() r.Use(context.PackageContexter()) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 37361a8b963..be66cc52408 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -64,7 +64,6 @@ package v1 import ( - gocontext "context" "fmt" "net/http" "strings" @@ -705,7 +704,7 @@ func buildAuthGroup() *auth.Group { } // Routes registers all v1 APIs routes to web application. -func Routes(ctx gocontext.Context) *web.Route { +func Routes() *web.Route { m := web.NewRoute() m.Use(securityHeaders()) @@ -722,13 +721,8 @@ func Routes(ctx gocontext.Context) *web.Route { } m.Use(context.APIContexter()) - group := buildAuthGroup() - if err := group.Init(ctx); err != nil { - log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err) - } - // Get user from session if logged in. - m.Use(auth.APIAuth(group)) + m.Use(auth.APIAuth(buildAuthGroup())) m.Use(auth.VerifyAuthWithOptionsAPI(&auth.VerifyOptions{ SignInRequired: setting.Service.RequireSignInView, diff --git a/routers/api/v1/misc/markup_test.go b/routers/api/v1/misc/markup_test.go index fdf540fd65b..bab06b3e662 100644 --- a/routers/api/v1/misc/markup_test.go +++ b/routers/api/v1/misc/markup_test.go @@ -7,18 +7,14 @@ import ( go_context "context" "io" "net/http" - "net/http/httptest" - "net/url" "strings" "testing" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/web" - "code.gitea.io/gitea/modules/web/middleware" "github.com/stretchr/testify/assert" ) @@ -29,34 +25,16 @@ const ( AppSubURL = AppURL + Repo + "/" ) -func createAPIContext(req *http.Request) (*context.APIContext, *httptest.ResponseRecorder) { - resp := httptest.NewRecorder() - base, baseCleanUp := context.NewBaseContext(resp, req) - base.Data = middleware.ContextData{} - c := &context.APIContext{Base: base} - _ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later - - return c, resp -} - func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, responseCode int) { setting.AppURL = AppURL - options := api.MarkupOption{ Mode: mode, - Text: "", + Text: text, Context: Repo, Wiki: true, FilePath: filePath, } - requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markup")) - req := &http.Request{ - Method: "POST", - URL: requrl, - } - ctx, resp := createAPIContext(req) - - options.Text = text + ctx, resp := test.MockAPIContext(t, "POST /api/v1/markup") web.SetForm(ctx, &options) Markup(ctx) assert.Equal(t, responseBody, resp.Body.String()) @@ -66,21 +44,13 @@ func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, r func testRenderMarkdown(t *testing.T, mode, text, responseBody string, responseCode int) { setting.AppURL = AppURL - options := api.MarkdownOption{ Mode: mode, - Text: "", + Text: text, Context: Repo, Wiki: true, } - requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) - req := &http.Request{ - Method: "POST", - URL: requrl, - } - ctx, resp := createAPIContext(req) - - options.Text = text + ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") web.SetForm(ctx, &options) Markdown(ctx) assert.Equal(t, responseBody, resp.Body.String()) @@ -187,19 +157,12 @@ var simpleCases = []string{ func TestAPI_RenderSimple(t *testing.T) { setting.AppURL = AppURL - options := api.MarkdownOption{ Mode: "markdown", Text: "", Context: Repo, } - requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) - req := &http.Request{ - Method: "POST", - URL: requrl, - } - ctx, resp := createAPIContext(req) - + ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") for i := 0; i < len(simpleCases); i += 2 { options.Text = simpleCases[i] web.SetForm(ctx, &options) @@ -211,14 +174,7 @@ func TestAPI_RenderSimple(t *testing.T) { func TestAPI_RenderRaw(t *testing.T) { setting.AppURL = AppURL - - requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) - req := &http.Request{ - Method: "POST", - URL: requrl, - } - ctx, resp := createAPIContext(req) - + ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") for i := 0; i < len(simpleCases); i += 2 { ctx.Req.Body = io.NopCloser(strings.NewReader(simpleCases[i])) MarkdownRaw(ctx) diff --git a/routers/api/v1/repo/hook_test.go b/routers/api/v1/repo/hook_test.go index 56658b45d59..b43a22cd55f 100644 --- a/routers/api/v1/repo/hook_test.go +++ b/routers/api/v1/repo/hook_test.go @@ -17,7 +17,7 @@ import ( func TestTestHook(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockAPIContext(t, "user2/repo1/wiki/_pages") + ctx, _ := test.MockAPIContext(t, "user2/repo1/wiki/_pages") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) diff --git a/routers/api/v1/repo/repo_test.go b/routers/api/v1/repo/repo_test.go index e1bdea5c82b..7593a87c2c0 100644 --- a/routers/api/v1/repo/repo_test.go +++ b/routers/api/v1/repo/repo_test.go @@ -19,7 +19,7 @@ import ( func TestRepoEdit(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockAPIContext(t, "user2/repo1") + ctx, _ := test.MockAPIContext(t, "user2/repo1") test.LoadRepo(t, ctx, 1) test.LoadUser(t, ctx, 2) ctx.Repo.Owner = ctx.Doer @@ -65,7 +65,7 @@ func TestRepoEdit(t *testing.T) { func TestRepoEditNameChange(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockAPIContext(t, "user2/repo1") + ctx, _ := test.MockAPIContext(t, "user2/repo1") test.LoadRepo(t, ctx, 1) test.LoadUser(t, ctx, 2) ctx.Repo.Owner = ctx.Doer diff --git a/routers/common/redirect.go b/routers/common/redirect.go new file mode 100644 index 00000000000..9bf2025e19e --- /dev/null +++ b/routers/common/redirect.go @@ -0,0 +1,26 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package common + +import ( + "net/http" + + "code.gitea.io/gitea/modules/httplib" +) + +// FetchRedirectDelegate helps the "fetch" requests to redirect to the correct location +func FetchRedirectDelegate(resp http.ResponseWriter, req *http.Request) { + // When use "fetch" to post requests and the response is a redirect, browser's "location.href = uri" has limitations. + // 1. change "location" from old "/foo" to new "/foo#hash", the browser will not reload the page. + // 2. when use "window.reload()", the hash is not respected, the newly loaded page won't scroll to the hash target. + // The typical page is "issue comment" page. The backend responds "/owner/repo/issues/1#comment-2", + // then frontend needs this delegate to redirect to the new location with hash correctly. + redirect := req.PostFormValue("redirect") + if httplib.IsRiskyRedirectURL(redirect) { + resp.WriteHeader(http.StatusBadRequest) + return + } + resp.Header().Add("Location", redirect) + resp.WriteHeader(http.StatusSeeOther) +} diff --git a/routers/init.go b/routers/init.go index 5737ef3dc06..54e8d2b8b39 100644 --- a/routers/init.go +++ b/routers/init.go @@ -174,25 +174,27 @@ func GlobalInitInstalled(ctx context.Context) { } // NormalRoutes represents non install routes -func NormalRoutes(ctx context.Context) *web.Route { +func NormalRoutes() *web.Route { _ = templates.HTMLRenderer() r := web.NewRoute() r.Use(common.ProtocolMiddlewares()...) - r.Mount("/", web_routers.Routes(ctx)) - r.Mount("/api/v1", apiv1.Routes(ctx)) + r.Mount("/", web_routers.Routes()) + r.Mount("/api/v1", apiv1.Routes()) r.Mount("/api/internal", private.Routes()) + r.Post("/-/fetch-redirect", common.FetchRedirectDelegate) + if setting.Packages.Enabled { // This implements package support for most package managers - r.Mount("/api/packages", packages_router.CommonRoutes(ctx)) + r.Mount("/api/packages", packages_router.CommonRoutes()) // This implements the OCI API (Note this is not preceded by /api but is instead /v2) - r.Mount("/v2", packages_router.ContainerRoutes(ctx)) + r.Mount("/v2", packages_router.ContainerRoutes()) } if setting.Actions.Enabled { prefix := "/api/actions" - r.Mount(prefix, actions_router.Routes(ctx, prefix)) + r.Mount(prefix, actions_router.Routes(prefix)) // TODO: Pipeline api used for runner internal communication with gitea server. but only artifact is used for now. // In Github, it uses ACTIONS_RUNTIME_URL=https://pipelines.actions.githubusercontent.com/fLgcSHkPGySXeIFrg8W8OBSfeg3b5Fls1A1CwX566g8PayEGlg/ diff --git a/routers/install/install.go b/routers/install/install.go index 4dba64df01d..16bb55b685b 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -393,6 +393,7 @@ func SubmitInstall(ctx *context.Context) { cfg.Section("server").Key("DOMAIN").SetValue(form.Domain) cfg.Section("server").Key("HTTP_PORT").SetValue(form.HTTPPort) cfg.Section("server").Key("ROOT_URL").SetValue(form.AppURL) + cfg.Section("server").Key("APP_DATA_PATH").SetValue(setting.AppDataPath) if form.SSHPort == 0 { cfg.Section("server").Key("DISABLE_SSH").SetValue("true") diff --git a/routers/web/admin/users_test.go b/routers/web/admin/users_test.go index ed58a54eef9..19d6d7294da 100644 --- a/routers/web/admin/users_test.go +++ b/routers/web/admin/users_test.go @@ -19,7 +19,7 @@ import ( func TestNewUserPost_MustChangePassword(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "admin/users/new") + ctx, _ := test.MockContext(t, "admin/users/new") u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, @@ -56,7 +56,7 @@ func TestNewUserPost_MustChangePassword(t *testing.T) { func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "admin/users/new") + ctx, _ := test.MockContext(t, "admin/users/new") u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, @@ -93,7 +93,7 @@ func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { func TestNewUserPost_InvalidEmail(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "admin/users/new") + ctx, _ := test.MockContext(t, "admin/users/new") u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, @@ -123,7 +123,7 @@ func TestNewUserPost_InvalidEmail(t *testing.T) { func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "admin/users/new") + ctx, _ := test.MockContext(t, "admin/users/new") u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, @@ -161,7 +161,7 @@ func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { func TestNewUserPost_VisibilityPrivate(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "admin/users/new") + ctx, _ := test.MockContext(t, "admin/users/new") u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 80f149d8061..0ce3bbde003 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -4,7 +4,7 @@ package auth import ( - stdContext "context" + go_context "context" "encoding/base64" "errors" "fmt" @@ -12,6 +12,7 @@ import ( "io" "net/http" "net/url" + "sort" "strings" "code.gitea.io/gitea/models/auth" @@ -39,6 +40,7 @@ import ( "github.com/golang-jwt/jwt/v4" "github.com/markbates/goth" "github.com/markbates/goth/gothic" + go_oauth2 "golang.org/x/oauth2" ) const ( @@ -143,7 +145,7 @@ type AccessTokenResponse struct { IDToken string `json:"id_token,omitempty"` } -func newAccessTokenResponse(ctx stdContext.Context, grant *auth.OAuth2Grant, serverKey, clientKey oauth2.JWTSigningKey) (*AccessTokenResponse, *AccessTokenError) { +func newAccessTokenResponse(ctx go_context.Context, grant *auth.OAuth2Grant, serverKey, clientKey oauth2.JWTSigningKey) (*AccessTokenResponse, *AccessTokenError) { if setting.OAuth2.InvalidateRefreshTokens { if err := grant.IncreaseCounter(ctx); err != nil { return nil, &AccessTokenError{ @@ -886,6 +888,17 @@ func SignInOAuth(ctx *context.Context) { func SignInOAuthCallback(ctx *context.Context) { provider := ctx.Params(":provider") + if ctx.Req.FormValue("error") != "" { + var errorKeyValues []string + for k, vv := range ctx.Req.Form { + for _, v := range vv { + errorKeyValues = append(errorKeyValues, fmt.Sprintf("%s = %s", html.EscapeString(k), html.EscapeString(v))) + } + } + sort.Strings(errorKeyValues) + ctx.Flash.Error(strings.Join(errorKeyValues, "
"), true) + } + // first look if the provider is still active authSource, err := auth.GetActiveOAuth2SourceByName(provider) if err != nil { @@ -894,7 +907,7 @@ func SignInOAuthCallback(ctx *context.Context) { } if authSource == nil { - ctx.ServerError("SignIn", errors.New("No valid provider found, check configured callback url in provider")) + ctx.ServerError("SignIn", errors.New("no valid provider found, check configured callback url in provider")) return } @@ -920,6 +933,9 @@ func SignInOAuthCallback(ctx *context.Context) { ctx.Redirect(setting.AppSubURL + "/user/login") return } + if err, ok := err.(*go_oauth2.RetrieveError); ok { + ctx.Flash.Error("OAuth2 RetrieveError: "+err.Error(), true) + } ctx.ServerError("UserSignIn", err) return } diff --git a/routers/web/org/projects_test.go b/routers/web/org/projects_test.go index 3450fa8e72d..08a97b7d2de 100644 --- a/routers/web/org/projects_test.go +++ b/routers/web/org/projects_test.go @@ -15,7 +15,7 @@ import ( func TestCheckProjectBoardChangePermissions(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/-/projects/4/4") + ctx, _ := test.MockContext(t, "user2/-/projects/4/4") test.LoadUser(t, ctx, 2) ctx.ContextUser = ctx.Doer // user2 ctx.SetParams(":id", "4") diff --git a/routers/web/repo/editor_test.go b/routers/web/repo/editor_test.go index 1e53aac9b09..52dded68b79 100644 --- a/routers/web/repo/editor_test.go +++ b/routers/web/repo/editor_test.go @@ -41,7 +41,7 @@ func TestCleanUploadName(t *testing.T) { func TestGetUniquePatchBranchName(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -56,7 +56,7 @@ func TestGetUniquePatchBranchName(t *testing.T) { func TestGetClosestParentWithFiles(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 5ab8db2e057..9f087edc72d 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1134,12 +1134,12 @@ func NewIssuePost(ctx *context.Context) { } if ctx.HasError() { - ctx.HTML(http.StatusOK, tplIssueNew) + ctx.JSONError(ctx.GetErrMsg()) return } if util.IsEmptyString(form.Title) { - ctx.RenderWithErr(ctx.Tr("repo.issues.new.title_empty"), tplIssueNew, form) + ctx.JSONError(ctx.Tr("repo.issues.new.title_empty")) return } @@ -1184,9 +1184,9 @@ func NewIssuePost(ctx *context.Context) { log.Trace("Issue created: %d/%d", repo.ID, issue.ID) if ctx.FormString("redirect_after_creation") == "project" && projectID > 0 { - ctx.Redirect(ctx.Repo.RepoLink + "/projects/" + strconv.FormatInt(projectID, 10)) + ctx.JSONRedirect(ctx.Repo.RepoLink + "/projects/" + strconv.FormatInt(projectID, 10)) } else { - ctx.Redirect(issue.Link()) + ctx.JSONRedirect(issue.Link()) } } @@ -2777,8 +2777,7 @@ func NewComment(ctx *context.Context) { } if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.Doer.IsAdmin { - ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked")) - ctx.Redirect(issue.Link()) + ctx.JSONError(ctx.Tr("repo.issues.comment_on_locked")) return } @@ -2788,8 +2787,7 @@ func NewComment(ctx *context.Context) { } if ctx.HasError() { - ctx.Flash.Error(ctx.Data["ErrorMsg"].(string)) - ctx.Redirect(issue.Link()) + ctx.JSONError(ctx.GetErrMsg()) return } @@ -2809,8 +2807,7 @@ func NewComment(ctx *context.Context) { pr, err = issues_model.GetUnmergedPullRequest(ctx, pull.HeadRepoID, pull.BaseRepoID, pull.HeadBranch, pull.BaseBranch, pull.Flow) if err != nil { if !issues_model.IsErrPullRequestNotExist(err) { - ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked")) - ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, pull.Index)) + ctx.JSONError(ctx.Tr("repo.issues.dependency.pr_close_blocked")) return } } @@ -2841,8 +2838,7 @@ func NewComment(ctx *context.Context) { } if ok := git.IsBranchExist(ctx, pull.HeadRepo.RepoPath(), pull.BaseBranch); !ok { // todo localize - ctx.Flash.Error("The origin branch is delete, cannot reopen.") - ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, pull.Index)) + ctx.JSONError("The origin branch is delete, cannot reopen.") return } headBranchRef := pull.GetGitHeadBranchRefName() @@ -2882,11 +2878,9 @@ func NewComment(ctx *context.Context) { if issues_model.IsErrDependenciesLeft(err) { if issue.IsPull { - ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked")) - ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, issue.Index)) + ctx.JSONError(ctx.Tr("repo.issues.dependency.pr_close_blocked")) } else { - ctx.Flash.Error(ctx.Tr("repo.issues.dependency.issue_close_blocked")) - ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issue.Index)) + ctx.JSONError(ctx.Tr("repo.issues.dependency.issue_close_blocked")) } return } @@ -2899,7 +2893,6 @@ func NewComment(ctx *context.Context) { log.Trace("Issue [%d] status changed to closed: %v", issue.ID, issue.IsClosed) } } - } // Redirect to comment hashtag if there is any actual content. @@ -2908,9 +2901,9 @@ func NewComment(ctx *context.Context) { typeName = "pulls" } if comment != nil { - ctx.Redirect(fmt.Sprintf("%s/%s/%d#%s", ctx.Repo.RepoLink, typeName, issue.Index, comment.HashTag())) + ctx.JSONRedirect(fmt.Sprintf("%s/%s/%d#%s", ctx.Repo.RepoLink, typeName, issue.Index, comment.HashTag())) } else { - ctx.Redirect(fmt.Sprintf("%s/%s/%d", ctx.Repo.RepoLink, typeName, issue.Index)) + ctx.JSONRedirect(fmt.Sprintf("%s/%s/%d", ctx.Repo.RepoLink, typeName, issue.Index)) } }() diff --git a/routers/web/repo/issue_label_test.go b/routers/web/repo/issue_label_test.go index c24fe898b6b..4c9a3594380 100644 --- a/routers/web/repo/issue_label_test.go +++ b/routers/web/repo/issue_label_test.go @@ -32,7 +32,7 @@ func int64SliceToCommaSeparated(a []int64) string { func TestInitializeLabels(t *testing.T) { unittest.PrepareTestEnv(t) assert.NoError(t, repository.LoadRepoConfig()) - ctx := test.MockContext(t, "user2/repo1/labels/initialize") + ctx, _ := test.MockContext(t, "user2/repo1/labels/initialize") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 2) web.SetForm(ctx, &forms.InitializeLabelsForm{TemplateName: "Default"}) @@ -57,7 +57,7 @@ func TestRetrieveLabels(t *testing.T) { {1, "leastissues", []int64{2, 1}}, {2, "", []int64{}}, } { - ctx := test.MockContext(t, "user/repo/issues") + ctx, _ := test.MockContext(t, "user/repo/issues") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, testCase.RepoID) ctx.Req.Form.Set("sort", testCase.Sort) @@ -75,7 +75,7 @@ func TestRetrieveLabels(t *testing.T) { func TestNewLabel(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/labels/edit") + ctx, _ := test.MockContext(t, "user2/repo1/labels/edit") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) web.SetForm(ctx, &forms.CreateLabelForm{ @@ -93,7 +93,7 @@ func TestNewLabel(t *testing.T) { func TestUpdateLabel(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/labels/edit") + ctx, _ := test.MockContext(t, "user2/repo1/labels/edit") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) web.SetForm(ctx, &forms.CreateLabelForm{ @@ -113,7 +113,7 @@ func TestUpdateLabel(t *testing.T) { func TestDeleteLabel(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/labels/delete") + ctx, _ := test.MockContext(t, "user2/repo1/labels/delete") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) ctx.Req.Form.Set("id", "2") @@ -126,7 +126,7 @@ func TestDeleteLabel(t *testing.T) { func TestUpdateIssueLabel_Clear(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) ctx.Req.Form.Set("issue_ids", "1,3") @@ -151,7 +151,7 @@ func TestUpdateIssueLabel_Toggle(t *testing.T) { {"toggle", []int64{1, 2}, 2, true}, } { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) ctx.Req.Form.Set("issue_ids", int64SliceToCommaSeparated(testCase.IssueIDs)) diff --git a/routers/web/repo/projects_test.go b/routers/web/repo/projects_test.go index c712902ea9f..e2797772a8f 100644 --- a/routers/web/repo/projects_test.go +++ b/routers/web/repo/projects_test.go @@ -14,7 +14,7 @@ import ( func TestCheckProjectBoardChangePermissions(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/projects/1/2") + ctx, _ := test.MockContext(t, "user2/repo1/projects/1/2") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) ctx.SetParams(":id", "1") diff --git a/routers/web/repo/release_test.go b/routers/web/repo/release_test.go index 9ec1b4d3492..07e349811e3 100644 --- a/routers/web/repo/release_test.go +++ b/routers/web/repo/release_test.go @@ -47,7 +47,7 @@ func TestNewReleasePost(t *testing.T) { } { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/releases/new") + ctx, _ := test.MockContext(t, "user2/repo1/releases/new") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) test.LoadGitRepo(t, ctx) @@ -67,7 +67,7 @@ func TestNewReleasePost(t *testing.T) { func TestNewReleasesList(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo-release/releases") + ctx, _ := test.MockContext(t, "user2/repo-release/releases") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 57) test.LoadGitRepo(t, ctx) diff --git a/routers/web/repo/settings_test.go b/routers/web/repo/settings_test.go index 3bb202505c4..a33e92c8211 100644 --- a/routers/web/repo/settings_test.go +++ b/routers/web/repo/settings_test.go @@ -42,7 +42,7 @@ func TestAddReadOnlyDeployKey(t *testing.T) { } unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/settings/keys") + ctx, _ := test.MockContext(t, "user2/repo1/settings/keys") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 2) @@ -71,7 +71,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/settings/keys") + ctx, _ := test.MockContext(t, "user2/repo1/settings/keys") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 2) @@ -94,7 +94,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) { func TestCollaborationPost(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadUser(t, ctx, 4) test.LoadRepo(t, ctx, 1) @@ -129,7 +129,7 @@ func TestCollaborationPost(t *testing.T) { func TestCollaborationPost_InactiveUser(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadUser(t, ctx, 9) test.LoadRepo(t, ctx, 1) @@ -152,7 +152,7 @@ func TestCollaborationPost_InactiveUser(t *testing.T) { func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadUser(t, ctx, 4) test.LoadRepo(t, ctx, 1) @@ -193,7 +193,7 @@ func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { func TestCollaborationPost_NonExistentUser(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) @@ -215,7 +215,7 @@ func TestCollaborationPost_NonExistentUser(t *testing.T) { func TestAddTeamPost(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "org26/repo43") + ctx, _ := test.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team11") @@ -255,7 +255,7 @@ func TestAddTeamPost(t *testing.T) { func TestAddTeamPost_NotAllowed(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "org26/repo43") + ctx, _ := test.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team11") @@ -295,7 +295,7 @@ func TestAddTeamPost_NotAllowed(t *testing.T) { func TestAddTeamPost_AddTeamTwice(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "org26/repo43") + ctx, _ := test.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team11") @@ -336,7 +336,7 @@ func TestAddTeamPost_AddTeamTwice(t *testing.T) { func TestAddTeamPost_NonExistentTeam(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "org26/repo43") + ctx, _ := test.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team-non-existent") @@ -369,7 +369,7 @@ func TestAddTeamPost_NonExistentTeam(t *testing.T) { func TestDeleteTeam(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "org3/team1/repo3") + ctx, _ := test.MockContext(t, "org3/team1/repo3") ctx.Req.Form.Set("id", "2") diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index cf719c49f0b..ad87bae9b8f 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -390,6 +390,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["IsRepresentableAsText"] = isRepresentableAsText ctx.Data["IsDisplayingSource"] = isDisplayingSource ctx.Data["IsDisplayingRendered"] = isDisplayingRendered + ctx.Data["IsExecutable"] = entry.IsExecutable() isTextSource := fInfo.isTextFile || isDisplayingSource ctx.Data["IsTextSource"] = isTextSource diff --git a/routers/web/repo/wiki_test.go b/routers/web/repo/wiki_test.go index e51820a520e..d85879d1e5c 100644 --- a/routers/web/repo/wiki_test.go +++ b/routers/web/repo/wiki_test.go @@ -78,7 +78,7 @@ func assertPagesMetas(t *testing.T, expectedNames []string, metas interface{}) { func TestWiki(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/?action=_pages") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_pages") ctx.SetParams("*", "Home") test.LoadRepo(t, ctx, 1) Wiki(ctx) @@ -90,7 +90,7 @@ func TestWiki(t *testing.T) { func TestWikiPages(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/?action=_pages") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_pages") test.LoadRepo(t, ctx, 1) WikiPages(ctx) assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) @@ -100,7 +100,7 @@ func TestWikiPages(t *testing.T) { func TestNewWiki(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) NewWiki(ctx) @@ -115,7 +115,7 @@ func TestNewWikiPost(t *testing.T) { } { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) web.SetForm(ctx, &forms.NewWikiForm{ @@ -133,7 +133,7 @@ func TestNewWikiPost(t *testing.T) { func TestNewWikiPost_ReservedName(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) web.SetForm(ctx, &forms.NewWikiForm{ @@ -150,7 +150,7 @@ func TestNewWikiPost_ReservedName(t *testing.T) { func TestEditWiki(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_edit") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_edit") ctx.SetParams("*", "Home") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) @@ -166,7 +166,7 @@ func TestEditWikiPost(t *testing.T) { "New/", } { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_new") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_new") ctx.SetParams("*", "Home") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) @@ -188,7 +188,7 @@ func TestEditWikiPost(t *testing.T) { func TestDeleteWikiPagePost(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_delete") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_delete") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) DeleteWikiPagePost(ctx) @@ -207,7 +207,7 @@ func TestWikiRaw(t *testing.T) { } { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/raw/"+url.PathEscape(filepath)) + ctx, _ := test.MockContext(t, "user2/repo1/wiki/raw/"+url.PathEscape(filepath)) ctx.SetParams("*", filepath) test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) diff --git a/routers/web/user/home_test.go b/routers/web/user/home_test.go index 534b0b26207..3a06a38c245 100644 --- a/routers/web/user/home_test.go +++ b/routers/web/user/home_test.go @@ -20,7 +20,7 @@ func TestArchivedIssues(t *testing.T) { setting.UI.IssuePagingNum = 1 assert.NoError(t, unittest.LoadFixtures()) - ctx := test.MockContext(t, "issues") + ctx, _ := test.MockContext(t, "issues") test.LoadUser(t, ctx, 30) ctx.Req.Form.Set("state", "open") @@ -53,7 +53,7 @@ func TestIssues(t *testing.T) { setting.UI.IssuePagingNum = 1 assert.NoError(t, unittest.LoadFixtures()) - ctx := test.MockContext(t, "issues") + ctx, _ := test.MockContext(t, "issues") test.LoadUser(t, ctx, 2) ctx.Req.Form.Set("state", "closed") Issues(ctx) @@ -69,7 +69,7 @@ func TestPulls(t *testing.T) { setting.UI.IssuePagingNum = 20 assert.NoError(t, unittest.LoadFixtures()) - ctx := test.MockContext(t, "pulls") + ctx, _ := test.MockContext(t, "pulls") test.LoadUser(t, ctx, 2) ctx.Req.Form.Set("state", "open") Pulls(ctx) @@ -82,7 +82,7 @@ func TestMilestones(t *testing.T) { setting.UI.IssuePagingNum = 1 assert.NoError(t, unittest.LoadFixtures()) - ctx := test.MockContext(t, "milestones") + ctx, _ := test.MockContext(t, "milestones") test.LoadUser(t, ctx, 2) ctx.SetParams("sort", "issues") ctx.Req.Form.Set("state", "closed") @@ -101,7 +101,7 @@ func TestMilestonesForSpecificRepo(t *testing.T) { setting.UI.IssuePagingNum = 1 assert.NoError(t, unittest.LoadFixtures()) - ctx := test.MockContext(t, "milestones") + ctx, _ := test.MockContext(t, "milestones") test.LoadUser(t, ctx, 2) ctx.SetParams("sort", "issues") ctx.SetParams("repo", "1") diff --git a/routers/web/user/setting/account_test.go b/routers/web/user/setting/account_test.go index 569d597722e..ba840db2889 100644 --- a/routers/web/user/setting/account_test.go +++ b/routers/web/user/setting/account_test.go @@ -83,7 +83,7 @@ func TestChangePassword(t *testing.T) { t.Run(req.OldPassword+"__"+req.NewPassword, func(t *testing.T) { unittest.PrepareTestEnv(t) setting.PasswordComplexity = req.PasswordComplexity - ctx := test.MockContext(t, "user/settings/security") + ctx, _ := test.MockContext(t, "user/settings/security") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) diff --git a/routers/web/web.go b/routers/web/web.go index 5f6d63039a6..7261e2c8735 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -104,7 +104,7 @@ func ctxDataSet(args ...any) func(ctx *context.Context) { } // Routes returns all web routes -func Routes(ctx gocontext.Context) *web.Route { +func Routes() *web.Route { routes := web.NewRoute() routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler @@ -146,13 +146,8 @@ func Routes(ctx gocontext.Context) *web.Route { mid = append(mid, common.Sessioner(), context.Contexter()) - group := buildAuthGroup() - if err := group.Init(ctx); err != nil { - log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err) - } - // Get user from session if logged in. - mid = append(mid, auth_service.Auth(group)) + mid = append(mid, auth_service.Auth(buildAuthGroup())) // GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route mid = append(mid, middleware.GetHead) diff --git a/services/auth/group.go b/services/auth/group.go index 0a0330b3aa9..a1ff65f2038 100644 --- a/services/auth/group.go +++ b/services/auth/group.go @@ -4,7 +4,6 @@ package auth import ( - "context" "net/http" "reflect" "strings" @@ -14,9 +13,7 @@ import ( // Ensure the struct implements the interface. var ( - _ Method = &Group{} - _ Initializable = &Group{} - _ Freeable = &Group{} + _ Method = &Group{} ) // Group implements the Auth interface with serval Auth. @@ -49,35 +46,6 @@ func (b *Group) Name() string { return strings.Join(names, ",") } -// Init does nothing as the Basic implementation does not need to allocate any resources -func (b *Group) Init(ctx context.Context) error { - for _, method := range b.methods { - initializable, ok := method.(Initializable) - if !ok { - continue - } - - if err := initializable.Init(ctx); err != nil { - return err - } - } - return nil -} - -// Free does nothing as the Basic implementation does not have to release any resources -func (b *Group) Free() error { - for _, method := range b.methods { - freeable, ok := method.(Freeable) - if !ok { - continue - } - if err := freeable.Free(); err != nil { - return err - } - } - return nil -} - // Verify extracts and validates func (b *Group) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { // Try to sign in with each of the enabled plugins diff --git a/services/auth/interface.go b/services/auth/interface.go index c4a8a20d010..508291fa431 100644 --- a/services/auth/interface.go +++ b/services/auth/interface.go @@ -29,26 +29,11 @@ type Method interface { Verify(http *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) } -// Initializable represents a structure that requires initialization -// It usually should only be called once before anything else is called -type Initializable interface { - // Init should be called exactly once before using any of the other methods, - // in order to allow the plugin to allocate necessary resources - Init(ctx context.Context) error -} - // Named represents a named thing type Named interface { Name() string } -// Freeable represents a structure that is required to be freed -type Freeable interface { - // Free should be called exactly once before application closes, in order to - // give chance to the plugin to free any allocated resources - Free() error -} - // PasswordAuthenticator represents a source of authentication type PasswordAuthenticator interface { Authenticate(user *user_model.User, login, password string) (*user_model.User, error) diff --git a/services/auth/sspi_windows.go b/services/auth/sspi_windows.go index d49497e19c9..c162810797c 100644 --- a/services/auth/sspi_windows.go +++ b/services/auth/sspi_windows.go @@ -4,10 +4,10 @@ package auth import ( - "context" "errors" "net/http" "strings" + "sync" "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/avatars" @@ -32,13 +32,12 @@ var ( // sspiAuth is a global instance of the websspi authentication package, // which is used to avoid acquiring the server credential handle on // every request - sspiAuth *websspi.Authenticator + sspiAuth *websspi.Authenticator + sspiAuthOnce sync.Once // Ensure the struct implements the interface. - _ Method = &SSPI{} - _ Named = &SSPI{} - _ Initializable = &SSPI{} - _ Freeable = &SSPI{} + _ Method = &SSPI{} + _ Named = &SSPI{} ) // SSPI implements the SingleSignOn interface and authenticates requests @@ -47,32 +46,25 @@ var ( // Returns nil if authentication fails. type SSPI struct{} -// Init creates a new global websspi.Authenticator object -func (s *SSPI) Init(ctx context.Context) error { - config := websspi.NewConfig() - var err error - sspiAuth, err = websspi.New(config) - if err != nil { - return err - } - return nil -} - // Name represents the name of auth method func (s *SSPI) Name() string { return "sspi" } -// Free releases resources used by the global websspi.Authenticator object -func (s *SSPI) Free() error { - return sspiAuth.Free() -} - // Verify uses SSPI (Windows implementation of SPNEGO) to authenticate the request. // If authentication is successful, returns the corresponding user object. // If negotiation should continue or authentication fails, immediately returns a 401 HTTP // response code, as required by the SPNEGO protocol. func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { + var errInit error + sspiAuthOnce.Do(func() { + config := websspi.NewConfig() + sspiAuth, errInit = websspi.New(config) + }) + if errInit != nil { + return nil, errInit + } + if !s.shouldAuthenticate(req) { return nil, nil } diff --git a/services/repository/archiver/archiver_test.go b/services/repository/archiver/archiver_test.go index 3cd6e813512..4b6fb7446da 100644 --- a/services/repository/archiver/archiver_test.go +++ b/services/repository/archiver/archiver_test.go @@ -24,7 +24,7 @@ func TestMain(m *testing.M) { func TestArchive_Basic(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - ctx := test.MockContext(t, "user27/repo49") + ctx, _ := test.MockContext(t, "user27/repo49") firstCommit, secondCommit := "51f84af23134", "aacbdfe9e1c4" test.LoadRepo(t, ctx, 49) diff --git a/services/repository/files/content_test.go b/services/repository/files/content_test.go index a43b71cf31e..8ff96822c9a 100644 --- a/services/repository/files/content_test.go +++ b/services/repository/files/content_test.go @@ -54,7 +54,7 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse { func TestGetContents(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -82,7 +82,7 @@ func TestGetContents(t *testing.T) { func TestGetContentsOrListForDir(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -117,7 +117,7 @@ func TestGetContentsOrListForDir(t *testing.T) { func TestGetContentsOrListForFile(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -145,7 +145,7 @@ func TestGetContentsOrListForFile(t *testing.T) { func TestGetContentsErrors(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -176,7 +176,7 @@ func TestGetContentsErrors(t *testing.T) { func TestGetContentsOrListErrors(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -207,7 +207,7 @@ func TestGetContentsOrListErrors(t *testing.T) { func TestGetContentsOrListOfEmptyRepos(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user30/empty") + ctx, _ := test.MockContext(t, "user30/empty") ctx.SetParams(":id", "52") test.LoadRepo(t, ctx, 52) test.LoadUser(t, ctx, 30) @@ -225,7 +225,7 @@ func TestGetContentsOrListOfEmptyRepos(t *testing.T) { func TestGetBlobBySHA(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) test.LoadUser(t, ctx, 2) diff --git a/services/repository/files/diff_test.go b/services/repository/files/diff_test.go index 621816e97d4..0346e0e9e9b 100644 --- a/services/repository/files/diff_test.go +++ b/services/repository/files/diff_test.go @@ -17,7 +17,7 @@ import ( func TestGetDiffPreview(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -139,7 +139,7 @@ func TestGetDiffPreview(t *testing.T) { func TestGetDiffPreviewErrors(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) diff --git a/services/repository/files/file_test.go b/services/repository/files/file_test.go index e1c7d5d7fb4..d14a049438e 100644 --- a/services/repository/files/file_test.go +++ b/services/repository/files/file_test.go @@ -98,7 +98,7 @@ func getExpectedFileResponse() *api.FileResponse { func TestGetFileResponseFromCommit(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) diff --git a/services/repository/files/tree_test.go b/services/repository/files/tree_test.go index a500dbdb224..51a2190e8f4 100644 --- a/services/repository/files/tree_test.go +++ b/services/repository/files/tree_test.go @@ -15,7 +15,7 @@ import ( func TestGetTreeBySHA(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) test.LoadUser(t, ctx, 2) diff --git a/templates/admin/auth/edit.tmpl b/templates/admin/auth/edit.tmpl index af9d4c4bc50..801cf9e7b45 100644 --- a/templates/admin/auth/edit.tmpl +++ b/templates/admin/auth/edit.tmpl @@ -14,8 +14,8 @@ {{.Source.TypeName}}
- - + +
@@ -36,11 +36,11 @@
- +
- +
@@ -51,7 +51,7 @@ {{if .Source.IsLDAP}}
- +
@@ -60,17 +60,17 @@ {{end}}
- +
{{if .Source.IsDLDAP}}
- +
{{end}}
- +
@@ -95,15 +95,15 @@
- +
- +
- +
@@ -117,23 +117,23 @@
- +
- +
- +
- +
- +
@@ -360,7 +360,7 @@
- +
@@ -434,6 +434,17 @@
+ +

+ {{.locale.Tr "admin.auths.tips"}} +

+
+
GMail Settings:
+

Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true

+ +
{{.locale.Tr "admin.auths.tips.oauth2.general"}}:
+

{{.locale.Tr "admin.auths.tips.oauth2.general.tip"}}

+
- - + +
@@ -85,8 +85,8 @@
GMail Settings:

Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true

-
{{.locale.Tr "admin.auths.tips.oauth2.general"}}:
-

{{.locale.Tr "admin.auths.tips.oauth2.general.tip"}}

+
{{.locale.Tr "admin.auths.tips.oauth2.general"}}:
+

{{.locale.Tr "admin.auths.tips.oauth2.general.tip"}}

{{.locale.Tr "admin.auths.tip.oauth2_provider"}}
diff --git a/templates/admin/auth/source/ldap.tmpl b/templates/admin/auth/source/ldap.tmpl index 26eef890b29..a2bd37be0c5 100644 --- a/templates/admin/auth/source/ldap.tmpl +++ b/templates/admin/auth/source/ldap.tmpl @@ -14,11 +14,11 @@
- +
- +
@@ -28,7 +28,7 @@
- +
@@ -36,15 +36,15 @@
- +
- +
- +
@@ -69,15 +69,15 @@
- +
- +
- +
@@ -90,23 +90,23 @@
- +
- +
- +
- +
- +
diff --git a/templates/admin/auth/source/oauth.tmpl b/templates/admin/auth/source/oauth.tmpl index a0c5a87d0ff..aaa8b7fe2d6 100644 --- a/templates/admin/auth/source/oauth.tmpl +++ b/templates/admin/auth/source/oauth.tmpl @@ -100,7 +100,7 @@
- +
diff --git a/templates/admin/queue.tmpl b/templates/admin/queue.tmpl index f58f25e4ae0..4ed9dbb9aa5 100644 --- a/templates/admin/queue.tmpl +++ b/templates/admin/queue.tmpl @@ -23,7 +23,7 @@ {{$q.GetItemTypeName}} {{$sum := $q.GetWorkerNumber}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}} {{$sum = $q.GetQueueItemNumber}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}} - {{if lt $sum 0}}{{$.locale.Tr "admin.monitor.queue.review"}}{{else}}{{$.locale.Tr "admin.monitor.queue.review_add"}}{{end}} + {{if lt $sum 0}}{{$.locale.Tr "admin.monitor.queue.review"}}{{else}}{{$.locale.Tr "admin.monitor.queue.review_add"}}{{end}} {{end}} diff --git a/templates/admin/queue_manage.tmpl b/templates/admin/queue_manage.tmpl index d456c2fbab6..c8ae07a19a1 100644 --- a/templates/admin/queue_manage.tmpl +++ b/templates/admin/queue_manage.tmpl @@ -44,7 +44,7 @@

{{.locale.Tr "admin.monitor.queue.settings.desc"}}

-
+ {{$.CsrfTokenHtml}}
diff --git a/templates/admin/repo/unadopted.tmpl b/templates/admin/repo/unadopted.tmpl index 27898a18540..7b86b0defd7 100644 --- a/templates/admin/repo/unadopted.tmpl +++ b/templates/admin/repo/unadopted.tmpl @@ -31,7 +31,7 @@

{{$.locale.Tr "repo.adopt_preexisting_content" $dir}}

- + {{$.CsrfTokenHtml}} @@ -48,7 +48,7 @@

{{$.locale.Tr "repo.delete_preexisting_content" $dir}}

- + {{$.CsrfTokenHtml}} diff --git a/templates/admin/user/edit.tmpl b/templates/admin/user/edit.tmpl index 63703d78371..75bbd9a97c3 100644 --- a/templates/admin/user/edit.tmpl +++ b/templates/admin/user/edit.tmpl @@ -72,7 +72,7 @@
- +
@@ -197,7 +197,7 @@ {{svg "octicon-trash"}} {{.locale.Tr "settings.delete_account_title"}}
- +

{{.locale.Tr "settings.delete_account_desc"}}

{{$.CsrfTokenHtml}} diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 5e41636ba39..e46e276ed02 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -91,7 +91,7 @@ {{if .ActiveStopwatch}}{{Sec2Time .ActiveStopwatch.Seconds}}{{end}} - + {{.CsrfTokenHtml}} -
+ {{.CsrfTokenHtml}}
+
+

SVG alignment

+ +

Text with SVG

+
{{svg "octicon-alert"}} {{svg "octicon-x"}} text (block)
+
{{svg "octicon-alert"}} {{svg "octicon-x"}} text
(inline)
+
+
{{svg "octicon-alert"}} flex every line
+
{{svg "octicon-alert"}} flex every item
+
+ +

Button with SVG

+
+ +
+ + 123 +
+
+ +

Input with SVG

+
+ +
+ +

Dropdown with SVG

+
+ + + + + +
+ + +
+
+ +
+ + +
+
+

ComboMarkdownEditor

ps: no JS code attached, so just a layout
diff --git a/templates/install.tmpl b/templates/install.tmpl index 52be6a6013e..1cd5dcff8ba 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -139,7 +139,7 @@
- + {{.locale.Tr "install.domain_helper"}}
@@ -154,7 +154,7 @@
- + {{.locale.Tr "install.app_url_helper"}}
diff --git a/templates/mail/notify/repo_transfer.tmpl b/templates/mail/notify/repo_transfer.tmpl index 586f83e6525..43d95b3ff09 100644 --- a/templates/mail/notify/repo_transfer.tmpl +++ b/templates/mail/notify/repo_transfer.tmpl @@ -9,6 +9,7 @@

{{.Subject}}. {{.locale.Tr "mail.repo.transfer.body" $url | Str2html}} +

---
diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index f215dd52cd0..260a8ba803c 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -34,12 +34,12 @@

{{.locale.Tr "org.team_access_desc"}}

    {{if .Team.IncludesAllRepositories}} -
  • {{.locale.Tr "org.teams.all_repositories" | Str2html}} +
  • {{.locale.Tr "org.teams.all_repositories" | Str2html}}
  • {{else}} -
  • {{.locale.Tr "org.teams.specific_repositories" | Str2html}} +
  • {{.locale.Tr "org.teams.specific_repositories" | Str2html}}
  • {{end}} {{if .Team.CanCreateOrgRepo}} -
  • {{.locale.Tr "org.teams.can_create_org_repo"}} +
  • {{.locale.Tr "org.teams.can_create_org_repo"}}
  • {{end}}
{{if (eq .Team.AccessMode 2)}} diff --git a/templates/package/content/rpm.tmpl b/templates/package/content/rpm.tmpl index 49a9273771b..63bb8b07920 100644 --- a/templates/package/content/rpm.tmpl +++ b/templates/package/content/rpm.tmpl @@ -4,7 +4,7 @@
-
dnf config-manager --add-repo 
+
dnf config-manager --add-repo 
diff --git a/templates/projects/list.tmpl b/templates/projects/list.tmpl index e9e86e5d5d5..bde9925ab98 100644 --- a/templates/projects/list.tmpl +++ b/templates/projects/list.tmpl @@ -35,33 +35,36 @@
-
+
{{range .Projects}} -
  • - {{svg .IconName}} {{.Title}} -
    - {{$closedDate:= TimeSinceUnix .ClosedDateUnix $.locale}} - {{if .IsClosed}} - {{svg "octicon-clock"}} {{$.locale.Tr "repo.milestones.closed" $closedDate | Safe}} +
  • +

    + {{svg .IconName 16}} + {{.Title}} +

    +
    +
    +
    + {{svg "octicon-issue-opened" 14}} + {{$.locale.PrettyNumber .NumOpenIssues}} {{$.locale.Tr "repo.issues.open_title"}} +
    +
    + {{svg "octicon-check" 14}} + {{$.locale.PrettyNumber .NumClosedIssues}} {{$.locale.Tr "repo.issues.closed_title"}} +
    +
    + {{if and $.CanWriteProjects (not $.Repository.IsArchived)}} + {{end}} - - {{svg "octicon-issue-opened" 16 "gt-mr-3"}} - {{$.locale.PrettyNumber .NumOpenIssues}} {{$.locale.Tr "repo.issues.open_title"}} - {{svg "octicon-check" 16 "gt-mr-3"}} - {{$.locale.PrettyNumber .NumClosedIssues}} {{$.locale.Tr "repo.issues.closed_title"}} -
    - {{if and $.CanWriteProjects (not $.Repository.IsArchived)}} - - {{end}} {{if .Description}}
    {{.RenderedContent|Str2html}} diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index a7209e0c217..58dbca2a4bd 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -46,7 +46,7 @@ {{if $.CanWriteProjects}}