diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..6288e4d367 --- /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 4e7789ef92..5d4e13038b 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 6d4698d6a8..7e7a139c9a 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 8642049117..700d45a3c8 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 a7c9ceabd3..3f147c685d 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 9a9c54720b..398fb6eae3 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 daee522c27..5e094f02c1 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 916de6b27d..61f1fd5632 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 0000000000..71ec6dae84 --- /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 804fe87c04..581417df61 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 4e2315ac95..8aeb706182 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 664839273b..f6d9b9d04f 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 da6c987ff8..3a46b90911 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 0f999215d9..c13f223919 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 eb0e186582..2b285ce6ea 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 20ca812eff..bf3bf4c312 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 b654fe2efa..ddab43530e 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 8d0899feac..fb202e3078 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 259ddd6ade..29254b1f07 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 a018bb0553..49143a87e8 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 092ad73f31..3c4d020413 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 5ae5e65d3e..45f33feb08 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 9e351432c4..93d448fca5 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 1f215eb8ad..88e375986c 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 41ca8a4709..2e9b31140a 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 8708d77da0..2f271f211b 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 4d69653e09..7d9d9776da 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 0000000000..14b95898f5 --- /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 0000000000..72033b1208 --- /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 cd6b8d4562..3aa530a1f4 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 4dab468c10..836a2bb25f 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 293333a95b..539eb4b197 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 349c7e3e80..cf8af32fc6 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 282895eaa9..2917741c45 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 c8aebd9051..26b7428016 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 c1f0516d7d..9497dc02e2 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 d801f1025c..db511aeb18 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 b58065aa73..6a4dae66f7 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 0000000000..834f4912f4 --- /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 738c1ecd71..5936451439 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 1633a5a805..1818343f92 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 76beea934e..e808ccf2a8 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 41d834771a..0701862cc2 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 0000000000..69258f749c --- /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 0000000000..0299355b5d --- /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 64eddfa1d5..b2a143c5c6 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 0000000000..34370c2060 --- /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 0000000000..a4fbeabeaa --- /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 0000000000..7a3af6dee2 --- /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 0000000000..bbeb817b82 --- /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 0000000000..53ac646414 --- /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 0000000000..ce5f475b27 --- /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 bdcac41206..a418b3a1c4 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 4b10cd7ad1..060f7bc3d4 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 4f0f637fa5..fa7f66f3ab 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 37361a8b96..be66cc5240 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 fdf540fd65..bab06b3e66 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 56658b45d5..b43a22cd55 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 e1bdea5c82..7593a87c2c 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 0000000000..9bf2025e19 --- /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 5737ef3dc0..54e8d2b8b3 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 4dba64df01..16bb55b685 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 ed58a54eef..19d6d7294d 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 80f149d806..0ce3bbde00 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 3450fa8e72..08a97b7d2d 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 1e53aac9b0..52dded68b7 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 5ab8db2e05..9f087edc72 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 c24fe898b6..4c9a359438 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 c712902ea9..e2797772a8 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 9ec1b4d349..07e349811e 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 3bb202505c..a33e92c821 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 cf719c49f0..ad87bae9b8 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 e51820a520..d85879d1e5 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 534b0b2620..3a06a38c24 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 569d597722..ba840db288 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 5f6d63039a..7261e2c873 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 0a0330b3aa..a1ff65f203 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 c4a8a20d01..508291fa43 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 d49497e19c..c162810797 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 3cd6e81351..4b6fb7446d 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 a43b71cf31..8ff96822c9 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 621816e97d..0346e0e9e9 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 e1c7d5d7fb..d14a049438 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 a500dbdb22..51a2190e8f 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 af9d4c4bc5..801cf9e7b4 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 26eef890b2..a2bd37be0c 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 a0c5a87d0f..aaa8b7fe2d 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 f58f25e4ae..4ed9dbb9aa 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 d456c2fbab..c8ae07a19a 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 27898a1854..7b86b0defd 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 63703d7837..75bbd9a97c 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 5e41636ba3..e46e276ed0 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 52be6a6013..1cd5dcff8b 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 586f83e652..43d95b3ff0 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 f215dd52cd..260a8ba803 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 49a9273771..63bb8b0792 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 e9e86e5d5d..bde9925ab9 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 a7209e0c21..58dbca2a4b 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -46,7 +46,7 @@ {{if $.CanWriteProjects}}