Merge remote-tracking branch 'upstream/main' into limit-repo-size
@@ -9,13 +9,15 @@ parserOptions:
|
||||
ecmaVersion: latest
|
||||
|
||||
plugins:
|
||||
- eslint-plugin-unicorn
|
||||
- "@eslint-community/eslint-plugin-eslint-comments"
|
||||
- eslint-plugin-custom-elements
|
||||
- eslint-plugin-import
|
||||
- eslint-plugin-jquery
|
||||
- eslint-plugin-no-jquery
|
||||
- eslint-plugin-sonarjs
|
||||
- eslint-plugin-custom-elements
|
||||
- eslint-plugin-regexp
|
||||
- eslint-plugin-sonarjs
|
||||
- eslint-plugin-unicorn
|
||||
- eslint-plugin-wc
|
||||
|
||||
env:
|
||||
es2022: true
|
||||
@@ -43,6 +45,15 @@ overrides:
|
||||
import/no-unused-modules: [0]
|
||||
|
||||
rules:
|
||||
"@eslint-community/eslint-comments/disable-enable-pair": [2]
|
||||
"@eslint-community/eslint-comments/no-aggregating-enable": [2]
|
||||
"@eslint-community/eslint-comments/no-duplicate-disable": [2]
|
||||
"@eslint-community/eslint-comments/no-restricted-disable": [0]
|
||||
"@eslint-community/eslint-comments/no-unlimited-disable": [2]
|
||||
"@eslint-community/eslint-comments/no-unused-disable": [2]
|
||||
"@eslint-community/eslint-comments/no-unused-enable": [2]
|
||||
"@eslint-community/eslint-comments/no-use": [0]
|
||||
"@eslint-community/eslint-comments/require-description": [0]
|
||||
accessor-pairs: [2]
|
||||
array-bracket-newline: [0]
|
||||
array-bracket-spacing: [2, never]
|
||||
@@ -717,6 +728,15 @@ rules:
|
||||
use-isnan: [2]
|
||||
valid-typeof: [2, {requireStringLiterals: true}]
|
||||
vars-on-top: [0]
|
||||
wc/attach-shadow-constructor: [2]
|
||||
wc/guard-super-call: [2]
|
||||
wc/no-closed-shadow-root: [2]
|
||||
wc/no-constructor-attributes: [2]
|
||||
wc/no-constructor-params: [2]
|
||||
wc/no-invalid-element-name: [0] # covered by custom-elements/valid-tag-name
|
||||
wc/no-self-class: [2]
|
||||
wc/no-typos: [2]
|
||||
wc/require-listener-teardown: [2]
|
||||
wrap-iife: [2, inside]
|
||||
wrap-regex: [0]
|
||||
yield-star-spacing: [2, after]
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
name: "Cron: Update licenses and gitignores"
|
||||
name: cron-licenses
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# weekly on Monday at 0:07 UTC
|
||||
- cron: "7 0 * * 1"
|
||||
- cron: "7 0 * * 1" # every Monday at 00:07 UTC
|
||||
|
||||
jobs:
|
||||
cron:
|
||||
cron-licenses:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'go-gitea/gitea'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
- name: update licenses and gitignores
|
||||
run: timeout -s ABRT 40m make generate-license generate-gitignore
|
||||
go-version: ">=1.20.1"
|
||||
- run: make generate-license generate-gitignore
|
||||
timeout-minutes: 40
|
||||
- name: push translations to repo
|
||||
uses: appleboy/git-push-action@v0.0.2
|
||||
with:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
name: 'Lock Threads'
|
||||
name: cron-lock
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Run once a day
|
||||
- cron: "0 0 * * *" # every day at 00:00 UTC
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -15,6 +15,7 @@ concurrency:
|
||||
jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'go-gitea/gitea'
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v4
|
||||
with:
|
||||
@@ -1,15 +1,15 @@
|
||||
name: "Cron: Pull translations from Crowdin"
|
||||
name: cron-translations
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "7 0 * * *" # every day at 0:07 UTC
|
||||
- cron: "7 0 * * *" # every day at 00:07 UTC
|
||||
|
||||
jobs:
|
||||
crowdin_pull:
|
||||
crowdin-pull:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'go-gitea/gitea'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
- name: download from crowdin
|
||||
uses: docker://jonasfranz/crowdin
|
||||
env:
|
||||
@@ -30,16 +30,17 @@ jobs:
|
||||
commit_message: "[skip ci] Updated translations via Crowdin"
|
||||
remote: "git@github.com:go-gitea/gitea.git"
|
||||
ssh_key: ${{ secrets.DEPLOY_KEY }}
|
||||
crowdin_push:
|
||||
crowdin-push:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'go-gitea/gitea'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
- name: push translations to crowdin
|
||||
uses: docker://jonasfranz/crowdin
|
||||
env:
|
||||
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
|
||||
PLUGIN_UPLOAD: true
|
||||
PLUGIN_EXPORT_DIR: options/locale/
|
||||
PLUGIN_IGNORE_BRANCH: true
|
||||
PLUGIN_PROJECT_IDENTIFIER: gitea
|
||||
PLUGIN_FILES: |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: "Docs: Publish"
|
||||
name: publish-docs
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -11,12 +11,10 @@ jobs:
|
||||
compliance-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
go-version: ">=1.20.1"
|
||||
- name: build docs
|
||||
run: |
|
||||
cd docs
|
||||
@@ -0,0 +1,22 @@
|
||||
name: compliance-docs
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
compliance-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
- run: make deps-frontend
|
||||
- run: make lint-md
|
||||
@@ -0,0 +1,13 @@
|
||||
name: compliance
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
|
||||
jobs:
|
||||
compliance-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "No build required"
|
||||
@@ -1,142 +1,103 @@
|
||||
name: "Pull: Compliance Tests"
|
||||
name: compliance
|
||||
|
||||
on: [pull_request]
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint_basic:
|
||||
lint-backend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20'
|
||||
go-version: ">=1.20"
|
||||
check-latest: true
|
||||
- name: deps-backend
|
||||
run: make deps-backend deps-tools
|
||||
- name: lint backend
|
||||
run: make lint-backend
|
||||
- run: make deps-backend deps-tools
|
||||
- run: make lint-backend
|
||||
env:
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
lint_windows:
|
||||
lint-go-windows:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20'
|
||||
go-version: ">=1.20"
|
||||
check-latest: true
|
||||
- name: deps-backend
|
||||
run: make deps-backend deps-tools
|
||||
- name: lint-backend-windows
|
||||
run: make lint-go-windows lint-go-vet
|
||||
- run: make deps-backend deps-tools
|
||||
- run: make lint-go-windows lint-go-vet
|
||||
env:
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
GOOS: windows
|
||||
GOARCH: amd64
|
||||
lint_gogit:
|
||||
lint-go-gogit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20'
|
||||
go-version: ">=1.20"
|
||||
check-latest: true
|
||||
- name: deps-backend
|
||||
run: make deps-backend deps-tools
|
||||
- name: lint-backend-gogit
|
||||
run: make lint-backend
|
||||
- run: make deps-backend deps-tools
|
||||
- run: make lint-go
|
||||
env:
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
- name: checks backend
|
||||
run: make --always-make checks-backend # ensure the 'go-licenses' make target runs
|
||||
check_backend:
|
||||
checks-backend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20'
|
||||
go-version: ">=1.20"
|
||||
check-latest: true
|
||||
- name: deps-backend
|
||||
run: make deps-backend deps-tools
|
||||
- name: checks backend
|
||||
run: make --always-make checks-backend # ensure the 'go-licenses' make target runs
|
||||
- run: make deps-backend deps-tools
|
||||
- run: make --always-make checks-backend # ensure the "go-licenses" make target runs
|
||||
frontend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
- name: deps-frontend
|
||||
run: make deps-frontend
|
||||
- name: lint frontend
|
||||
run: make lint-frontend
|
||||
- name: checks frontend
|
||||
run: make checks-frontend
|
||||
- name: test frontend
|
||||
run: make test-frontend
|
||||
- run: make deps-frontend
|
||||
- run: make lint-frontend
|
||||
- run: make checks-frontend
|
||||
backend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20'
|
||||
go-version: ">=1.20"
|
||||
check-latest: true
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
- name: deps-backend
|
||||
run: make deps-backend deps-tools
|
||||
- name: deps-frontend
|
||||
run: make deps-frontend
|
||||
- name: build frontend
|
||||
run: make frontend
|
||||
- name: build-backend-no-gcc
|
||||
run: go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
- run: make deps-backend deps-tools
|
||||
- run: make deps-frontend
|
||||
- run: make frontend
|
||||
- run: go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
|
||||
- name: build-backend-arm64
|
||||
run: make backend # test cross compile
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
GOOS: linux
|
||||
GOARCH: arm64
|
||||
TAGS: bindata gogit
|
||||
- name: build-backend-windows
|
||||
run: go build -o gitea_windows
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
GOOS: windows
|
||||
GOARCH: amd64
|
||||
TAGS: bindata gogit
|
||||
- name: build-backend-386
|
||||
run: go build -o gitea_linux_386 # test if compatible with 32 bit
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
GOOS: linux
|
||||
GOARCH: 386
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
name: "Pull: Compliance testing for documentation"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
compliance-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
- name: install dependencies
|
||||
run: make deps-frontend
|
||||
- name: lint markdown
|
||||
run: make lint-md
|
||||
@@ -0,0 +1,38 @@
|
||||
name: db-tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
|
||||
jobs:
|
||||
test-pgsql:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "No build required"
|
||||
|
||||
test-sqlite:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "No build required"
|
||||
|
||||
test-unit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "No build required"
|
||||
|
||||
test-mysql5:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "No build required"
|
||||
|
||||
test-mysql8:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "No build required"
|
||||
|
||||
test-mssql:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "No build required"
|
||||
@@ -1,14 +1,17 @@
|
||||
name: "Pull: Database Tests"
|
||||
name: db-tests
|
||||
|
||||
on: [pull_request]
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# PostgreSQL Tests
|
||||
db_pgsql_test:
|
||||
test-pgsql:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
pgsql:
|
||||
@@ -33,61 +36,45 @@ jobs:
|
||||
ports:
|
||||
- "9000:9000"
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.0'
|
||||
go-version: ">=1.20.0"
|
||||
- name: Add hosts to /etc/hosts
|
||||
run: echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts
|
||||
- name: install dependencies
|
||||
run: make deps-backend
|
||||
- name: build
|
||||
run: make backend
|
||||
- run: make deps-backend
|
||||
- run: make backend
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata
|
||||
- name: run tests
|
||||
run: timeout -s ABRT 50m make test-pgsql-migration test-pgsql
|
||||
- run: make test-pgsql-migration test-pgsql
|
||||
timeout-minutes: 50
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata gogit
|
||||
RACE_ENABLED: true
|
||||
TEST_TAGS: gogit
|
||||
TEST_LDAP: 1
|
||||
USE_REPO_TEST_DIR: 1
|
||||
|
||||
# SQLite Tests
|
||||
db_sqlite_test:
|
||||
test-sqlite:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.0'
|
||||
- name: install dependencies
|
||||
run: make deps-backend
|
||||
- name: build
|
||||
run: make backend
|
||||
go-version: ">=1.20.0"
|
||||
- run: make deps-backend
|
||||
- run: make backend
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
- name: run tests
|
||||
run: timeout -s ABRT 50m make test-sqlite-migration test-sqlite
|
||||
- run: make test-sqlite-migration test-sqlite
|
||||
timeout-minutes: 50
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
RACE_ENABLED: true
|
||||
TEST_TAGS: gogit sqlite sqlite_unlock_notify
|
||||
USE_REPO_TEST_DIR: 1
|
||||
|
||||
# Unit Tests
|
||||
db_unit_tests:
|
||||
test-unit:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mysql:
|
||||
@@ -112,48 +99,45 @@ jobs:
|
||||
- "993:993"
|
||||
redis:
|
||||
image: redis
|
||||
# Set health checks to wait until redis has started
|
||||
options: >-
|
||||
options: >- # wait until redis has started
|
||||
--health-cmd "redis-cli ping"
|
||||
--health-interval 5s
|
||||
--health-timeout 3s
|
||||
--health-retries 10
|
||||
ports:
|
||||
- 6379:6379
|
||||
minio:
|
||||
image: bitnami/minio:2021.3.17
|
||||
env:
|
||||
MINIO_ACCESS_KEY: 123456
|
||||
MINIO_SECRET_KEY: 12345678
|
||||
ports:
|
||||
- "9000:9000"
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.0'
|
||||
go-version: ">=1.20.0"
|
||||
- name: Add hosts to /etc/hosts
|
||||
run: echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts
|
||||
- name: install dependencies
|
||||
run: make deps-backend
|
||||
- name: build
|
||||
run: make backend
|
||||
- run: make deps-backend
|
||||
- run: make backend
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata
|
||||
- name: unit tests
|
||||
- name: unit-tests
|
||||
run: make unit-test-coverage test-check
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
RACE_ENABLED: true
|
||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
||||
- name: unit tests (gogit)
|
||||
- name: unit-tests-gogit
|
||||
run: make unit-test-coverage test-check
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata gogit
|
||||
RACE_ENABLED: true
|
||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
||||
|
||||
# MySQL Tests
|
||||
db_mysql_test:
|
||||
test-mysql5:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mysql:
|
||||
@@ -177,33 +161,25 @@ jobs:
|
||||
- "587:587"
|
||||
- "993:993"
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.0'
|
||||
go-version: ">=1.20.0"
|
||||
- name: Add hosts to /etc/hosts
|
||||
run: echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts
|
||||
- name: install dependencies
|
||||
run: make deps-backend
|
||||
- name: build
|
||||
run: make backend
|
||||
- run: make deps-backend
|
||||
- run: make backend
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata
|
||||
- name: run tests
|
||||
run: make test-mysql-migration integration-test-coverage
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
RACE_ENABLED: true
|
||||
USE_REPO_TEST_DIR: 1
|
||||
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
|
||||
|
||||
# MySQL8 Tests
|
||||
db_mysql8_test:
|
||||
test-mysql8:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mysql8:
|
||||
@@ -214,31 +190,23 @@ jobs:
|
||||
ports:
|
||||
- "3306:3306"
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.0'
|
||||
go-version: ">=1.20.0"
|
||||
- name: Add hosts to /etc/hosts
|
||||
run: echo "127.0.0.1 mysql8" | sudo tee -a /etc/hosts
|
||||
- name: install dependencies
|
||||
run: make deps-backend
|
||||
- name: build
|
||||
run: make backend
|
||||
- run: make deps-backend
|
||||
- run: make backend
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata
|
||||
- name: run tests
|
||||
run: timeout -s ABRT 50m make test-mysql8-migration test-mysql8
|
||||
- run: make test-mysql8-migration test-mysql8
|
||||
timeout-minutes: 50
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
USE_REPO_TEST_DIR: 1
|
||||
|
||||
# MSSQL Tests
|
||||
db_mssql_test:
|
||||
test-mssql:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mssql:
|
||||
@@ -250,25 +218,18 @@ jobs:
|
||||
ports:
|
||||
- "1433:1433"
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.0'
|
||||
go-version: ">=1.20.0"
|
||||
- name: Add hosts to /etc/hosts
|
||||
run: echo "127.0.0.1 mssql" | sudo tee -a /etc/hosts
|
||||
- name: install dependencies
|
||||
run: make deps-backend
|
||||
- name: build
|
||||
run: make backend
|
||||
- run: make deps-backend
|
||||
- run: make backend
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata
|
||||
- name: run tests
|
||||
run: timeout -s ABRT 50m make test-mssql-migration test-mssql
|
||||
- run: make test-mssql-migration test-mssql
|
||||
timeout-minutes: 50
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
USE_REPO_TEST_DIR: 1
|
||||
@@ -0,0 +1,13 @@
|
||||
name: docker-dryrun
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
|
||||
jobs:
|
||||
docker-dryrun:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "No build required"
|
||||
@@ -0,0 +1,21 @@
|
||||
name: docker-dryrun
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
docker-dryrun:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: docker/setup-buildx-action@v2
|
||||
- uses: docker/build-push-action@v4
|
||||
with:
|
||||
push: false
|
||||
tags: gitea/gitea:linux-amd64
|
||||
@@ -1,23 +0,0 @@
|
||||
name: "Pull: Docker Dry Run"
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
docker_dryrun:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
push: false
|
||||
tags: gitea/gitea:linux-amd64
|
||||
build-args: |
|
||||
GOPROXY=https://goproxy.io
|
||||
@@ -0,0 +1,13 @@
|
||||
name: e2e-tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
|
||||
jobs:
|
||||
test-e2e:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "No build required"
|
||||
@@ -0,0 +1,30 @@
|
||||
name: e2e-tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test-e2e:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- 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 frontend deps-backend
|
||||
- run: npx playwright install --with-deps
|
||||
- run: make test-e2e-sqlite
|
||||
timeout-minutes: 40
|
||||
env:
|
||||
USE_REPO_TEST_DIR: 1
|
||||
@@ -1,33 +0,0 @@
|
||||
name: "Pull: E2E Tests"
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
e2e_tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20'
|
||||
check-latest: true
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
- name: build
|
||||
run: make deps-frontend frontend deps-backend
|
||||
- name: Install playwright browsers
|
||||
run: npx playwright install --with-deps
|
||||
- name: run tests
|
||||
run: timeout -s ABRT 40m make test-e2e-sqlite
|
||||
env:
|
||||
GOPROXY: https://goproxy.io
|
||||
GOSUMDB: sum.golang.org
|
||||
USE_REPO_TEST_DIR: 1
|
||||
@@ -5,7 +5,7 @@ ignoreFiles:
|
||||
- "**/*.go"
|
||||
|
||||
overrides:
|
||||
- files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console/*"]
|
||||
- files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console.css"]
|
||||
rules:
|
||||
scale-unlimited/declaration-strict-value: null
|
||||
- files: ["**/chroma/*", "**/codemirror/*"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Build stage
|
||||
FROM docker.io/library/golang:1.20-alpine3.17 AS build-env
|
||||
FROM docker.io/library/golang:1.20-alpine3.18 AS build-env
|
||||
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY ${GOPROXY:-direct}
|
||||
@@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
|
||||
# Begin env-to-ini build
|
||||
RUN go build contrib/environment-to-ini/environment-to-ini.go
|
||||
|
||||
FROM docker.io/library/alpine:3.17
|
||||
FROM docker.io/library/alpine:3.18
|
||||
LABEL maintainer="maintainers@gitea.io"
|
||||
|
||||
EXPOSE 22 3000
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Build stage
|
||||
FROM docker.io/library/golang:1.20-alpine3.17 AS build-env
|
||||
FROM docker.io/library/golang:1.20-alpine3.18 AS build-env
|
||||
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY ${GOPROXY:-direct}
|
||||
@@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
|
||||
# Begin env-to-ini build
|
||||
RUN go build contrib/environment-to-ini/environment-to-ini.go
|
||||
|
||||
FROM docker.io/library/alpine:3.17
|
||||
FROM docker.io/library/alpine:3.18
|
||||
LABEL maintainer="maintainers@gitea.io"
|
||||
|
||||
EXPOSE 2222 3000
|
||||
|
||||
@@ -50,3 +50,4 @@ Eddie Yang <576951401@qq.com> (@yp05327)
|
||||
Dong Ge <gedong_1994@163.com> (@sillyguodong)
|
||||
Xinyi Gong <hestergong@gmail.com> (@HesterG)
|
||||
wxiaoguang <wxiaoguang@gmail.com> (@wxiaoguang)
|
||||
Gary Moon <gary@garymoon.net> (@garymoon)
|
||||
|
||||
@@ -394,7 +394,7 @@ lint-go:
|
||||
lint-go-fix:
|
||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix
|
||||
|
||||
# workaround step for the lint-backend-windows CI task because 'go run' can not
|
||||
# workaround step for the lint-go-windows CI task because 'go run' can not
|
||||
# have distinct GOOS/GOARCH for its build and run steps
|
||||
.PHONY: lint-go-windows
|
||||
lint-go-windows:
|
||||
@@ -409,7 +409,7 @@ lint-go-vet:
|
||||
|
||||
.PHONY: lint-editorconfig
|
||||
lint-editorconfig:
|
||||
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates
|
||||
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .github/workflows
|
||||
|
||||
.PHONY: watch
|
||||
watch:
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
"code.gitea.io/gitea/models/migrations"
|
||||
@@ -32,7 +33,7 @@ var CmdMigrateStorage = cli.Command{
|
||||
cli.StringFlag{
|
||||
Name: "type, t",
|
||||
Value: "",
|
||||
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages'",
|
||||
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log'",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "storage, s",
|
||||
@@ -134,6 +135,22 @@ func migratePackages(ctx context.Context, dstStorage storage.ObjectStorage) erro
|
||||
})
|
||||
}
|
||||
|
||||
func migrateActionsLog(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
||||
return db.Iterate(ctx, nil, func(ctx context.Context, task *actions_model.ActionTask) error {
|
||||
if task.LogExpired {
|
||||
// the log has been cleared
|
||||
return nil
|
||||
}
|
||||
if !task.LogInStorage {
|
||||
// running tasks store logs in DBFS
|
||||
return nil
|
||||
}
|
||||
p := task.LogFilename
|
||||
_, err := storage.Copy(dstStorage, p, storage.Actions, p)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func runMigrateStorage(ctx *cli.Context) error {
|
||||
stdCtx, cancel := installSignals()
|
||||
defer cancel()
|
||||
@@ -201,6 +218,7 @@ func runMigrateStorage(ctx *cli.Context) error {
|
||||
"repo-avatars": migrateRepoAvatars,
|
||||
"repo-archivers": migrateRepoArchivers,
|
||||
"packages": migratePackages,
|
||||
"actions-log": migrateActionsLog,
|
||||
}
|
||||
|
||||
tp := strings.ToLower(ctx.String("type"))
|
||||
|
||||
@@ -52,7 +52,7 @@ After=network.target
|
||||
# Uncomment the next line if you have repos with lots of files and get a HTTP 500 error because of that
|
||||
# LimitNOFILE=524288:524288
|
||||
RestartSec=2s
|
||||
Type=simple
|
||||
Type=notify
|
||||
User=git
|
||||
Group=git
|
||||
WorkingDirectory=/var/lib/gitea/
|
||||
@@ -62,6 +62,7 @@ WorkingDirectory=/var/lib/gitea/
|
||||
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
|
||||
Restart=always
|
||||
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
|
||||
WatchdogSec=30s
|
||||
# If you install Git to directory prefix other than default PATH (which happens
|
||||
# for example if you install other versions of Git side-to-side with
|
||||
# distribution version), uncomment below line and add that prefix to PATH
|
||||
|
||||
@@ -940,6 +940,9 @@ ROUTER = console
|
||||
;; Force ssh:// clone url instead of scp-style uri when default SSH port is used
|
||||
;USE_COMPAT_SSH_URI = false
|
||||
;;
|
||||
;; Value for the "go get" request returns the repository url as https or ssh, default is https
|
||||
;GO_GET_CLONE_URL_PROTOCOL = https
|
||||
;;
|
||||
;; Close issues as long as a commit on any branch marks it as fixed
|
||||
;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions.
|
||||
;DISABLED_REPO_UNITS =
|
||||
@@ -1430,7 +1433,7 @@ ROUTER = console
|
||||
;; Batch size to send for batched queues
|
||||
;BATCH_LENGTH = 20
|
||||
;;
|
||||
;; Connection string for redis queues this will store the redis connection string.
|
||||
;; Connection string for redis queues this will store the redis or redis-cluster connection string.
|
||||
;; When `TYPE` is `persistable-channel`, this provides a directory for the underlying leveldb
|
||||
;; or additional options of the form `leveldb://path/to/db?option=value&....`, and will override `DATADIR`.
|
||||
;CONN_STR = "redis://127.0.0.1:6379/0"
|
||||
@@ -1702,8 +1705,9 @@ ROUTER = console
|
||||
;; For "memory" only, GC interval in seconds, default is 60
|
||||
;INTERVAL = 60
|
||||
;;
|
||||
;; For "redis" and "memcache", connection host address
|
||||
;; For "redis", "redis-cluster" and "memcache", connection host address
|
||||
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
|
||||
;; redis-cluster: `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
|
||||
;; memcache: `127.0.0.1:11211`
|
||||
;; twoqueue: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000`
|
||||
;HOST =
|
||||
@@ -1735,7 +1739,7 @@ ROUTER = console
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; Either "memory", "file", "redis", "db", "mysql", "couchbase", "memcache" or "postgres"
|
||||
;; Either "memory", "file", "redis", "redis-cluster", "db", "mysql", "couchbase", "memcache" or "postgres"
|
||||
;; Default is "memory". "db" will reuse the configuration in [database]
|
||||
;PROVIDER = memory
|
||||
;;
|
||||
@@ -1743,6 +1747,7 @@ ROUTER = console
|
||||
;; memory: doesn't have any config yet
|
||||
;; file: session file path, e.g. `data/sessions`
|
||||
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
|
||||
;; redis-cluster: `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
|
||||
;; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table`
|
||||
;PROVIDER_CONFIG = data/sessions ; Relative paths will be made absolute against _`AppWorkPath`_.
|
||||
;;
|
||||
@@ -1778,16 +1783,19 @@ ROUTER = console
|
||||
;; Max Width and Height of uploaded avatars.
|
||||
;; This is to limit the amount of RAM used when resizing the image.
|
||||
;AVATAR_MAX_WIDTH = 4096
|
||||
;AVATAR_MAX_HEIGHT = 3072
|
||||
;AVATAR_MAX_HEIGHT = 4096
|
||||
;;
|
||||
;; The multiplication factor for rendered avatar images.
|
||||
;; Larger values result in finer rendering on HiDPI devices.
|
||||
;AVATAR_RENDERED_SIZE_FACTOR = 3
|
||||
;AVATAR_RENDERED_SIZE_FACTOR = 2
|
||||
;;
|
||||
;; Maximum allowed file size for uploaded avatars.
|
||||
;; This is to limit the amount of RAM used when resizing the image.
|
||||
;AVATAR_MAX_FILE_SIZE = 1048576
|
||||
;;
|
||||
;; If the uploaded file is not larger than this byte size, the image will be used as is, without resizing/converting.
|
||||
;AVATAR_MAX_ORIGIN_SIZE = 262144
|
||||
;;
|
||||
;; Chinese users can choose "duoshuo"
|
||||
;; or a custom avatar source, like: http://cn.gravatar.com/avatar/
|
||||
;GRAVATAR_SOURCE = gravatar
|
||||
@@ -2373,7 +2381,7 @@ ROUTER = console
|
||||
;QUEUE_LENGTH = 1000
|
||||
;;
|
||||
;; Task queue connection string, available only when `QUEUE_TYPE` is `redis`.
|
||||
;; If there is a password of redis, use `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`.
|
||||
;; If there is a password of redis, use `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for `redis-clsuter`.
|
||||
;QUEUE_CONN_STR = "redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s"
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -2447,6 +2455,8 @@ ROUTER = console
|
||||
;LIMIT_TOTAL_OWNER_COUNT = -1
|
||||
;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
;LIMIT_TOTAL_OWNER_SIZE = -1
|
||||
;; Maximum size of an Alpine upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
;LIMIT_SIZE_ALPINE = -1
|
||||
;; Maximum size of a Cargo upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
;LIMIT_SIZE_CARGO = -1
|
||||
;; Maximum size of a Chef upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
@@ -2463,6 +2473,8 @@ ROUTER = console
|
||||
;LIMIT_SIZE_DEBIAN = -1
|
||||
;; Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
;LIMIT_SIZE_GENERIC = -1
|
||||
;; Maximum size of a Go upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
;LIMIT_SIZE_GO = -1
|
||||
;; Maximum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
;LIMIT_SIZE_HELM = -1
|
||||
;; Maximum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
|
||||
@@ -95,6 +95,8 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build
|
||||
HTTP protocol.
|
||||
- `USE_COMPAT_SSH_URI`: **false**: Force ssh:// clone url instead of scp-style uri when
|
||||
default SSH port is used.
|
||||
- `GO_GET_CLONE_URL_PROTOCOL`: **https**: Value for the "go get" request returns the repository url as https or ssh
|
||||
default is https.
|
||||
- `ACCESS_CONTROL_ALLOW_ORIGIN`: **\<empty\>**: Value for Access-Control-Allow-Origin header,
|
||||
default is not to present. **WARNING**: This maybe harmful to you website if you do not
|
||||
give it a right value.
|
||||
@@ -485,7 +487,7 @@ Configuration at `[queue]` will set defaults for queues with overrides for indiv
|
||||
- `DATADIR`: **queues/common**: Base DataDir for storing level queues. `DATADIR` for individual queues can be set in `queue.name` sections. Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
|
||||
- `LENGTH`: **100**: Maximal queue size before channel queues block
|
||||
- `BATCH_LENGTH`: **20**: Batch data before passing to the handler
|
||||
- `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. Options can be set using query params. Similarly, LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**, and will override `DATADIR`
|
||||
- `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. For `redis-cluster` use `redis+cluster://127.0.0.1:6379/0`. Options can be set using query params. Similarly, LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**, and will override `DATADIR`
|
||||
- `QUEUE_NAME`: **_queue**: The suffix for default redis and disk queue name. Individual queues will default to **`name`**`QUEUE_NAME` but can be overridden in the specific `queue.name` section.
|
||||
- `SET_NAME`: **_unique**: The suffix that will be added to the default redis and disk queue `set` name for unique queues. Individual queues will default to **`name`**`QUEUE_NAME`_`SET_NAME`_ but can be overridden in the specific `queue.name` section.
|
||||
- `MAX_WORKERS`: **10**: Maximum number of worker go-routines for the queue.
|
||||
@@ -757,10 +759,11 @@ and
|
||||
## Cache (`cache`)
|
||||
|
||||
- `ENABLED`: **true**: Enable the cache.
|
||||
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.)
|
||||
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `redis-cluster`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.)
|
||||
- `INTERVAL`: **60**: Garbage Collection interval (sec), for memory and twoqueue cache only.
|
||||
- `HOST`: **\<empty\>**: Connection string for `redis` and `memcache`. For `twoqueue` sets configuration for the queue.
|
||||
- `HOST`: **\<empty\>**: Connection string for `redis`, `redis-cluster` and `memcache`. For `twoqueue` sets configuration for the queue.
|
||||
- Redis: `redis://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
|
||||
- Redis-cluster `redis+cluster://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
|
||||
- Memcache: `127.0.0.1:9090;127.0.0.1:9091`
|
||||
- TwoQueue LRU cache: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000` representing the maximum number of objects stored in the cache.
|
||||
- `ITEM_TTL`: **16h**: Time to keep items in cache if not used, Setting it to -1 disables caching.
|
||||
@@ -773,7 +776,7 @@ and
|
||||
|
||||
## Session (`session`)
|
||||
|
||||
- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, db, mysql, couchbase, memcache, postgres\]. Setting `db` will reuse the configuration in `[database]`
|
||||
- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, redis-cluster, db, mysql, couchbase, memcache, postgres\]. Setting `db` will reuse the configuration in `[database]`
|
||||
- `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for db, empty (database config will be used); for others, the connection string. Relative paths will be made absolute against _`AppWorkPath`_.
|
||||
- `COOKIE_SECURE`: **false**: Enable this to force using HTTPS for all session access.
|
||||
- `COOKIE_NAME`: **i\_like\_gitea**: The name of the cookie used for the session ID.
|
||||
@@ -793,9 +796,10 @@ and
|
||||
- `AVATAR_STORAGE_TYPE`: **default**: Storage type defined in `[storage.xxx]`. Default is `default` which will read `[storage]` if no section `[storage]` will be a type `local`.
|
||||
- `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store user avatar image files.
|
||||
- `AVATAR_MAX_WIDTH`: **4096**: Maximum avatar image width in pixels.
|
||||
- `AVATAR_MAX_HEIGHT`: **3072**: Maximum avatar image height in pixels.
|
||||
- `AVATAR_MAX_FILE_SIZE`: **1048576** (1Mb): Maximum avatar image file size in bytes.
|
||||
- `AVATAR_RENDERED_SIZE_FACTOR`: **3**: The multiplication factor for rendered avatar images. Larger values result in finer rendering on HiDPI devices.
|
||||
- `AVATAR_MAX_HEIGHT`: **4096**: Maximum avatar image height in pixels.
|
||||
- `AVATAR_MAX_FILE_SIZE`: **1048576** (1MiB): Maximum avatar image file size in bytes.
|
||||
- `AVATAR_MAX_ORIGIN_SIZE`: **262144** (256KiB): If the uploaded file is not larger than this byte size, the image will be used as is, without resizing/converting.
|
||||
- `AVATAR_RENDERED_SIZE_FACTOR`: **2**: The multiplication factor for rendered avatar images. Larger values result in finer rendering on HiDPI devices.
|
||||
|
||||
- `REPOSITORY_AVATAR_STORAGE_TYPE`: **default**: Storage type defined in `[storage.xxx]`. Default is `default` which will read `[storage]` if no section `[storage]` will be a type `local`.
|
||||
- `REPOSITORY_AVATAR_UPLOAD_PATH`: **data/repo-avatars**: Path to store repository avatar image files.
|
||||
@@ -1019,7 +1023,7 @@ Default templates for project boards:
|
||||
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
||||
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
|
||||
- `SCHEDULE`: **@every 168h**: Cron syntax to set how often to check.
|
||||
- `OLDER_THAN`: **@every 8760h**: any action older than this expression will be deleted from database, suggest using `8760h` (1 year) because that's the max length of heatmap.
|
||||
- `OLDER_THAN`: **8760h**: any action older than this expression will be deleted from database, suggest using `8760h` (1 year) because that's the max length of heatmap.
|
||||
|
||||
#### Cron - Check for new Gitea versions (`cron.update_checker`)
|
||||
|
||||
@@ -1035,7 +1039,7 @@ Default templates for project boards:
|
||||
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
||||
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
|
||||
- `SCHEDULE`: **@every 168h**: Cron syntax to set how often to check.
|
||||
- `OLDER_THAN`: **@every 8760h**: any system notice older than this expression will be deleted from database.
|
||||
- `OLDER_THAN`: **8760h**: any system notice older than this expression will be deleted from database.
|
||||
|
||||
#### Cron - Garbage collect LFS pointers in repositories (`cron.gc_lfs`)
|
||||
|
||||
@@ -1184,7 +1188,7 @@ Task queue configuration has been moved to `queue.task`. However, the below conf
|
||||
|
||||
- `QUEUE_TYPE`: **channel**: Task queue type, could be `channel` or `redis`.
|
||||
- `QUEUE_LENGTH`: **1000**: Task queue length, available only when `QUEUE_TYPE` is `channel`.
|
||||
- `QUEUE_CONN_STR`: **redis://127.0.0.1:6379/0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If redis needs a password, use `redis://123@127.0.0.1:6379/0`.
|
||||
- `QUEUE_CONN_STR`: **redis://127.0.0.1:6379/0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If redis needs a password, use `redis://123@127.0.0.1:6379/0` or `redis+cluster://123@127.0.0.1:6379/0`.
|
||||
|
||||
## Migrations (`migrations`)
|
||||
|
||||
@@ -1214,6 +1218,7 @@ Task queue configuration has been moved to `queue.task`. However, the below conf
|
||||
- `CHUNKED_UPLOAD_PATH`: **tmp/package-upload**: Path for chunked uploads. Defaults to `APP_DATA_PATH` + `tmp/package-upload`
|
||||
- `LIMIT_TOTAL_OWNER_COUNT`: **-1**: Maximum count of package versions a single owner can have (`-1` means no limits)
|
||||
- `LIMIT_TOTAL_OWNER_SIZE`: **-1**: Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
- `LIMIT_SIZE_ALPINE`: **-1**: Maximum size of an Alpine upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
- `LIMIT_SIZE_CARGO`: **-1**: Maximum size of a Cargo upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
- `LIMIT_SIZE_CHEF`: **-1**: Maximum size of a Chef upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
- `LIMIT_SIZE_COMPOSER`: **-1**: Maximum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
@@ -1222,6 +1227,7 @@ Task queue configuration has been moved to `queue.task`. However, the below conf
|
||||
- `LIMIT_SIZE_CONTAINER`: **-1**: Maximum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
- `LIMIT_SIZE_DEBIAN`: **-1**: Maximum size of a Debian upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
- `LIMIT_SIZE_GENERIC`: **-1**: Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
- `LIMIT_SIZE_GO`: **-1**: Maximum size of a Go upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
- `LIMIT_SIZE_HELM`: **-1**: Maximum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
- `LIMIT_SIZE_MAVEN`: **-1**: Maximum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
- `LIMIT_SIZE_NPM`: **-1**: Maximum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||
|
||||
@@ -214,8 +214,8 @@ menu:
|
||||
- `AVATAR_STORAGE_TYPE`: **local**: 头像存储类型,可以为 `local` 或 `minio`,分别支持本地文件系统和 minio 兼容的API。
|
||||
- `AVATAR_UPLOAD_PATH`: **data/avatars**: 存储头像的文件系统路径。
|
||||
- `AVATAR_MAX_WIDTH`: **4096**: 头像最大宽度,单位像素。
|
||||
- `AVATAR_MAX_HEIGHT`: **3072**: 头像最大高度,单位像素。
|
||||
- `AVATAR_MAX_FILE_SIZE`: **1048576** (1Mb): 头像最大大小。
|
||||
- `AVATAR_MAX_HEIGHT`: **4096**: 头像最大高度,单位像素。
|
||||
- `AVATAR_MAX_FILE_SIZE`: **1048576** (1MiB): 头像最大大小。
|
||||
|
||||
- `REPOSITORY_AVATAR_STORAGE_TYPE`: **local**: 仓库头像存储类型,可以为 `local` 或 `minio`,分别支持本地文件系统和 minio 兼容的API。
|
||||
- `REPOSITORY_AVATAR_UPLOAD_PATH`: **data/repo-avatars**: 存储仓库头像的路径。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
date: "2019-02-14T11:51:04+08:00"
|
||||
title: "横向对比 Gitea 与其它 Git 托管工具"
|
||||
title: "对比 Gitea 与其它 Git 托管工具"
|
||||
slug: "comparison"
|
||||
weight: 5
|
||||
toc: false
|
||||
@@ -15,7 +15,7 @@ menu:
|
||||
identifier: "comparison"
|
||||
---
|
||||
|
||||
# 横向对比 Gitea 与其它 Git 托管工具
|
||||
# 对比 Gitea 与其它 Git 托管工具
|
||||
|
||||
这里列出了 Gitea 与其它一些 Git 托管工具之间的异同,以便确认 Gitea 是否能够满足您的需求。
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ git --version
|
||||
Create a user to run Gitea (e.g. `git`)
|
||||
|
||||
```sh
|
||||
# On Ubuntu/Debian:
|
||||
adduser \
|
||||
--system \
|
||||
--shell /bin/bash \
|
||||
@@ -88,6 +89,17 @@ adduser \
|
||||
--disabled-password \
|
||||
--home /home/git \
|
||||
git
|
||||
|
||||
# On Fedora/RHEL/CentOS:
|
||||
groupadd --system git
|
||||
adduser \
|
||||
--system \
|
||||
--shell /bin/bash \
|
||||
--comment 'Git Version Control' \
|
||||
--gid git \
|
||||
--home-dir /home/git \
|
||||
--create-home \
|
||||
git
|
||||
```
|
||||
|
||||
### Create required directory structure
|
||||
|
||||
@@ -74,6 +74,7 @@ git --version
|
||||
创建用户(推荐使用名称 `git`)
|
||||
|
||||
```sh
|
||||
# On Ubuntu/Debian:
|
||||
adduser \
|
||||
--system \
|
||||
--shell /bin/bash \
|
||||
@@ -82,6 +83,17 @@ adduser \
|
||||
--disabled-password \
|
||||
--home /home/git \
|
||||
git
|
||||
|
||||
# On Fedora/RHEL/CentOS:
|
||||
groupadd --system git
|
||||
adduser \
|
||||
--system \
|
||||
--shell /bin/bash \
|
||||
--comment 'Git Version Control' \
|
||||
--gid git \
|
||||
--home-dir /home/git \
|
||||
--create-home \
|
||||
git
|
||||
```
|
||||
|
||||
### 创建工作路径
|
||||
|
||||
@@ -85,7 +85,7 @@ And you can see the new runner in the management page:
|
||||
|
||||

|
||||
|
||||
You can find more information by visiting [Act runner]({{< relref "doc/actions/act-runner.en-us.md" >}}).
|
||||
You can find more information by visiting [Act runner]({{< relref "doc/usage/actions/act-runner.en-us.md" >}}).
|
||||
|
||||
### Use Actions
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
date: "2023-03-25T00:00:00+00:00"
|
||||
title: "Alpine Packages Repository"
|
||||
slug: "packages/alpine"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "Alpine"
|
||||
weight: 4
|
||||
identifier: "alpine"
|
||||
---
|
||||
|
||||
# Alpine Packages Repository
|
||||
|
||||
Publish [Alpine](https://pkgs.alpinelinux.org/) packages for your user or organization.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the Alpine registry, you need to use a HTTP client like `curl` to upload and a package manager like `apk` to consume packages.
|
||||
|
||||
The following examples use `apk`.
|
||||
|
||||
## Configuring the package registry
|
||||
|
||||
To register the Alpine registry add the url to the list of known apk sources (`/etc/apk/repositories`):
|
||||
|
||||
```
|
||||
https://gitea.example.com/api/packages/{owner}/alpine/<branch>/<repository>
|
||||
```
|
||||
|
||||
| Placeholder | Description |
|
||||
| ------------ | ----------- |
|
||||
| `owner` | The owner of the packages. |
|
||||
| `branch` | The branch to use. |
|
||||
| `repository` | The repository to use. |
|
||||
|
||||
If the registry is private, provide credentials in the url. You can use a password or a [personal access token]({{< relref "doc/development/api-usage.en-us.md#authentication" >}}):
|
||||
|
||||
```
|
||||
https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/alpine/<branch>/<repository>
|
||||
```
|
||||
|
||||
The Alpine registry files are signed with a RSA key which must be known to apk. Download the public key and store it in `/etc/apk/keys/`:
|
||||
|
||||
```shell
|
||||
curl -JO https://gitea.example.com/api/packages/{owner}/alpine/key
|
||||
```
|
||||
|
||||
Afterwards update the local package index:
|
||||
|
||||
```shell
|
||||
apk update
|
||||
```
|
||||
|
||||
## Publish a package
|
||||
|
||||
To publish an Alpine package (`*.apk`), perform a HTTP `PUT` operation with the package content in the request body.
|
||||
|
||||
```
|
||||
PUT https://gitea.example.com/api/packages/{owner}/alpine/{branch}/{repository}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------ | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
| `branch` | The branch may match the release version of the OS, ex: `v3.17`. |
|
||||
| `repository` | The repository can be used [to group packages](https://wiki.alpinelinux.org/wiki/Repositories) or just `main` or similar. |
|
||||
|
||||
Example request using HTTP Basic authentication:
|
||||
|
||||
```shell
|
||||
curl --user your_username:your_password_or_token \
|
||||
--upload-file path/to/file.apk \
|
||||
https://gitea.example.com/api/packages/testuser/alpine/v3.17/main
|
||||
```
|
||||
|
||||
If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/development/api-usage.en-us.md#authentication" >}}) instead of the password.
|
||||
You cannot publish a file with the same name twice to a package. You must delete the existing package file first.
|
||||
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
| `201 Created` | The package has been published. |
|
||||
| `400 Bad Request` | The package name, version, branch, repository or architecture are invalid. |
|
||||
| `409 Conflict` | A package file with the same combination of parameters exist already in the package. |
|
||||
|
||||
## Delete a package
|
||||
|
||||
To delete an Alpine package perform a HTTP `DELETE` operation. This will delete the package version too if there is no file left.
|
||||
|
||||
```
|
||||
DELETE https://gitea.example.com/api/packages/{owner}/alpine/{branch}/{repository}/{architecture}/{filename}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| -------------- | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
| `branch` | The branch to use. |
|
||||
| `repository` | The repository to use. |
|
||||
| `architecture` | The package architecture. |
|
||||
| `filename` | The file to delete.
|
||||
|
||||
Example request using HTTP Basic authentication:
|
||||
|
||||
```shell
|
||||
curl --user your_username:your_token_or_password -X DELETE \
|
||||
https://gitea.example.com/api/packages/testuser/alpine/v3.17/main/test-package-1.0.0.apk
|
||||
```
|
||||
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
| `204 No Content` | Success |
|
||||
| `404 Not Found` | The package or file was not found. |
|
||||
|
||||
## Install a package
|
||||
|
||||
To install a package from the Alpine registry, execute the following commands:
|
||||
|
||||
```shell
|
||||
# use latest version
|
||||
apk add {package_name}
|
||||
# use specific version
|
||||
apk add {package_name}={package_version}
|
||||
```
|
||||
@@ -83,7 +83,7 @@ curl --user your_username:your_password_or_token \
|
||||
If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/development/api-usage.en-us.md#authentication" >}}) instead of the password.
|
||||
You cannot publish a file with the same name twice to a package. You must delete the existing package version first.
|
||||
|
||||
The server reponds with the following HTTP Status codes.
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
@@ -115,7 +115,7 @@ curl --user your_username:your_token_or_password -X DELETE \
|
||||
https://gitea.example.com/api/packages/testuser/debian/pools/bionic/main/test-package/1.0.0/amd64
|
||||
```
|
||||
|
||||
The server reponds with the following HTTP Status codes.
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
|
||||
@@ -51,7 +51,7 @@ curl --user your_username:your_password_or_token \
|
||||
|
||||
If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/development/api-usage.en-us.md#authentication" >}}) instead of the password.
|
||||
|
||||
The server reponds with the following HTTP Status codes.
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
@@ -83,7 +83,7 @@ curl --user your_username:your_token_or_password \
|
||||
https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin
|
||||
```
|
||||
|
||||
The server reponds with the following HTTP Status codes.
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
@@ -111,7 +111,7 @@ curl --user your_username:your_token_or_password -X DELETE \
|
||||
https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0
|
||||
```
|
||||
|
||||
The server reponds with the following HTTP Status codes.
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
@@ -140,7 +140,7 @@ curl --user your_username:your_token_or_password -X DELETE \
|
||||
https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin
|
||||
```
|
||||
|
||||
The server reponds with the following HTTP Status codes.
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
date: "2023-05-10T00:00:00+00:00"
|
||||
title: "Go Packages Repository"
|
||||
slug: "go"
|
||||
weight: 45
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "Go"
|
||||
weight: 45
|
||||
identifier: "go"
|
||||
---
|
||||
|
||||
# Go Packages Repository
|
||||
|
||||
Publish Go packages for your user or organization.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Publish a package
|
||||
|
||||
To publish a Go package perform a HTTP `PUT` operation with the package content in the request body.
|
||||
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
|
||||
The package must follow the [documented structure](https://go.dev/ref/mod#zip-files).
|
||||
|
||||
```
|
||||
PUT https://gitea.example.com/api/packages/{owner}/go/upload
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| --------- | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
|
||||
To authenticate to the package registry, you need to provide [custom HTTP headers or use HTTP Basic authentication]({{< relref "doc/development/api-usage.en-us.md#authentication" >}}):
|
||||
|
||||
```shell
|
||||
curl --user your_username:your_password_or_token \
|
||||
--upload-file path/to/file.zip \
|
||||
https://gitea.example.com/api/packages/testuser/go/upload
|
||||
```
|
||||
|
||||
If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/development/api-usage.en-us.md#authentication" >}}) instead of the password.
|
||||
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
| `201 Created` | The package has been published. |
|
||||
| `400 Bad Request` | The package is invalid. |
|
||||
| `409 Conflict` | A package with the same name exist already. |
|
||||
|
||||
## Install a package
|
||||
|
||||
To install a Go package instruct Go to use the package registry as proxy:
|
||||
|
||||
```shell
|
||||
# use latest version
|
||||
GOPROXY=https://gitea.example.com/api/packages/{owner}/go go install {package_name}
|
||||
# or
|
||||
GOPROXY=https://gitea.example.com/api/packages/{owner}/go go install {package_name}@latest
|
||||
# use specific version
|
||||
GOPROXY=https://gitea.example.com/api/packages/{owner}/go go install {package_name}@{package_version}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------------- | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
| `package_name` | The package name. |
|
||||
| `package_version` | The package version. |
|
||||
|
||||
If the owner of the packages is private you need to [provide credentials](https://go.dev/ref/mod#private-module-proxy-auth).
|
||||
|
||||
More information about the `GOPROXY` environment variable and how to protect against data leaks can be found in [the documentation](https://go.dev/ref/mod#private-modules).
|
||||
@@ -27,6 +27,7 @@ The following package managers are currently supported:
|
||||
|
||||
| Name | Language | Package client |
|
||||
| ---- | -------- | -------------- |
|
||||
| [Alpine]({{< relref "doc/usage/packages/alpine.en-us.md" >}}) | - | `apk` |
|
||||
| [Cargo]({{< relref "doc/usage/packages/cargo.en-us.md" >}}) | Rust | `cargo` |
|
||||
| [Chef]({{< relref "doc/usage/packages/chef.en-us.md" >}}) | - | `knife` |
|
||||
| [Composer]({{< relref "doc/usage/packages/composer.en-us.md" >}}) | PHP | `composer` |
|
||||
@@ -35,6 +36,7 @@ The following package managers are currently supported:
|
||||
| [Container]({{< relref "doc/usage/packages/container.en-us.md" >}}) | - | any OCI compliant client |
|
||||
| [Debian]({{< relref "doc/usage/packages/debian.en-us.md" >}}) | - | `apt` |
|
||||
| [Generic]({{< relref "doc/usage/packages/generic.en-us.md" >}}) | - | any HTTP client |
|
||||
| [Go]({{< relref "doc/usage/packages/go.en-us.md" >}}) | Go | `go` |
|
||||
| [Helm]({{< relref "doc/usage/packages/helm.en-us.md" >}}) | - | any HTTP client, `cm-push` |
|
||||
| [Maven]({{< relref "doc/usage/packages/maven.en-us.md" >}}) | Java | `mvn`, `gradle` |
|
||||
| [npm]({{< relref "doc/usage/packages/npm.en-us.md" >}}) | JavaScript | `npm`, `yarn`, `pnpm` |
|
||||
|
||||
@@ -69,7 +69,7 @@ curl --user your_username:your_password_or_token \
|
||||
If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/development/api-usage.en-us.md#authentication" >}}) instead of the password.
|
||||
You cannot publish a file with the same name twice to a package. You must delete the existing package version first.
|
||||
|
||||
The server reponds with the following HTTP Status codes.
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
@@ -99,7 +99,7 @@ curl --user your_username:your_token_or_password -X DELETE \
|
||||
https://gitea.example.com/api/packages/testuser/rpm/test-package/1.0.0/x86_64
|
||||
```
|
||||
|
||||
The server reponds with the following HTTP Status codes.
|
||||
The server responds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
|
||||
@@ -9,7 +9,7 @@ menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "Storage"
|
||||
weight: 5
|
||||
weight: 2
|
||||
identifier: "storage"
|
||||
---
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html{{ with site.LanguageCode | default site.Language.Lang }} lang="{{ . }}"{{ end }}>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ .Permalink }}</title>
|
||||
<link rel="canonical" href="{{ .Permalink }}">
|
||||
<meta name="robots" content="noindex">
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
@@ -45,6 +44,9 @@ func (runs RunList) LoadTriggerUser(ctx context.Context) error {
|
||||
run.TriggerUser = user_model.NewActionsUser()
|
||||
} else {
|
||||
run.TriggerUser = users[run.TriggerUserID]
|
||||
if run.TriggerUser == nil {
|
||||
run.TriggerUser = user_model.NewGhostUser()
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -66,7 +68,6 @@ type FindRunOptions struct {
|
||||
db.ListOptions
|
||||
RepoID int64
|
||||
OwnerID int64
|
||||
IsClosed util.OptionalBool
|
||||
WorkflowFileName string
|
||||
TriggerUserID int64
|
||||
Approved bool // not util.OptionalBool, it works only when it's true
|
||||
@@ -80,14 +81,6 @@ func (opts FindRunOptions) toConds() builder.Cond {
|
||||
if opts.OwnerID > 0 {
|
||||
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
||||
}
|
||||
if opts.IsClosed.IsFalse() {
|
||||
cond = cond.And(builder.Eq{"status": StatusWaiting}.Or(
|
||||
builder.Eq{"status": StatusRunning}))
|
||||
} else if opts.IsClosed.IsTrue() {
|
||||
cond = cond.And(
|
||||
builder.Neq{"status": StatusWaiting}.And(
|
||||
builder.Neq{"status": StatusRunning}))
|
||||
}
|
||||
if opts.WorkflowFileName != "" {
|
||||
cond = cond.And(builder.Eq{"workflow_id": opts.WorkflowFileName})
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/shared/types"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
@@ -28,7 +29,7 @@ type ActionRunner struct {
|
||||
Version string `xorm:"VARCHAR(64)"`
|
||||
OwnerID int64 `xorm:"index"` // org level runner, 0 means system
|
||||
Owner *user_model.User `xorm:"-"`
|
||||
RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global
|
||||
RepoID int64 `xorm:"index"` // repo level runner, if OwnerID also is zero, then it's a global
|
||||
Repo *repo_model.Repository `xorm:"-"`
|
||||
Description string `xorm:"TEXT"`
|
||||
Base int // 0 native 1 docker 2 virtual machine
|
||||
@@ -52,14 +53,25 @@ type ActionRunner struct {
|
||||
Deleted timeutil.TimeStamp `xorm:"deleted"`
|
||||
}
|
||||
|
||||
func (r *ActionRunner) OwnType() string {
|
||||
// BelongsToOwnerName before calling, should guarantee that all attributes are loaded
|
||||
func (r *ActionRunner) BelongsToOwnerName() string {
|
||||
if r.RepoID != 0 {
|
||||
return fmt.Sprintf("Repo(%s)", r.Repo.FullName())
|
||||
return r.Repo.FullName()
|
||||
}
|
||||
if r.OwnerID != 0 {
|
||||
return fmt.Sprintf("Org(%s)", r.Owner.Name)
|
||||
return r.Owner.Name
|
||||
}
|
||||
return "Global"
|
||||
return ""
|
||||
}
|
||||
|
||||
func (r *ActionRunner) BelongsToOwnerType() types.OwnerType {
|
||||
if r.RepoID != 0 {
|
||||
return types.OwnerTypeRepository
|
||||
}
|
||||
if r.OwnerID != 0 {
|
||||
return types.OwnerTypeOrganization
|
||||
}
|
||||
return types.OwnerTypeSystemGlobal
|
||||
}
|
||||
|
||||
func (r *ActionRunner) Status() runnerv1.RunnerStatus {
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
@@ -240,6 +241,55 @@ func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOp
|
||||
return statuses, count, db.GetEngine(ctx).In("id", ids).Find(&statuses)
|
||||
}
|
||||
|
||||
// GetLatestCommitStatusForPairs returns all statuses with a unique context for a given list of repo-sha pairs
|
||||
func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHAs map[int64]string, listOptions db.ListOptions) (map[int64][]*CommitStatus, error) {
|
||||
type result struct {
|
||||
ID int64
|
||||
RepoID int64
|
||||
}
|
||||
|
||||
results := make([]result, 0, len(repoIDsToLatestCommitSHAs))
|
||||
|
||||
sess := db.GetEngine(ctx).Table(&CommitStatus{})
|
||||
|
||||
// Create a disjunction of conditions for each repoID and SHA pair
|
||||
conds := make([]builder.Cond, 0, len(repoIDsToLatestCommitSHAs))
|
||||
for repoID, sha := range repoIDsToLatestCommitSHAs {
|
||||
conds = append(conds, builder.Eq{"repo_id": repoID, "sha": sha})
|
||||
}
|
||||
sess = sess.Where(builder.Or(conds...)).
|
||||
Select("max( id ) as id, repo_id").
|
||||
GroupBy("context_hash, repo_id").OrderBy("max( id ) desc")
|
||||
|
||||
sess = db.SetSessionPagination(sess, &listOptions)
|
||||
|
||||
err := sess.Find(&results)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ids := make([]int64, 0, len(results))
|
||||
repoStatuses := make(map[int64][]*CommitStatus)
|
||||
for _, result := range results {
|
||||
ids = append(ids, result.ID)
|
||||
}
|
||||
|
||||
statuses := make([]*CommitStatus, 0, len(ids))
|
||||
if len(ids) > 0 {
|
||||
err = db.GetEngine(ctx).In("id", ids).Find(&statuses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Group the statuses by repo ID
|
||||
for _, status := range statuses {
|
||||
repoStatuses[status.RepoID] = append(repoStatuses[status.RepoID], status)
|
||||
}
|
||||
}
|
||||
|
||||
return repoStatuses, nil
|
||||
}
|
||||
|
||||
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
|
||||
func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
|
||||
start := timeutil.TimeStampNow().AddDuration(-before)
|
||||
|
||||
@@ -63,8 +63,8 @@ func GetTeamMembers(ctx context.Context, opts *SearchMembersOptions) ([]*user_mo
|
||||
Where(builder.Eq{"team_id": opts.TeamID}),
|
||||
)
|
||||
}
|
||||
if opts.PageSize > 0 && opts.Page > -1 {
|
||||
sess = sess.Limit(opts.PageSize, opts.Page*opts.PageSize)
|
||||
if opts.PageSize > 0 && opts.Page > 0 {
|
||||
sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
|
||||
}
|
||||
if err := sess.OrderBy("full_name, name").Find(&members); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package alpine
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
alpine_module "code.gitea.io/gitea/modules/packages/alpine"
|
||||
)
|
||||
|
||||
// GetBranches gets all available branches
|
||||
func GetBranches(ctx context.Context, ownerID int64) ([]string, error) {
|
||||
return packages_model.GetDistinctPropertyValues(
|
||||
ctx,
|
||||
packages_model.TypeAlpine,
|
||||
ownerID,
|
||||
packages_model.PropertyTypeFile,
|
||||
alpine_module.PropertyBranch,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
// GetRepositories gets all available repositories for the given branch
|
||||
func GetRepositories(ctx context.Context, ownerID int64, branch string) ([]string, error) {
|
||||
return packages_model.GetDistinctPropertyValues(
|
||||
ctx,
|
||||
packages_model.TypeAlpine,
|
||||
ownerID,
|
||||
packages_model.PropertyTypeFile,
|
||||
alpine_module.PropertyRepository,
|
||||
&packages_model.DistinctPropertyDependency{
|
||||
Name: alpine_module.PropertyBranch,
|
||||
Value: branch,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// GetArchitectures gets all available architectures for the given repository
|
||||
func GetArchitectures(ctx context.Context, ownerID int64, repository string) ([]string, error) {
|
||||
return packages_model.GetDistinctPropertyValues(
|
||||
ctx,
|
||||
packages_model.TypeAlpine,
|
||||
ownerID,
|
||||
packages_model.PropertyTypeFile,
|
||||
alpine_module.PropertyArchitecture,
|
||||
&packages_model.DistinctPropertyDependency{
|
||||
Name: alpine_module.PropertyRepository,
|
||||
Value: repository,
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -88,44 +88,42 @@ func SearchLatestPackages(ctx context.Context, opts *PackageSearchOptions) ([]*p
|
||||
|
||||
// GetDistributions gets all available distributions
|
||||
func GetDistributions(ctx context.Context, ownerID int64) ([]string, error) {
|
||||
return getDistinctPropertyValues(ctx, ownerID, "", debian_module.PropertyDistribution)
|
||||
return packages.GetDistinctPropertyValues(
|
||||
ctx,
|
||||
packages.TypeDebian,
|
||||
ownerID,
|
||||
packages.PropertyTypeFile,
|
||||
debian_module.PropertyDistribution,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
// GetComponents gets all available components for the given distribution
|
||||
func GetComponents(ctx context.Context, ownerID int64, distribution string) ([]string, error) {
|
||||
return getDistinctPropertyValues(ctx, ownerID, distribution, debian_module.PropertyComponent)
|
||||
return packages.GetDistinctPropertyValues(
|
||||
ctx,
|
||||
packages.TypeDebian,
|
||||
ownerID,
|
||||
packages.PropertyTypeFile,
|
||||
debian_module.PropertyComponent,
|
||||
&packages.DistinctPropertyDependency{
|
||||
Name: debian_module.PropertyDistribution,
|
||||
Value: distribution,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// GetArchitectures gets all available architectures for the given distribution
|
||||
func GetArchitectures(ctx context.Context, ownerID int64, distribution string) ([]string, error) {
|
||||
return getDistinctPropertyValues(ctx, ownerID, distribution, debian_module.PropertyArchitecture)
|
||||
}
|
||||
|
||||
func getDistinctPropertyValues(ctx context.Context, ownerID int64, distribution, propName string) ([]string, error) {
|
||||
var cond builder.Cond = builder.Eq{
|
||||
"package_property.ref_type": packages.PropertyTypeFile,
|
||||
"package_property.name": propName,
|
||||
"package.type": packages.TypeDebian,
|
||||
"package.owner_id": ownerID,
|
||||
}
|
||||
if distribution != "" {
|
||||
innerCond := builder.
|
||||
Expr("pp.ref_id = package_property.ref_id").
|
||||
And(builder.Eq{
|
||||
"pp.ref_type": packages.PropertyTypeFile,
|
||||
"pp.name": debian_module.PropertyDistribution,
|
||||
"pp.value": distribution,
|
||||
})
|
||||
cond = cond.And(builder.Exists(builder.Select("pp.ref_id").From("package_property pp").Where(innerCond)))
|
||||
}
|
||||
|
||||
values := make([]string, 0, 5)
|
||||
return values, db.GetEngine(ctx).
|
||||
Table("package_property").
|
||||
Distinct("package_property.value").
|
||||
Join("INNER", "package_file", "package_file.id = package_property.ref_id").
|
||||
Join("INNER", "package_version", "package_version.id = package_file.version_id").
|
||||
Join("INNER", "package", "package.id = package_version.package_id").
|
||||
Where(cond).
|
||||
Find(&values)
|
||||
return packages.GetDistinctPropertyValues(
|
||||
ctx,
|
||||
packages.TypeDebian,
|
||||
ownerID,
|
||||
packages.PropertyTypeFile,
|
||||
debian_module.PropertyArchitecture,
|
||||
&packages.DistinctPropertyDependency{
|
||||
Name: debian_module.PropertyDistribution,
|
||||
Value: distribution,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/packages/alpine"
|
||||
"code.gitea.io/gitea/modules/packages/cargo"
|
||||
"code.gitea.io/gitea/modules/packages/chef"
|
||||
"code.gitea.io/gitea/modules/packages/composer"
|
||||
@@ -136,6 +137,8 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
|
||||
|
||||
var metadata interface{}
|
||||
switch p.Type {
|
||||
case TypeAlpine:
|
||||
metadata = &alpine.VersionMetadata{}
|
||||
case TypeCargo:
|
||||
metadata = &cargo.Metadata{}
|
||||
case TypeChef:
|
||||
@@ -152,6 +155,8 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
|
||||
metadata = &debian.Metadata{}
|
||||
case TypeGeneric:
|
||||
// generic packages have no metadata
|
||||
case TypeGo:
|
||||
// go packages have no metadata
|
||||
case TypeHelm:
|
||||
metadata = &helm.Metadata{}
|
||||
case TypeNuGet:
|
||||
|
||||
@@ -30,6 +30,7 @@ type Type string
|
||||
|
||||
// List of supported packages
|
||||
const (
|
||||
TypeAlpine Type = "alpine"
|
||||
TypeCargo Type = "cargo"
|
||||
TypeChef Type = "chef"
|
||||
TypeComposer Type = "composer"
|
||||
@@ -38,6 +39,7 @@ const (
|
||||
TypeContainer Type = "container"
|
||||
TypeDebian Type = "debian"
|
||||
TypeGeneric Type = "generic"
|
||||
TypeGo Type = "go"
|
||||
TypeHelm Type = "helm"
|
||||
TypeMaven Type = "maven"
|
||||
TypeNpm Type = "npm"
|
||||
@@ -51,6 +53,7 @@ const (
|
||||
)
|
||||
|
||||
var TypeList = []Type{
|
||||
TypeAlpine,
|
||||
TypeCargo,
|
||||
TypeChef,
|
||||
TypeComposer,
|
||||
@@ -59,6 +62,7 @@ var TypeList = []Type{
|
||||
TypeContainer,
|
||||
TypeDebian,
|
||||
TypeGeneric,
|
||||
TypeGo,
|
||||
TypeHelm,
|
||||
TypeMaven,
|
||||
TypeNpm,
|
||||
@@ -74,6 +78,8 @@ var TypeList = []Type{
|
||||
// Name gets the name of the package type
|
||||
func (pt Type) Name() string {
|
||||
switch pt {
|
||||
case TypeAlpine:
|
||||
return "Alpine"
|
||||
case TypeCargo:
|
||||
return "Cargo"
|
||||
case TypeChef:
|
||||
@@ -90,6 +96,8 @@ func (pt Type) Name() string {
|
||||
return "Debian"
|
||||
case TypeGeneric:
|
||||
return "Generic"
|
||||
case TypeGo:
|
||||
return "Go"
|
||||
case TypeHelm:
|
||||
return "Helm"
|
||||
case TypeMaven:
|
||||
@@ -117,6 +125,8 @@ func (pt Type) Name() string {
|
||||
// SVGName gets the name of the package type svg image
|
||||
func (pt Type) SVGName() string {
|
||||
switch pt {
|
||||
case TypeAlpine:
|
||||
return "gitea-alpine"
|
||||
case TypeCargo:
|
||||
return "gitea-cargo"
|
||||
case TypeChef:
|
||||
@@ -133,6 +143,8 @@ func (pt Type) SVGName() string {
|
||||
return "gitea-debian"
|
||||
case TypeGeneric:
|
||||
return "octicon-package"
|
||||
case TypeGo:
|
||||
return "gitea-go"
|
||||
case TypeHelm:
|
||||
return "gitea-helm"
|
||||
case TypeMaven:
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -81,3 +83,39 @@ func DeletePropertyByName(ctx context.Context, refType PropertyType, refID int64
|
||||
_, err := db.GetEngine(ctx).Where("ref_type = ? AND ref_id = ? AND name = ?", refType, refID, name).Delete(&PackageProperty{})
|
||||
return err
|
||||
}
|
||||
|
||||
type DistinctPropertyDependency struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
// GetDistinctPropertyValues returns all distinct property values for a given type.
|
||||
// Optional: Search only in dependence of another property.
|
||||
func GetDistinctPropertyValues(ctx context.Context, packageType Type, ownerID int64, refType PropertyType, propertyName string, dep *DistinctPropertyDependency) ([]string, error) {
|
||||
var cond builder.Cond = builder.Eq{
|
||||
"package_property.ref_type": refType,
|
||||
"package_property.name": propertyName,
|
||||
"package.type": packageType,
|
||||
"package.owner_id": ownerID,
|
||||
}
|
||||
if dep != nil {
|
||||
innerCond := builder.
|
||||
Expr("pp.ref_id = package_property.ref_id").
|
||||
And(builder.Eq{
|
||||
"pp.ref_type": refType,
|
||||
"pp.name": dep.Name,
|
||||
"pp.value": dep.Value,
|
||||
})
|
||||
cond = cond.And(builder.Exists(builder.Select("pp.ref_id").From("package_property pp").Where(innerCond)))
|
||||
}
|
||||
|
||||
values := make([]string, 0, 5)
|
||||
return values, db.GetEngine(ctx).
|
||||
Table("package_property").
|
||||
Distinct("package_property.value").
|
||||
Join("INNER", "package_file", "package_file.id = package_property.ref_id").
|
||||
Join("INNER", "package_version", "package_version.id = package_file.version_id").
|
||||
Join("INNER", "package", "package.id = package_version.package_id").
|
||||
Where(cond).
|
||||
Find(&values)
|
||||
}
|
||||
|
||||
@@ -149,8 +149,8 @@ type Repository struct {
|
||||
IsEmpty bool `xorm:"INDEX"`
|
||||
IsArchived bool `xorm:"INDEX"`
|
||||
IsMirror bool `xorm:"INDEX"`
|
||||
*Mirror `xorm:"-"`
|
||||
Status RepositoryStatus `xorm:"NOT NULL DEFAULT 0"`
|
||||
|
||||
Status RepositoryStatus `xorm:"NOT NULL DEFAULT 0"`
|
||||
|
||||
RenderingMetas map[string]string `xorm:"-"`
|
||||
DocumentRenderingMetas map[string]string `xorm:"-"`
|
||||
@@ -596,16 +596,9 @@ func ComposeHTTPSCloneURL(owner, repo string) string {
|
||||
return fmt.Sprintf("%s%s/%s.git", setting.AppURL, url.PathEscape(owner), url.PathEscape(repo))
|
||||
}
|
||||
|
||||
func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
|
||||
repoName := repo.Name
|
||||
if isWiki {
|
||||
repoName += ".wiki"
|
||||
}
|
||||
|
||||
func ComposeSSHCloneURL(ownerName, repoName string) string {
|
||||
sshUser := setting.SSH.User
|
||||
|
||||
cl := new(CloneLink)
|
||||
|
||||
// if we have a ipv6 literal we need to put brackets around it
|
||||
// for the git cloning to work.
|
||||
sshDomain := setting.SSH.Domain
|
||||
@@ -615,12 +608,25 @@ func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
|
||||
}
|
||||
|
||||
if setting.SSH.Port != 22 {
|
||||
cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, net.JoinHostPort(setting.SSH.Domain, strconv.Itoa(setting.SSH.Port)), url.PathEscape(repo.OwnerName), url.PathEscape(repoName))
|
||||
} else if setting.Repository.UseCompatSSHURI {
|
||||
cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName))
|
||||
} else {
|
||||
cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName))
|
||||
return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser,
|
||||
net.JoinHostPort(setting.SSH.Domain, strconv.Itoa(setting.SSH.Port)),
|
||||
url.PathEscape(ownerName),
|
||||
url.PathEscape(repoName))
|
||||
}
|
||||
if setting.Repository.UseCompatSSHURI {
|
||||
return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshDomain, url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||
}
|
||||
return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshDomain, url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||
}
|
||||
|
||||
func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
|
||||
repoName := repo.Name
|
||||
if isWiki {
|
||||
repoName += ".wiki"
|
||||
}
|
||||
|
||||
cl := new(CloneLink)
|
||||
cl.SSH = ComposeSSHCloneURL(repo.OwnerName, repoName)
|
||||
cl.HTTPS = ComposeHTTPSCloneURL(repo.OwnerName, repoName)
|
||||
return cl
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func newSecret(ownerID, repoID int64, name, data string) *Secret {
|
||||
|
||||
// InsertEncryptedSecret Creates, encrypts, and validates a new secret with yet unencrypted data and insert into database
|
||||
func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, data string) (*Secret, error) {
|
||||
encrypted, err := secret_module.EncryptSecret(setting.SecretKey, strings.TrimSpace(data))
|
||||
encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package types
|
||||
|
||||
import "code.gitea.io/gitea/modules/translation"
|
||||
|
||||
type OwnerType string
|
||||
|
||||
const (
|
||||
OwnerTypeSystemGlobal = "system-global"
|
||||
OwnerTypeIndividual = "individual"
|
||||
OwnerTypeRepository = "repository"
|
||||
OwnerTypeOrganization = "organization"
|
||||
)
|
||||
|
||||
func (o OwnerType) LocaleString(locale translation.Locale) string {
|
||||
switch o {
|
||||
case OwnerTypeSystemGlobal:
|
||||
return locale.Tr("concept_system_global")
|
||||
case OwnerTypeIndividual:
|
||||
return locale.Tr("concept_user_individual")
|
||||
case OwnerTypeRepository:
|
||||
return locale.Tr("concept_code_repository")
|
||||
case OwnerTypeOrganization:
|
||||
return locale.Tr("concept_user_organization")
|
||||
}
|
||||
return locale.Tr("unknown")
|
||||
}
|
||||
@@ -5,13 +5,14 @@ package avatar
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
|
||||
_ "image/gif" // for processing gif images
|
||||
_ "image/jpeg" // for processing jpeg images
|
||||
_ "image/png" // for processing png images
|
||||
|
||||
"code.gitea.io/gitea/modules/avatar/identicon"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@@ -22,8 +23,11 @@ import (
|
||||
_ "golang.org/x/image/webp" // for processing webp images
|
||||
)
|
||||
|
||||
// AvatarSize returns avatar's size
|
||||
const AvatarSize = 290
|
||||
// DefaultAvatarSize is the target CSS pixel size for avatar generation. It is
|
||||
// multiplied by setting.Avatar.RenderedSizeFactor and the resulting size is the
|
||||
// usual size of avatar image saved on server, unless the original file is smaller
|
||||
// than the size after resizing.
|
||||
const DefaultAvatarSize = 256
|
||||
|
||||
// RandomImageSize generates and returns a random avatar image unique to input data
|
||||
// in custom size (height and width).
|
||||
@@ -39,28 +43,44 @@ func RandomImageSize(size int, data []byte) (image.Image, error) {
|
||||
// RandomImage generates and returns a random avatar image unique to input data
|
||||
// in default size (height and width).
|
||||
func RandomImage(data []byte) (image.Image, error) {
|
||||
return RandomImageSize(AvatarSize, data)
|
||||
return RandomImageSize(DefaultAvatarSize*setting.Avatar.RenderedSizeFactor, data)
|
||||
}
|
||||
|
||||
// Prepare accepts a byte slice as input, validates it contains an image of an
|
||||
// acceptable format, and crops and resizes it appropriately.
|
||||
func Prepare(data []byte) (*image.Image, error) {
|
||||
imgCfg, _, err := image.DecodeConfig(bytes.NewReader(data))
|
||||
// processAvatarImage process the avatar image data, crop and resize it if necessary.
|
||||
// the returned data could be the original image if no processing is needed.
|
||||
func processAvatarImage(data []byte, maxOriginSize int64) ([]byte, error) {
|
||||
imgCfg, imgType, err := image.DecodeConfig(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DecodeConfig: %w", err)
|
||||
return nil, fmt.Errorf("image.DecodeConfig: %w", err)
|
||||
}
|
||||
|
||||
// for safety, only accept known types explicitly
|
||||
if imgType != "png" && imgType != "jpeg" && imgType != "gif" && imgType != "webp" {
|
||||
return nil, errors.New("unsupported avatar image type")
|
||||
}
|
||||
|
||||
// do not process image which is too large, it would consume too much memory
|
||||
if imgCfg.Width > setting.Avatar.MaxWidth {
|
||||
return nil, fmt.Errorf("Image width is too large: %d > %d", imgCfg.Width, setting.Avatar.MaxWidth)
|
||||
return nil, fmt.Errorf("image width is too large: %d > %d", imgCfg.Width, setting.Avatar.MaxWidth)
|
||||
}
|
||||
if imgCfg.Height > setting.Avatar.MaxHeight {
|
||||
return nil, fmt.Errorf("Image height is too large: %d > %d", imgCfg.Height, setting.Avatar.MaxHeight)
|
||||
return nil, fmt.Errorf("image height is too large: %d > %d", imgCfg.Height, setting.Avatar.MaxHeight)
|
||||
}
|
||||
|
||||
// If the origin is small enough, just use it, then APNG could be supported,
|
||||
// otherwise, if the image is processed later, APNG loses animation.
|
||||
// And one more thing, webp is not fully supported, for animated webp, image.DecodeConfig works but Decode fails.
|
||||
// So for animated webp, if the uploaded file is smaller than maxOriginSize, it will be used, if it's larger, there will be an error.
|
||||
if len(data) < int(maxOriginSize) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
img, _, err := image.Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Decode: %w", err)
|
||||
return nil, fmt.Errorf("image.Decode: %w", err)
|
||||
}
|
||||
|
||||
// try to crop and resize the origin image if necessary
|
||||
if imgCfg.Width != imgCfg.Height {
|
||||
var newSize, ax, ay int
|
||||
if imgCfg.Width > imgCfg.Height {
|
||||
@@ -74,13 +94,33 @@ func Prepare(data []byte) (*image.Image, error) {
|
||||
img, err = cutter.Crop(img, cutter.Config{
|
||||
Width: newSize,
|
||||
Height: newSize,
|
||||
Anchor: image.Point{ax, ay},
|
||||
Anchor: image.Point{X: ax, Y: ay},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
img = resize.Resize(AvatarSize, AvatarSize, img, resize.Bilinear)
|
||||
return &img, nil
|
||||
targetSize := uint(DefaultAvatarSize * setting.Avatar.RenderedSizeFactor)
|
||||
img = resize.Resize(targetSize, targetSize, img, resize.Bilinear)
|
||||
|
||||
// try to encode the cropped/resized image to png
|
||||
bs := bytes.Buffer{}
|
||||
if err = png.Encode(&bs, img); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resized := bs.Bytes()
|
||||
|
||||
// usually the png compression is not good enough, use the original image (no cropping/resizing) if the origin is smaller
|
||||
if len(data) <= len(resized) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
return resized, nil
|
||||
}
|
||||
|
||||
// ProcessAvatarImage process the avatar image data, crop and resize it if necessary.
|
||||
// the returned data could be the original image if no processing is needed.
|
||||
func ProcessAvatarImage(data []byte) ([]byte, error) {
|
||||
return processAvatarImage(data, setting.Avatar.MaxOriginSize)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
package avatar
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/png"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@@ -25,49 +28,109 @@ func Test_RandomImage(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_PrepareWithPNG(t *testing.T) {
|
||||
func Test_ProcessAvatarPNG(t *testing.T) {
|
||||
setting.Avatar.MaxWidth = 4096
|
||||
setting.Avatar.MaxHeight = 4096
|
||||
|
||||
data, err := os.ReadFile("testdata/avatar.png")
|
||||
assert.NoError(t, err)
|
||||
|
||||
imgPtr, err := Prepare(data)
|
||||
_, err = processAvatarImage(data, 262144)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 290, (*imgPtr).Bounds().Max.X)
|
||||
assert.Equal(t, 290, (*imgPtr).Bounds().Max.Y)
|
||||
}
|
||||
|
||||
func Test_PrepareWithJPEG(t *testing.T) {
|
||||
func Test_ProcessAvatarJPEG(t *testing.T) {
|
||||
setting.Avatar.MaxWidth = 4096
|
||||
setting.Avatar.MaxHeight = 4096
|
||||
|
||||
data, err := os.ReadFile("testdata/avatar.jpeg")
|
||||
assert.NoError(t, err)
|
||||
|
||||
imgPtr, err := Prepare(data)
|
||||
_, err = processAvatarImage(data, 262144)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 290, (*imgPtr).Bounds().Max.X)
|
||||
assert.Equal(t, 290, (*imgPtr).Bounds().Max.Y)
|
||||
}
|
||||
|
||||
func Test_PrepareWithInvalidImage(t *testing.T) {
|
||||
func Test_ProcessAvatarInvalidData(t *testing.T) {
|
||||
setting.Avatar.MaxWidth = 5
|
||||
setting.Avatar.MaxHeight = 5
|
||||
|
||||
_, err := Prepare([]byte{})
|
||||
assert.EqualError(t, err, "DecodeConfig: image: unknown format")
|
||||
_, err := processAvatarImage([]byte{}, 12800)
|
||||
assert.EqualError(t, err, "image.DecodeConfig: image: unknown format")
|
||||
}
|
||||
|
||||
func Test_PrepareWithInvalidImageSize(t *testing.T) {
|
||||
func Test_ProcessAvatarInvalidImageSize(t *testing.T) {
|
||||
setting.Avatar.MaxWidth = 5
|
||||
setting.Avatar.MaxHeight = 5
|
||||
|
||||
data, err := os.ReadFile("testdata/avatar.png")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = Prepare(data)
|
||||
assert.EqualError(t, err, "Image width is too large: 10 > 5")
|
||||
_, err = processAvatarImage(data, 12800)
|
||||
assert.EqualError(t, err, "image width is too large: 10 > 5")
|
||||
}
|
||||
|
||||
func Test_ProcessAvatarImage(t *testing.T) {
|
||||
setting.Avatar.MaxWidth = 4096
|
||||
setting.Avatar.MaxHeight = 4096
|
||||
scaledSize := DefaultAvatarSize * setting.Avatar.RenderedSizeFactor
|
||||
|
||||
newImgData := func(size int, optHeight ...int) []byte {
|
||||
width := size
|
||||
height := size
|
||||
if len(optHeight) == 1 {
|
||||
height = optHeight[0]
|
||||
}
|
||||
img := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
bs := bytes.Buffer{}
|
||||
err := png.Encode(&bs, img)
|
||||
assert.NoError(t, err)
|
||||
return bs.Bytes()
|
||||
}
|
||||
|
||||
// if origin image canvas is too large, crop and resize it
|
||||
origin := newImgData(500, 600)
|
||||
result, err := processAvatarImage(origin, 0)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, origin, result)
|
||||
decoded, err := png.Decode(bytes.NewReader(result))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, scaledSize, decoded.Bounds().Max.X)
|
||||
assert.EqualValues(t, scaledSize, decoded.Bounds().Max.Y)
|
||||
|
||||
// if origin image is smaller than the default size, use the origin image
|
||||
origin = newImgData(1)
|
||||
result, err = processAvatarImage(origin, 0)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, origin, result)
|
||||
|
||||
// use the origin image if the origin is smaller
|
||||
origin = newImgData(scaledSize + 100)
|
||||
result, err = processAvatarImage(origin, 0)
|
||||
assert.NoError(t, err)
|
||||
assert.Less(t, len(result), len(origin))
|
||||
|
||||
// still use the origin image if the origin doesn't exceed the max-origin-size
|
||||
origin = newImgData(scaledSize + 100)
|
||||
result, err = processAvatarImage(origin, 262144)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, origin, result)
|
||||
|
||||
// allow to use known image format (eg: webp) if it is small enough
|
||||
origin, err = os.ReadFile("testdata/animated.webp")
|
||||
assert.NoError(t, err)
|
||||
result, err = processAvatarImage(origin, 262144)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, origin, result)
|
||||
|
||||
// do not support unknown image formats, eg: SVG may contain embedded JS
|
||||
origin = []byte("<svg></svg>")
|
||||
_, err = processAvatarImage(origin, 262144)
|
||||
assert.ErrorContains(t, err, "image: unknown format")
|
||||
|
||||
// make sure the canvas size limit works
|
||||
setting.Avatar.MaxWidth = 5
|
||||
setting.Avatar.MaxHeight = 5
|
||||
origin = newImgData(10)
|
||||
_, err = processAvatarImage(origin, 262144)
|
||||
assert.ErrorContains(t, err, "image width is too large: 10 > 5")
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -5,16 +5,16 @@ package context
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRemoveSessionCookieHeader(t *testing.T) {
|
||||
w := httplib.NewMockResponseWriter()
|
||||
w := httptest.NewRecorder()
|
||||
w.Header().Add("Set-Cookie", (&http.Cookie{Name: setting.SessionConfig.CookieName, Value: "foo"}).String())
|
||||
w.Header().Add("Set-Cookie", (&http.Cookie{Name: "other", Value: "bar"}).String())
|
||||
assert.Len(t, w.Header().Values("Set-Cookie"), 2)
|
||||
|
||||
@@ -61,7 +61,6 @@ type Repository struct {
|
||||
RepoLink string
|
||||
CloneLink repo_model.CloneLink
|
||||
CommitsCount int64
|
||||
Mirror *repo_model.Mirror
|
||||
|
||||
PullRequest *PullRequest
|
||||
}
|
||||
@@ -319,7 +318,14 @@ func EarlyResponseForGoGetMeta(ctx *Context) {
|
||||
ctx.PlainText(http.StatusBadRequest, "invalid repository path")
|
||||
return
|
||||
}
|
||||
goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(username, reponame), repo_model.ComposeHTTPSCloneURL(username, reponame))
|
||||
|
||||
var cloneURL string
|
||||
if setting.Repository.GoGetCloneURLProtocol == "ssh" {
|
||||
cloneURL = repo_model.ComposeSSHCloneURL(username, reponame)
|
||||
} else {
|
||||
cloneURL = repo_model.ComposeHTTPSCloneURL(username, reponame)
|
||||
}
|
||||
goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(username, reponame), cloneURL)
|
||||
htmlMeta := fmt.Sprintf(`<meta name="go-import" content="%s">`, html.EscapeString(goImportContent))
|
||||
ctx.PlainText(http.StatusOK, htmlMeta)
|
||||
}
|
||||
@@ -373,13 +379,9 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
|
||||
ctx.Data["Permission"] = &ctx.Repo.Permission
|
||||
|
||||
if repo.IsMirror {
|
||||
ctx.Repo.Mirror, err = repo_model.GetMirrorByRepoID(ctx, repo.ID)
|
||||
pullMirror, err := repo_model.GetMirrorByRepoID(ctx, repo.ID)
|
||||
if err == nil {
|
||||
ctx.Repo.Mirror.Repo = repo
|
||||
ctx.Data["IsPullMirror"] = true
|
||||
ctx.Data["MirrorEnablePrune"] = ctx.Repo.Mirror.EnablePrune
|
||||
ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
|
||||
ctx.Data["Mirror"] = ctx.Repo.Mirror
|
||||
ctx.Data["PullMirror"] = pullMirror
|
||||
} else if err != repo_model.ErrMirrorNotExist {
|
||||
ctx.ServerError("GetMirrorByRepoID", err)
|
||||
return
|
||||
|
||||
@@ -106,6 +106,17 @@ func GetBranchesByPath(ctx context.Context, path string, skip, limit int) ([]*Br
|
||||
return gitRepo.GetBranches(skip, limit)
|
||||
}
|
||||
|
||||
// GetBranchCommitID returns a branch commit ID by its name
|
||||
func GetBranchCommitID(ctx context.Context, path, branch string) (string, error) {
|
||||
gitRepo, err := OpenRepository(ctx, path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
return gitRepo.GetBranchCommitID(branch)
|
||||
}
|
||||
|
||||
// GetBranches returns a slice of *git.Branch
|
||||
func (repo *Repository) GetBranches(skip, limit int) ([]*Branch, int, error) {
|
||||
brs, countAll, err := repo.GetBranchNames(skip, limit)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -45,7 +46,7 @@ type Manager struct {
|
||||
|
||||
func newGracefulManager(ctx context.Context) *Manager {
|
||||
manager := &Manager{
|
||||
isChild: len(os.Getenv(listenFDs)) > 0 && os.Getppid() > 1,
|
||||
isChild: len(os.Getenv(listenFDsEnv)) > 0 && os.Getppid() > 1,
|
||||
lock: &sync.RWMutex{},
|
||||
}
|
||||
manager.createServerWaitGroup.Add(numberOfServersToCreate)
|
||||
@@ -53,6 +54,41 @@ func newGracefulManager(ctx context.Context) *Manager {
|
||||
return manager
|
||||
}
|
||||
|
||||
type systemdNotifyMsg string
|
||||
|
||||
const (
|
||||
readyMsg systemdNotifyMsg = "READY=1"
|
||||
stoppingMsg systemdNotifyMsg = "STOPPING=1"
|
||||
reloadingMsg systemdNotifyMsg = "RELOADING=1"
|
||||
watchdogMsg systemdNotifyMsg = "WATCHDOG=1"
|
||||
)
|
||||
|
||||
func statusMsg(msg string) systemdNotifyMsg {
|
||||
return systemdNotifyMsg("STATUS=" + msg)
|
||||
}
|
||||
|
||||
func pidMsg() systemdNotifyMsg {
|
||||
return systemdNotifyMsg("MAINPID=" + strconv.Itoa(os.Getpid()))
|
||||
}
|
||||
|
||||
// Notify systemd of status via the notify protocol
|
||||
func (g *Manager) notify(msg systemdNotifyMsg) {
|
||||
conn, err := getNotifySocket()
|
||||
if err != nil {
|
||||
// the err is logged in getNotifySocket
|
||||
return
|
||||
}
|
||||
if conn == nil {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if _, err = conn.Write([]byte(msg)); err != nil {
|
||||
log.Warn("Failed to notify NOTIFY_SOCKET: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Manager) start(ctx context.Context) {
|
||||
// Make contexts
|
||||
g.terminateCtx, g.terminateCtxCancel = context.WithCancel(ctx)
|
||||
@@ -72,6 +108,8 @@ func (g *Manager) start(ctx context.Context) {
|
||||
|
||||
// Set the running state & handle signals
|
||||
g.setState(stateRunning)
|
||||
g.notify(statusMsg("Starting Gitea"))
|
||||
g.notify(pidMsg())
|
||||
go g.handleSignals(g.managerCtx)
|
||||
|
||||
// Handle clean up of unused provided listeners and delayed start-up
|
||||
@@ -84,6 +122,7 @@ func (g *Manager) start(ctx context.Context) {
|
||||
// Ignore the error here there's not much we can do with it
|
||||
// They're logged in the CloseProvidedListeners function
|
||||
_ = CloseProvidedListeners()
|
||||
g.notify(readyMsg)
|
||||
}()
|
||||
if setting.StartupTimeout > 0 {
|
||||
go func() {
|
||||
@@ -104,6 +143,8 @@ func (g *Manager) start(ctx context.Context) {
|
||||
return
|
||||
case <-time.After(setting.StartupTimeout):
|
||||
log.Error("Startup took too long! Shutting down")
|
||||
g.notify(statusMsg("Startup took too long! Shutting down"))
|
||||
g.notify(stoppingMsg)
|
||||
g.doShutdown()
|
||||
}
|
||||
}()
|
||||
@@ -126,6 +167,13 @@ func (g *Manager) handleSignals(ctx context.Context) {
|
||||
syscall.SIGTSTP,
|
||||
)
|
||||
|
||||
watchdogTimeout := getWatchdogTimeout()
|
||||
t := &time.Ticker{}
|
||||
if watchdogTimeout != 0 {
|
||||
g.notify(watchdogMsg)
|
||||
t = time.NewTicker(watchdogTimeout / 2)
|
||||
}
|
||||
|
||||
pid := syscall.Getpid()
|
||||
for {
|
||||
select {
|
||||
@@ -136,6 +184,7 @@ func (g *Manager) handleSignals(ctx context.Context) {
|
||||
g.DoGracefulRestart()
|
||||
case syscall.SIGUSR1:
|
||||
log.Warn("PID %d. Received SIGUSR1. Releasing and reopening logs", pid)
|
||||
g.notify(statusMsg("Releasing and reopening logs"))
|
||||
if err := log.ReleaseReopen(); err != nil {
|
||||
log.Error("Error whilst releasing and reopening logs: %v", err)
|
||||
}
|
||||
@@ -153,6 +202,8 @@ func (g *Manager) handleSignals(ctx context.Context) {
|
||||
default:
|
||||
log.Info("PID %d. Received %v.", pid, sig)
|
||||
}
|
||||
case <-t.C:
|
||||
g.notify(watchdogMsg)
|
||||
case <-ctx.Done():
|
||||
log.Warn("PID: %d. Background context for manager closed - %v - Shutting down...", pid, ctx.Err())
|
||||
g.DoGracefulShutdown()
|
||||
@@ -169,6 +220,9 @@ func (g *Manager) doFork() error {
|
||||
}
|
||||
g.forked = true
|
||||
g.lock.Unlock()
|
||||
|
||||
g.notify(reloadingMsg)
|
||||
|
||||
// We need to move the file logs to append pids
|
||||
setting.RestartLogsWithPIDSuffix()
|
||||
|
||||
@@ -191,18 +245,27 @@ func (g *Manager) DoGracefulRestart() {
|
||||
}
|
||||
} else {
|
||||
log.Info("PID: %d. Not set restartable. Shutting down...", os.Getpid())
|
||||
|
||||
g.notify(stoppingMsg)
|
||||
g.doShutdown()
|
||||
}
|
||||
}
|
||||
|
||||
// DoImmediateHammer causes an immediate hammer
|
||||
func (g *Manager) DoImmediateHammer() {
|
||||
g.notify(statusMsg("Sending immediate hammer"))
|
||||
g.doHammerTime(0 * time.Second)
|
||||
}
|
||||
|
||||
// DoGracefulShutdown causes a graceful shutdown
|
||||
func (g *Manager) DoGracefulShutdown() {
|
||||
g.lock.Lock()
|
||||
if !g.forked {
|
||||
g.lock.Unlock()
|
||||
g.notify(stoppingMsg)
|
||||
} else {
|
||||
g.lock.Unlock()
|
||||
g.notify(statusMsg("Shutting down after fork"))
|
||||
}
|
||||
g.doShutdown()
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@@ -21,9 +22,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
listenFDs = "LISTEN_FDS"
|
||||
startFD = 3
|
||||
unlinkFDs = "GITEA_UNLINK_FDS"
|
||||
listenFDsEnv = "LISTEN_FDS"
|
||||
startFD = 3
|
||||
unlinkFDsEnv = "GITEA_UNLINK_FDS"
|
||||
|
||||
notifySocketEnv = "NOTIFY_SOCKET"
|
||||
watchdogTimeoutEnv = "WATCHDOG_USEC"
|
||||
)
|
||||
|
||||
// In order to keep the working directory the same as when we started we record
|
||||
@@ -38,6 +42,9 @@ var (
|
||||
activeListenersToUnlink = []bool{}
|
||||
providedListeners = []net.Listener{}
|
||||
activeListeners = []net.Listener{}
|
||||
|
||||
notifySocketAddr string
|
||||
watchdogTimeout time.Duration
|
||||
)
|
||||
|
||||
func getProvidedFDs() (savedErr error) {
|
||||
@@ -45,18 +52,52 @@ func getProvidedFDs() (savedErr error) {
|
||||
once.Do(func() {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
// now handle some additional systemd provided things
|
||||
notifySocketAddr = os.Getenv(notifySocketEnv)
|
||||
if notifySocketAddr != "" {
|
||||
log.Debug("Systemd Notify Socket provided: %s", notifySocketAddr)
|
||||
savedErr = os.Unsetenv(notifySocketEnv)
|
||||
if savedErr != nil {
|
||||
log.Warn("Unable to Unset the NOTIFY_SOCKET environment variable: %v", savedErr)
|
||||
return
|
||||
}
|
||||
// FIXME: We don't handle WATCHDOG_PID
|
||||
timeoutStr := os.Getenv(watchdogTimeoutEnv)
|
||||
if timeoutStr != "" {
|
||||
savedErr = os.Unsetenv(watchdogTimeoutEnv)
|
||||
if savedErr != nil {
|
||||
log.Warn("Unable to Unset the WATCHDOG_USEC environment variable: %v", savedErr)
|
||||
return
|
||||
}
|
||||
|
||||
numFDs := os.Getenv(listenFDs)
|
||||
s, err := strconv.ParseInt(timeoutStr, 10, 64)
|
||||
if err != nil {
|
||||
log.Error("Unable to parse the provided WATCHDOG_USEC: %v", err)
|
||||
savedErr = fmt.Errorf("unable to parse the provided WATCHDOG_USEC: %w", err)
|
||||
return
|
||||
}
|
||||
if s <= 0 {
|
||||
log.Error("Unable to parse the provided WATCHDOG_USEC: %s should be a positive number", timeoutStr)
|
||||
savedErr = fmt.Errorf("unable to parse the provided WATCHDOG_USEC: %s should be a positive number", timeoutStr)
|
||||
return
|
||||
}
|
||||
watchdogTimeout = time.Duration(s) * time.Microsecond
|
||||
}
|
||||
} else {
|
||||
log.Trace("No Systemd Notify Socket provided")
|
||||
}
|
||||
|
||||
numFDs := os.Getenv(listenFDsEnv)
|
||||
if numFDs == "" {
|
||||
return
|
||||
}
|
||||
n, err := strconv.Atoi(numFDs)
|
||||
if err != nil {
|
||||
savedErr = fmt.Errorf("%s is not a number: %s. Err: %w", listenFDs, numFDs, err)
|
||||
savedErr = fmt.Errorf("%s is not a number: %s. Err: %w", listenFDsEnv, numFDs, err)
|
||||
return
|
||||
}
|
||||
|
||||
fdsToUnlinkStr := strings.Split(os.Getenv(unlinkFDs), ",")
|
||||
fdsToUnlinkStr := strings.Split(os.Getenv(unlinkFDsEnv), ",")
|
||||
providedListenersToUnlink = make([]bool, n)
|
||||
for _, fdStr := range fdsToUnlinkStr {
|
||||
i, err := strconv.Atoi(fdStr)
|
||||
@@ -73,7 +114,7 @@ func getProvidedFDs() (savedErr error) {
|
||||
if err == nil {
|
||||
// Close the inherited file if it's a listener
|
||||
if err = file.Close(); err != nil {
|
||||
savedErr = fmt.Errorf("error closing provided socket fd %d: %s", i, err)
|
||||
savedErr = fmt.Errorf("error closing provided socket fd %d: %w", i, err)
|
||||
return
|
||||
}
|
||||
providedListeners = append(providedListeners, l)
|
||||
@@ -255,3 +296,36 @@ func getActiveListenersToUnlink() []bool {
|
||||
copy(listenersToUnlink, activeListenersToUnlink)
|
||||
return listenersToUnlink
|
||||
}
|
||||
|
||||
func getNotifySocket() (*net.UnixConn, error) {
|
||||
if err := getProvidedFDs(); err != nil {
|
||||
// This error will be logged elsewhere
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if notifySocketAddr == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
socketAddr := &net.UnixAddr{
|
||||
Name: notifySocketAddr,
|
||||
Net: "unixgram",
|
||||
}
|
||||
|
||||
notifySocket, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
|
||||
if err != nil {
|
||||
log.Warn("failed to dial NOTIFY_SOCKET %s: %v", socketAddr, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return notifySocket, nil
|
||||
}
|
||||
|
||||
func getWatchdogTimeout() time.Duration {
|
||||
if err := getProvidedFDs(); err != nil {
|
||||
// This error will be logged elsewhere
|
||||
return 0
|
||||
}
|
||||
|
||||
return watchdogTimeout
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
var killParent sync.Once
|
||||
@@ -70,11 +71,20 @@ func RestartProcess() (int, error) {
|
||||
// Pass on the environment and replace the old count key with the new one.
|
||||
var env []string
|
||||
for _, v := range os.Environ() {
|
||||
if !strings.HasPrefix(v, listenFDs+"=") {
|
||||
if !strings.HasPrefix(v, listenFDsEnv+"=") {
|
||||
env = append(env, v)
|
||||
}
|
||||
}
|
||||
env = append(env, fmt.Sprintf("%s=%d", listenFDs, len(listeners)))
|
||||
env = append(env, fmt.Sprintf("%s=%d", listenFDsEnv, len(listeners)))
|
||||
|
||||
if notifySocketAddr != "" {
|
||||
env = append(env, fmt.Sprintf("%s=%s", notifySocketEnv, notifySocketAddr))
|
||||
}
|
||||
|
||||
if watchdogTimeout != 0 {
|
||||
watchdogStr := strconv.FormatInt(int64(watchdogTimeout/time.Millisecond), 10)
|
||||
env = append(env, fmt.Sprintf("%s=%s", watchdogTimeoutEnv, watchdogStr))
|
||||
}
|
||||
|
||||
sb := &strings.Builder{}
|
||||
for i, unlink := range getActiveListenersToUnlink() {
|
||||
@@ -87,7 +97,7 @@ func RestartProcess() (int, error) {
|
||||
unlinkStr := sb.String()
|
||||
if len(unlinkStr) > 0 {
|
||||
unlinkStr = unlinkStr[:len(unlinkStr)-1]
|
||||
env = append(env, fmt.Sprintf("%s=%s", unlinkFDs, unlinkStr))
|
||||
env = append(env, fmt.Sprintf("%s=%s", unlinkFDsEnv, unlinkStr))
|
||||
}
|
||||
|
||||
allFiles := append([]*os.File{os.Stdin, os.Stdout, os.Stderr}, files...)
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
package httpcache
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -37,38 +35,9 @@ func SetCacheControlInHeader(h http.Header, maxAge time.Duration, additionalDire
|
||||
h.Set("Cache-Control", strings.Join(append(directives, additionalDirectives...), ", "))
|
||||
}
|
||||
|
||||
// generateETag generates an ETag based on size, filename and file modification time
|
||||
func generateETag(fi os.FileInfo) string {
|
||||
etag := fmt.Sprint(fi.Size()) + fi.Name() + fi.ModTime().UTC().Format(http.TimeFormat)
|
||||
return `"` + base64.StdEncoding.EncodeToString([]byte(etag)) + `"`
|
||||
}
|
||||
|
||||
// HandleTimeCache handles time-based caching for a HTTP request
|
||||
func HandleTimeCache(req *http.Request, w http.ResponseWriter, fi os.FileInfo) (handled bool) {
|
||||
return HandleGenericTimeCache(req, w, fi.ModTime())
|
||||
}
|
||||
|
||||
// HandleGenericTimeCache handles time-based caching for a HTTP request
|
||||
func HandleGenericTimeCache(req *http.Request, w http.ResponseWriter, lastModified time.Time) (handled bool) {
|
||||
func ServeContentWithCacheControl(w http.ResponseWriter, req *http.Request, name string, modTime time.Time, content io.ReadSeeker) {
|
||||
SetCacheControlInHeader(w.Header(), setting.StaticCacheTime)
|
||||
|
||||
ifModifiedSince := req.Header.Get("If-Modified-Since")
|
||||
if ifModifiedSince != "" {
|
||||
t, err := time.Parse(http.TimeFormat, ifModifiedSince)
|
||||
if err == nil && lastModified.Unix() <= t.Unix() {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Last-Modified", lastModified.Format(http.TimeFormat))
|
||||
return false
|
||||
}
|
||||
|
||||
// HandleFileETagCache handles ETag-based caching for a HTTP request
|
||||
func HandleFileETagCache(req *http.Request, w http.ResponseWriter, fi os.FileInfo) (handled bool) {
|
||||
etag := generateETag(fi)
|
||||
return HandleGenericETagCache(req, w, etag)
|
||||
http.ServeContent(w, req, name, modTime, content)
|
||||
}
|
||||
|
||||
// HandleGenericETagCache handles ETag-based caching for a HTTP request.
|
||||
|
||||
@@ -6,23 +6,12 @@ package httpcache
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type mockFileInfo struct{}
|
||||
|
||||
func (m mockFileInfo) Name() string { return "gitea.test" }
|
||||
func (m mockFileInfo) Size() int64 { return int64(10) }
|
||||
func (m mockFileInfo) Mode() os.FileMode { return os.ModePerm }
|
||||
func (m mockFileInfo) ModTime() time.Time { return time.Time{} }
|
||||
func (m mockFileInfo) IsDir() bool { return false }
|
||||
func (m mockFileInfo) Sys() interface{} { return nil }
|
||||
|
||||
func countFormalHeaders(h http.Header) (c int) {
|
||||
for k := range h {
|
||||
// ignore our headers for internal usage
|
||||
@@ -34,52 +23,6 @@ func countFormalHeaders(h http.Header) (c int) {
|
||||
return c
|
||||
}
|
||||
|
||||
func TestHandleFileETagCache(t *testing.T) {
|
||||
fi := mockFileInfo{}
|
||||
etag := `"MTBnaXRlYS50ZXN0TW9uLCAwMSBKYW4gMDAwMSAwMDowMDowMCBHTVQ="`
|
||||
|
||||
t.Run("No_If-None-Match", func(t *testing.T) {
|
||||
req := &http.Request{Header: make(http.Header)}
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handled := HandleFileETagCache(req, w, fi)
|
||||
|
||||
assert.False(t, handled)
|
||||
assert.Equal(t, 2, countFormalHeaders(w.Header()))
|
||||
assert.Contains(t, w.Header(), "Cache-Control")
|
||||
assert.Contains(t, w.Header(), "Etag")
|
||||
assert.Equal(t, etag, w.Header().Get("Etag"))
|
||||
})
|
||||
t.Run("Wrong_If-None-Match", func(t *testing.T) {
|
||||
req := &http.Request{Header: make(http.Header)}
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
req.Header.Set("If-None-Match", `"wrong etag"`)
|
||||
|
||||
handled := HandleFileETagCache(req, w, fi)
|
||||
|
||||
assert.False(t, handled)
|
||||
assert.Equal(t, 2, countFormalHeaders(w.Header()))
|
||||
assert.Contains(t, w.Header(), "Cache-Control")
|
||||
assert.Contains(t, w.Header(), "Etag")
|
||||
assert.Equal(t, etag, w.Header().Get("Etag"))
|
||||
})
|
||||
t.Run("Correct_If-None-Match", func(t *testing.T) {
|
||||
req := &http.Request{Header: make(http.Header)}
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
req.Header.Set("If-None-Match", etag)
|
||||
|
||||
handled := HandleFileETagCache(req, w, fi)
|
||||
|
||||
assert.True(t, handled)
|
||||
assert.Equal(t, 1, countFormalHeaders(w.Header()))
|
||||
assert.Contains(t, w.Header(), "Etag")
|
||||
assert.Equal(t, etag, w.Header().Get("Etag"))
|
||||
assert.Equal(t, http.StatusNotModified, w.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandleGenericETagCache(t *testing.T) {
|
||||
etag := `"test"`
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package httplib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type MockResponseWriter struct {
|
||||
header http.Header
|
||||
|
||||
StatusCode int
|
||||
BodyBuffer bytes.Buffer
|
||||
}
|
||||
|
||||
func (m *MockResponseWriter) Header() http.Header {
|
||||
return m.header
|
||||
}
|
||||
|
||||
func (m *MockResponseWriter) Write(bytes []byte) (int, error) {
|
||||
if m.StatusCode == 0 {
|
||||
m.StatusCode = http.StatusOK
|
||||
}
|
||||
return m.BodyBuffer.Write(bytes)
|
||||
}
|
||||
|
||||
func (m *MockResponseWriter) WriteHeader(statusCode int) {
|
||||
m.StatusCode = statusCode
|
||||
}
|
||||
|
||||
func NewMockResponseWriter() *MockResponseWriter {
|
||||
return &MockResponseWriter{header: http.Header{}}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ package httplib
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -25,12 +26,12 @@ func TestServeContentByReader(t *testing.T) {
|
||||
r.Header.Set("Range", fmt.Sprintf("bytes=%s", rangeStr))
|
||||
}
|
||||
reader := strings.NewReader(data)
|
||||
w := NewMockResponseWriter()
|
||||
w := httptest.NewRecorder()
|
||||
ServeContentByReader(r, w, "test", int64(len(data)), reader)
|
||||
assert.Equal(t, expectedStatusCode, w.StatusCode)
|
||||
assert.Equal(t, expectedStatusCode, w.Code)
|
||||
if expectedStatusCode == http.StatusPartialContent || expectedStatusCode == http.StatusOK {
|
||||
assert.Equal(t, fmt.Sprint(len(expectedContent)), w.Header().Get("Content-Length"))
|
||||
assert.Equal(t, expectedContent, w.BodyBuffer.String())
|
||||
assert.Equal(t, expectedContent, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,12 +77,12 @@ func TestServeContentByReadSeeker(t *testing.T) {
|
||||
}
|
||||
defer seekReader.Close()
|
||||
|
||||
w := NewMockResponseWriter()
|
||||
w := httptest.NewRecorder()
|
||||
ServeContentByReadSeeker(r, w, "test", time.Time{}, seekReader)
|
||||
assert.Equal(t, expectedStatusCode, w.StatusCode)
|
||||
assert.Equal(t, expectedStatusCode, w.Code)
|
||||
if expectedStatusCode == http.StatusPartialContent || expectedStatusCode == http.StatusOK {
|
||||
assert.Equal(t, fmt.Sprint(len(expectedContent)), w.Header().Get("Content-Length"))
|
||||
assert.Equal(t, expectedContent, w.BodyBuffer.String())
|
||||
assert.Equal(t, expectedContent, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package alpine
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bufio"
|
||||
"compress/gzip"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMissingPKGINFOFile = util.NewInvalidArgumentErrorf("PKGINFO file is missing")
|
||||
ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid")
|
||||
ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid")
|
||||
)
|
||||
|
||||
const (
|
||||
PropertyMetadata = "alpine.metadata"
|
||||
PropertyBranch = "alpine.branch"
|
||||
PropertyRepository = "alpine.repository"
|
||||
PropertyArchitecture = "alpine.architecture"
|
||||
|
||||
SettingKeyPrivate = "alpine.key.private"
|
||||
SettingKeyPublic = "alpine.key.public"
|
||||
|
||||
RepositoryPackage = "_alpine"
|
||||
RepositoryVersion = "_repository"
|
||||
)
|
||||
|
||||
// https://wiki.alpinelinux.org/wiki/Apk_spec
|
||||
|
||||
// Package represents an Alpine package
|
||||
type Package struct {
|
||||
Name string
|
||||
Version string
|
||||
VersionMetadata VersionMetadata
|
||||
FileMetadata FileMetadata
|
||||
}
|
||||
|
||||
// Metadata of an Alpine package
|
||||
type VersionMetadata struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
License string `json:"license,omitempty"`
|
||||
ProjectURL string `json:"project_url,omitempty"`
|
||||
Maintainer string `json:"maintainer,omitempty"`
|
||||
}
|
||||
|
||||
type FileMetadata struct {
|
||||
Checksum string `json:"checksum"`
|
||||
Packager string `json:"packager,omitempty"`
|
||||
BuildDate int64 `json:"build_date,omitempty"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
Architecture string `json:"architecture,omitempty"`
|
||||
Origin string `json:"origin,omitempty"`
|
||||
CommitHash string `json:"commit_hash,omitempty"`
|
||||
InstallIf string `json:"install_if,omitempty"`
|
||||
Provides []string `json:"provides,omitempty"`
|
||||
Dependencies []string `json:"dependencies,omitempty"`
|
||||
}
|
||||
|
||||
// ParsePackage parses the Alpine package file
|
||||
func ParsePackage(r io.Reader) (*Package, error) {
|
||||
// Alpine packages are concated .tar.gz streams. Usually the first stream contains the package metadata.
|
||||
|
||||
br := bufio.NewReader(r) // needed for gzip Multistream
|
||||
|
||||
h := sha1.New()
|
||||
|
||||
gzr, err := gzip.NewReader(&teeByteReader{br, h})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer gzr.Close()
|
||||
|
||||
for {
|
||||
gzr.Multistream(false)
|
||||
|
||||
tr := tar.NewReader(gzr)
|
||||
for {
|
||||
hd, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if hd.Name == ".PKGINFO" {
|
||||
p, err := ParsePackageInfo(tr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// drain the reader
|
||||
for {
|
||||
if _, err := tr.Next(); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
p.FileMetadata.Checksum = "Q1" + base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
h = sha1.New()
|
||||
|
||||
err = gzr.Reset(&teeByteReader{br, h})
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrMissingPKGINFOFile
|
||||
}
|
||||
|
||||
// ParsePackageInfo parses a PKGINFO file to retrieve the metadata of an Alpine package
|
||||
func ParsePackageInfo(r io.Reader) (*Package, error) {
|
||||
p := &Package{}
|
||||
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
if strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
|
||||
i := strings.IndexRune(line, '=')
|
||||
if i == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
key := strings.TrimSpace(line[:i])
|
||||
value := strings.TrimSpace(line[i+1:])
|
||||
|
||||
switch key {
|
||||
case "pkgname":
|
||||
p.Name = value
|
||||
case "pkgver":
|
||||
p.Version = value
|
||||
case "pkgdesc":
|
||||
p.VersionMetadata.Description = value
|
||||
case "url":
|
||||
p.VersionMetadata.ProjectURL = value
|
||||
case "builddate":
|
||||
n, err := strconv.ParseInt(value, 10, 64)
|
||||
if err == nil {
|
||||
p.FileMetadata.BuildDate = n
|
||||
}
|
||||
case "size":
|
||||
n, err := strconv.ParseInt(value, 10, 64)
|
||||
if err == nil {
|
||||
p.FileMetadata.Size = n
|
||||
}
|
||||
case "arch":
|
||||
p.FileMetadata.Architecture = value
|
||||
case "origin":
|
||||
p.FileMetadata.Origin = value
|
||||
case "commit":
|
||||
p.FileMetadata.CommitHash = value
|
||||
case "maintainer":
|
||||
p.VersionMetadata.Maintainer = value
|
||||
case "packager":
|
||||
p.FileMetadata.Packager = value
|
||||
case "license":
|
||||
p.VersionMetadata.License = value
|
||||
case "install_if":
|
||||
p.FileMetadata.InstallIf = value
|
||||
case "provides":
|
||||
if value != "" {
|
||||
p.FileMetadata.Provides = append(p.FileMetadata.Provides, value)
|
||||
}
|
||||
case "depend":
|
||||
if value != "" {
|
||||
p.FileMetadata.Dependencies = append(p.FileMetadata.Dependencies, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if p.Name == "" {
|
||||
return nil, ErrInvalidName
|
||||
}
|
||||
|
||||
if p.Version == "" {
|
||||
return nil, ErrInvalidVersion
|
||||
}
|
||||
|
||||
if !validation.IsValidURL(p.VersionMetadata.ProjectURL) {
|
||||
p.VersionMetadata.ProjectURL = ""
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Same as io.TeeReader but implements io.ByteReader
|
||||
type teeByteReader struct {
|
||||
r *bufio.Reader
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (t *teeByteReader) Read(p []byte) (int, error) {
|
||||
n, err := t.r.Read(p)
|
||||
if n > 0 {
|
||||
if n, err := t.w.Write(p[:n]); err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (t *teeByteReader) ReadByte() (byte, error) {
|
||||
b, err := t.r.ReadByte()
|
||||
if err == nil {
|
||||
if _, err := t.w.Write([]byte{b}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return b, err
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package alpine
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
packageName = "gitea"
|
||||
packageVersion = "1.0.1"
|
||||
packageDescription = "Package Description"
|
||||
packageProjectURL = "https://gitea.io"
|
||||
packageMaintainer = "KN4CK3R <dummy@gitea.io>"
|
||||
)
|
||||
|
||||
func createPKGINFOContent(name, version string) []byte {
|
||||
return []byte(`pkgname = ` + name + `
|
||||
pkgver = ` + version + `
|
||||
pkgdesc = ` + packageDescription + `
|
||||
url = ` + packageProjectURL + `
|
||||
# comment
|
||||
builddate = 1678834800
|
||||
packager = Gitea <pack@ag.er>
|
||||
size = 123456
|
||||
arch = aarch64
|
||||
origin = origin
|
||||
commit = 1111e709613fbc979651b09ac2bc27c6591a9999
|
||||
maintainer = ` + packageMaintainer + `
|
||||
license = MIT
|
||||
depend = common
|
||||
install_if = value
|
||||
depend = gitea
|
||||
provides = common
|
||||
provides = gitea`)
|
||||
}
|
||||
|
||||
func TestParsePackage(t *testing.T) {
|
||||
createPackage := func(name string, content []byte) io.Reader {
|
||||
names := []string{"first.stream", name}
|
||||
contents := [][]byte{{0}, content}
|
||||
|
||||
var buf bytes.Buffer
|
||||
zw := gzip.NewWriter(&buf)
|
||||
|
||||
for i := range names {
|
||||
if i != 0 {
|
||||
zw.Close()
|
||||
zw.Reset(&buf)
|
||||
}
|
||||
|
||||
tw := tar.NewWriter(zw)
|
||||
hdr := &tar.Header{
|
||||
Name: names[i],
|
||||
Mode: 0o600,
|
||||
Size: int64(len(contents[i])),
|
||||
}
|
||||
tw.WriteHeader(hdr)
|
||||
tw.Write(contents[i])
|
||||
tw.Close()
|
||||
}
|
||||
|
||||
zw.Close()
|
||||
|
||||
return &buf
|
||||
}
|
||||
|
||||
t.Run("MissingPKGINFOFile", func(t *testing.T) {
|
||||
data := createPackage("dummy.txt", []byte{})
|
||||
|
||||
pp, err := ParsePackage(data)
|
||||
assert.Nil(t, pp)
|
||||
assert.ErrorIs(t, err, ErrMissingPKGINFOFile)
|
||||
})
|
||||
|
||||
t.Run("InvalidPKGINFOFile", func(t *testing.T) {
|
||||
data := createPackage(".PKGINFO", []byte{})
|
||||
|
||||
pp, err := ParsePackage(data)
|
||||
assert.Nil(t, pp)
|
||||
assert.ErrorIs(t, err, ErrInvalidName)
|
||||
})
|
||||
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
data := createPackage(".PKGINFO", createPKGINFOContent(packageName, packageVersion))
|
||||
|
||||
p, err := ParsePackage(data)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, p)
|
||||
|
||||
assert.Equal(t, "Q1SRYURM5+uQDqfHSwTnNIOIuuDVQ=", p.FileMetadata.Checksum)
|
||||
})
|
||||
}
|
||||
|
||||
func TestParsePackageInfo(t *testing.T) {
|
||||
t.Run("InvalidName", func(t *testing.T) {
|
||||
data := createPKGINFOContent("", packageVersion)
|
||||
|
||||
p, err := ParsePackageInfo(bytes.NewReader(data))
|
||||
assert.Nil(t, p)
|
||||
assert.ErrorIs(t, err, ErrInvalidName)
|
||||
})
|
||||
|
||||
t.Run("InvalidVersion", func(t *testing.T) {
|
||||
data := createPKGINFOContent(packageName, "")
|
||||
|
||||
p, err := ParsePackageInfo(bytes.NewReader(data))
|
||||
assert.Nil(t, p)
|
||||
assert.ErrorIs(t, err, ErrInvalidVersion)
|
||||
})
|
||||
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
data := createPKGINFOContent(packageName, packageVersion)
|
||||
|
||||
p, err := ParsePackageInfo(bytes.NewReader(data))
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, p)
|
||||
|
||||
assert.Equal(t, packageName, p.Name)
|
||||
assert.Equal(t, packageVersion, p.Version)
|
||||
assert.Equal(t, packageDescription, p.VersionMetadata.Description)
|
||||
assert.Equal(t, packageMaintainer, p.VersionMetadata.Maintainer)
|
||||
assert.Equal(t, packageProjectURL, p.VersionMetadata.ProjectURL)
|
||||
assert.Equal(t, "MIT", p.VersionMetadata.License)
|
||||
assert.Empty(t, p.FileMetadata.Checksum)
|
||||
assert.Equal(t, "Gitea <pack@ag.er>", p.FileMetadata.Packager)
|
||||
assert.EqualValues(t, 1678834800, p.FileMetadata.BuildDate)
|
||||
assert.EqualValues(t, 123456, p.FileMetadata.Size)
|
||||
assert.Equal(t, "aarch64", p.FileMetadata.Architecture)
|
||||
assert.Equal(t, "origin", p.FileMetadata.Origin)
|
||||
assert.Equal(t, "1111e709613fbc979651b09ac2bc27c6591a9999", p.FileMetadata.CommitHash)
|
||||
assert.Equal(t, "value", p.FileMetadata.InstallIf)
|
||||
assert.ElementsMatch(t, []string{"common", "gitea"}, p.FileMetadata.Provides)
|
||||
assert.ElementsMatch(t, []string{"common", "gitea"}, p.FileMetadata.Dependencies)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package goproxy
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
const (
|
||||
PropertyGoMod = "go.mod"
|
||||
|
||||
maxGoModFileSize = 16 * 1024 * 1024 // https://go.dev/ref/mod#zip-path-size-constraints
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidStructure = util.NewInvalidArgumentErrorf("package has invalid structure")
|
||||
ErrGoModFileTooLarge = util.NewInvalidArgumentErrorf("go.mod file is too large")
|
||||
)
|
||||
|
||||
type Package struct {
|
||||
Name string
|
||||
Version string
|
||||
GoMod string
|
||||
}
|
||||
|
||||
// ParsePackage parses the Go package file
|
||||
// https://go.dev/ref/mod#zip-files
|
||||
func ParsePackage(r io.ReaderAt, size int64) (*Package, error) {
|
||||
archive, err := zip.NewReader(r, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var p *Package
|
||||
|
||||
for _, file := range archive.File {
|
||||
nameAndVersion := path.Dir(file.Name)
|
||||
|
||||
parts := strings.SplitN(nameAndVersion, "@", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
versionParts := strings.SplitN(parts[1], "/", 2)
|
||||
|
||||
if p == nil {
|
||||
p = &Package{
|
||||
Name: strings.TrimSuffix(nameAndVersion, "@"+parts[1]),
|
||||
Version: versionParts[0],
|
||||
}
|
||||
}
|
||||
|
||||
if len(versionParts) > 1 {
|
||||
// files are expected in the "root" folder
|
||||
continue
|
||||
}
|
||||
|
||||
if path.Base(file.Name) == "go.mod" {
|
||||
if file.UncompressedSize64 > maxGoModFileSize {
|
||||
return nil, ErrGoModFileTooLarge
|
||||
}
|
||||
|
||||
f, err := archive.Open(file.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
bytes, err := io.ReadAll(&io.LimitedReader{R: f, N: maxGoModFileSize})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.GoMod = string(bytes)
|
||||
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
if p == nil {
|
||||
return nil, ErrInvalidStructure
|
||||
}
|
||||
|
||||
p.GoMod = fmt.Sprintf("module %s", p.Name)
|
||||
|
||||
return p, nil
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package goproxy
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
packageName = "gitea.com/go-gitea/gitea"
|
||||
packageVersion = "v0.0.1"
|
||||
)
|
||||
|
||||
func TestParsePackage(t *testing.T) {
|
||||
createArchive := func(files map[string][]byte) *bytes.Reader {
|
||||
var buf bytes.Buffer
|
||||
zw := zip.NewWriter(&buf)
|
||||
for name, content := range files {
|
||||
w, _ := zw.Create(name)
|
||||
w.Write(content)
|
||||
}
|
||||
zw.Close()
|
||||
return bytes.NewReader(buf.Bytes())
|
||||
}
|
||||
|
||||
t.Run("EmptyPackage", func(t *testing.T) {
|
||||
data := createArchive(nil)
|
||||
|
||||
p, err := ParsePackage(data, int64(data.Len()))
|
||||
assert.Nil(t, p)
|
||||
assert.ErrorIs(t, err, ErrInvalidStructure)
|
||||
})
|
||||
|
||||
t.Run("InvalidNameOrVersionStructure", func(t *testing.T) {
|
||||
data := createArchive(map[string][]byte{
|
||||
packageName + "/" + packageVersion + "/go.mod": {},
|
||||
})
|
||||
|
||||
p, err := ParsePackage(data, int64(data.Len()))
|
||||
assert.Nil(t, p)
|
||||
assert.ErrorIs(t, err, ErrInvalidStructure)
|
||||
})
|
||||
|
||||
t.Run("GoModFileInWrongDirectory", func(t *testing.T) {
|
||||
data := createArchive(map[string][]byte{
|
||||
packageName + "@" + packageVersion + "/subdir/go.mod": {},
|
||||
})
|
||||
|
||||
p, err := ParsePackage(data, int64(data.Len()))
|
||||
assert.NotNil(t, p)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, packageName, p.Name)
|
||||
assert.Equal(t, packageVersion, p.Version)
|
||||
assert.Equal(t, "module gitea.com/go-gitea/gitea", p.GoMod)
|
||||
})
|
||||
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
data := createArchive(map[string][]byte{
|
||||
packageName + "@" + packageVersion + "/subdir/go.mod": []byte("invalid"),
|
||||
packageName + "@" + packageVersion + "/go.mod": []byte("valid"),
|
||||
})
|
||||
|
||||
p, err := ParsePackage(data, int64(data.Len()))
|
||||
assert.NotNil(t, p)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, packageName, p.Name)
|
||||
assert.Equal(t, packageVersion, p.Version)
|
||||
assert.Equal(t, "valid", p.GoMod)
|
||||
})
|
||||
}
|
||||
@@ -97,10 +97,6 @@ func handleRequest(w http.ResponseWriter, req *http.Request, fs http.FileSystem,
|
||||
return true
|
||||
}
|
||||
|
||||
if httpcache.HandleFileETagCache(req, w, fi) {
|
||||
return true
|
||||
}
|
||||
|
||||
serveContent(w, req, fi, fi.ModTime(), f)
|
||||
return true
|
||||
}
|
||||
@@ -124,11 +120,11 @@ func serveContent(w http.ResponseWriter, req *http.Request, fi os.FileInfo, modt
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
}
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
http.ServeContent(w, req, fi.Name(), modtime, rdGzip)
|
||||
httpcache.ServeContentWithCacheControl(w, req, fi.Name(), modtime, rdGzip)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
http.ServeContent(w, req, fi.Name(), modtime, content)
|
||||
httpcache.ServeContentWithCacheControl(w, req, fi.Name(), modtime, content)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package repository
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -136,13 +137,11 @@ func TestPushCommits_AvatarLink(t *testing.T) {
|
||||
enableGravatar(t)
|
||||
|
||||
assert.Equal(t,
|
||||
"https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon&s=84",
|
||||
"https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon&s="+strconv.Itoa(28*setting.Avatar.RenderedSizeFactor),
|
||||
pushCommits.AvatarLink(db.DefaultContext, "user2@example.com"))
|
||||
|
||||
assert.Equal(t,
|
||||
"https://secure.gravatar.com/avatar/"+
|
||||
fmt.Sprintf("%x", md5.Sum([]byte("nonexistent@example.com")))+
|
||||
"?d=identicon&s=84",
|
||||
fmt.Sprintf("https://secure.gravatar.com/avatar/%x?d=identicon&s=%d", md5.Sum([]byte("nonexistent@example.com")), 28*setting.Avatar.RenderedSizeFactor),
|
||||
pushCommits.AvatarLink(db.DefaultContext, "nonexistent@example.com"))
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/mail"
|
||||
"strings"
|
||||
@@ -198,7 +199,7 @@ func loadMailerFrom(rootCfg ConfigProvider) {
|
||||
ips := tryResolveAddr(MailService.SMTPAddr)
|
||||
if MailService.Protocol == "smtp" {
|
||||
for _, ip := range ips {
|
||||
if !ip.IsLoopback() {
|
||||
if !ip.IP.IsLoopback() {
|
||||
log.Warn("connecting over insecure SMTP protocol to non-local address is not recommended")
|
||||
break
|
||||
}
|
||||
@@ -258,20 +259,21 @@ func loadNotifyMailFrom(rootCfg ConfigProvider) {
|
||||
log.Info("Notify Mail Service Enabled")
|
||||
}
|
||||
|
||||
func tryResolveAddr(addr string) []net.IP {
|
||||
func tryResolveAddr(addr string) []net.IPAddr {
|
||||
if strings.HasPrefix(addr, "[") && strings.HasSuffix(addr, "]") {
|
||||
addr = addr[1 : len(addr)-1]
|
||||
}
|
||||
ip := net.ParseIP(addr)
|
||||
if ip != nil {
|
||||
ips := make([]net.IP, 1)
|
||||
ips[0] = ip
|
||||
return ips
|
||||
return []net.IPAddr{{IP: ip}}
|
||||
}
|
||||
ips, err := net.LookupIP(addr)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
ips, err := net.DefaultResolver.LookupIPAddr(ctx, addr)
|
||||
if err != nil {
|
||||
log.Warn("could not look up mailer.SMTP_ADDR: %v", err)
|
||||
return make([]net.IP, 0)
|
||||
return nil
|
||||
}
|
||||
return ips
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ var (
|
||||
|
||||
LimitTotalOwnerCount int64
|
||||
LimitTotalOwnerSize int64
|
||||
LimitSizeAlpine int64
|
||||
LimitSizeCargo int64
|
||||
LimitSizeChef int64
|
||||
LimitSizeComposer int64
|
||||
@@ -32,6 +33,7 @@ var (
|
||||
LimitSizeContainer int64
|
||||
LimitSizeDebian int64
|
||||
LimitSizeGeneric int64
|
||||
LimitSizeGo int64
|
||||
LimitSizeHelm int64
|
||||
LimitSizeMaven int64
|
||||
LimitSizeNpm int64
|
||||
@@ -69,6 +71,7 @@ func loadPackagesFrom(rootCfg ConfigProvider) {
|
||||
}
|
||||
|
||||
Packages.LimitTotalOwnerSize = mustBytes(sec, "LIMIT_TOTAL_OWNER_SIZE")
|
||||
Packages.LimitSizeAlpine = mustBytes(sec, "LIMIT_SIZE_ALPINE")
|
||||
Packages.LimitSizeCargo = mustBytes(sec, "LIMIT_SIZE_CARGO")
|
||||
Packages.LimitSizeChef = mustBytes(sec, "LIMIT_SIZE_CHEF")
|
||||
Packages.LimitSizeComposer = mustBytes(sec, "LIMIT_SIZE_COMPOSER")
|
||||
@@ -77,6 +80,7 @@ func loadPackagesFrom(rootCfg ConfigProvider) {
|
||||
Packages.LimitSizeContainer = mustBytes(sec, "LIMIT_SIZE_CONTAINER")
|
||||
Packages.LimitSizeDebian = mustBytes(sec, "LIMIT_SIZE_DEBIAN")
|
||||
Packages.LimitSizeGeneric = mustBytes(sec, "LIMIT_SIZE_GENERIC")
|
||||
Packages.LimitSizeGo = mustBytes(sec, "LIMIT_SIZE_GO")
|
||||
Packages.LimitSizeHelm = mustBytes(sec, "LIMIT_SIZE_HELM")
|
||||
Packages.LimitSizeMaven = mustBytes(sec, "LIMIT_SIZE_MAVEN")
|
||||
Packages.LimitSizeNpm = mustBytes(sec, "LIMIT_SIZE_NPM")
|
||||
|
||||
@@ -3,21 +3,23 @@
|
||||
|
||||
package setting
|
||||
|
||||
// settings
|
||||
// Avatar settings
|
||||
|
||||
var (
|
||||
// Picture settings
|
||||
Avatar = struct {
|
||||
Storage
|
||||
|
||||
MaxWidth int
|
||||
MaxHeight int
|
||||
MaxFileSize int64
|
||||
MaxOriginSize int64
|
||||
RenderedSizeFactor int
|
||||
}{
|
||||
MaxWidth: 4096,
|
||||
MaxHeight: 3072,
|
||||
MaxHeight: 4096,
|
||||
MaxFileSize: 1048576,
|
||||
RenderedSizeFactor: 3,
|
||||
MaxOriginSize: 262144,
|
||||
RenderedSizeFactor: 2,
|
||||
}
|
||||
|
||||
GravatarSource string
|
||||
@@ -44,9 +46,10 @@ func loadPictureFrom(rootCfg ConfigProvider) {
|
||||
Avatar.Storage = getStorage(rootCfg, "avatars", storageType, avatarSec)
|
||||
|
||||
Avatar.MaxWidth = sec.Key("AVATAR_MAX_WIDTH").MustInt(4096)
|
||||
Avatar.MaxHeight = sec.Key("AVATAR_MAX_HEIGHT").MustInt(3072)
|
||||
Avatar.MaxHeight = sec.Key("AVATAR_MAX_HEIGHT").MustInt(4096)
|
||||
Avatar.MaxFileSize = sec.Key("AVATAR_MAX_FILE_SIZE").MustInt64(1048576)
|
||||
Avatar.RenderedSizeFactor = sec.Key("AVATAR_RENDERED_SIZE_FACTOR").MustInt(3)
|
||||
Avatar.MaxOriginSize = sec.Key("AVATAR_MAX_ORIGIN_SIZE").MustInt64(262144)
|
||||
Avatar.RenderedSizeFactor = sec.Key("AVATAR_RENDERED_SIZE_FACTOR").MustInt(2)
|
||||
|
||||
switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
|
||||
case "duoshuo":
|
||||
@@ -94,5 +97,5 @@ func loadRepoAvatarFrom(rootCfg ConfigProvider) {
|
||||
RepoAvatar.Storage = getStorage(rootCfg, "repo-avatars", storageType, repoAvatarSec)
|
||||
|
||||
RepoAvatar.Fallback = sec.Key("REPOSITORY_AVATAR_FALLBACK").MustString("none")
|
||||
RepoAvatar.FallbackImage = sec.Key("REPOSITORY_AVATAR_FALLBACK_IMAGE").MustString("/assets/img/repo_default.png")
|
||||
RepoAvatar.FallbackImage = sec.Key("REPOSITORY_AVATAR_FALLBACK_IMAGE").MustString(AppSubURL + "/assets/img/repo_default.png")
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ var (
|
||||
DisableHTTPGit bool
|
||||
AccessControlAllowOrigin string
|
||||
UseCompatSSHURI bool
|
||||
GoGetCloneURLProtocol string
|
||||
DefaultCloseIssuesViaCommitsInAnyBranch bool
|
||||
EnablePushCreateUser bool
|
||||
EnablePushCreateOrg bool
|
||||
@@ -307,6 +308,7 @@ func loadRepositoryFrom(rootCfg ConfigProvider) {
|
||||
|
||||
Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool()
|
||||
Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool()
|
||||
Repository.GoGetCloneURLProtocol = sec.Key("GO_GET_CLONE_URL_PROTOCOL").MustString("https")
|
||||
Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1)
|
||||
Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString(Repository.DefaultBranch)
|
||||
RepoRootPath = sec.Key("ROOT").MustString(path.Join(AppDataPath, "gitea-repositories"))
|
||||
|
||||
@@ -133,8 +133,8 @@ func (l *LocalStorage) URL(path, name string) (*url.URL, error) {
|
||||
}
|
||||
|
||||
// IterateObjects iterates across the objects in the local storage
|
||||
func (l *LocalStorage) IterateObjects(prefix string, fn func(path string, obj Object) error) error {
|
||||
dir := l.buildLocalPath(prefix)
|
||||
func (l *LocalStorage) IterateObjects(dirName string, fn func(path string, obj Object) error) error {
|
||||
dir := l.buildLocalPath(dirName)
|
||||
return filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -57,38 +55,5 @@ func TestBuildLocalPath(t *testing.T) {
|
||||
|
||||
func TestLocalStorageIterator(t *testing.T) {
|
||||
dir := filepath.Join(os.TempDir(), "TestLocalStorageIteratorTestDir")
|
||||
l, err := NewLocalStorage(context.Background(), LocalStorageConfig{Path: dir})
|
||||
assert.NoError(t, err)
|
||||
|
||||
testFiles := [][]string{
|
||||
{"a/1.txt", "a1"},
|
||||
{"/a/1.txt", "aa1"}, // same as above, but with leading slash that will be trim
|
||||
{"b/1.txt", "b1"},
|
||||
{"b/2.txt", "b2"},
|
||||
{"b/3.txt", "b3"},
|
||||
{"b/x 4.txt", "bx4"},
|
||||
}
|
||||
for _, f := range testFiles {
|
||||
_, err = l.Save(f[0], bytes.NewBufferString(f[1]), -1)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
expectedList := map[string][]string{
|
||||
"a": {"a/1.txt"},
|
||||
"b": {"b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
|
||||
"": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
|
||||
"/": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
|
||||
"a/b/../../a": {"a/1.txt"},
|
||||
}
|
||||
for dir, expected := range expectedList {
|
||||
count := 0
|
||||
err = l.IterateObjects(dir, func(path string, f Object) error {
|
||||
defer f.Close()
|
||||
assert.Contains(t, expected, path)
|
||||
count++
|
||||
return nil
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, expected, count)
|
||||
}
|
||||
testStorageIterator(t, string(LocalStorageType), LocalStorageConfig{Path: dir})
|
||||
}
|
||||
|
||||
@@ -129,7 +129,11 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
|
||||
}
|
||||
|
||||
func (m *MinioStorage) buildMinioPath(p string) string {
|
||||
return util.PathJoinRelX(m.basePath, p)
|
||||
p = util.PathJoinRelX(m.basePath, p)
|
||||
if p == "." {
|
||||
p = "" // minio doesn't use dot as relative path
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Open opens a file
|
||||
@@ -224,14 +228,15 @@ func (m *MinioStorage) URL(path, name string) (*url.URL, error) {
|
||||
}
|
||||
|
||||
// IterateObjects iterates across the objects in the miniostorage
|
||||
func (m *MinioStorage) IterateObjects(prefix string, fn func(path string, obj Object) error) error {
|
||||
func (m *MinioStorage) IterateObjects(dirName string, fn func(path string, obj Object) error) error {
|
||||
opts := minio.GetObjectOptions{}
|
||||
lobjectCtx, cancel := context.WithCancel(m.ctx)
|
||||
defer cancel()
|
||||
|
||||
basePath := m.basePath
|
||||
if prefix != "" {
|
||||
basePath = m.buildMinioPath(prefix)
|
||||
if dirName != "" {
|
||||
// ending slash is required for avoiding matching like "foo/" and "foobar/" with prefix "foo"
|
||||
basePath = m.buildMinioPath(dirName) + "/"
|
||||
}
|
||||
|
||||
for mObjInfo := range m.client.ListObjects(lobjectCtx, m.bucket, minio.ListObjectsOptions{
|
||||
@@ -244,7 +249,7 @@ func (m *MinioStorage) IterateObjects(prefix string, fn func(path string, obj Ob
|
||||
}
|
||||
if err := func(object *minio.Object, fn func(path string, obj Object) error) error {
|
||||
defer object.Close()
|
||||
return fn(strings.TrimPrefix(mObjInfo.Key, basePath), &minioObject{object})
|
||||
return fn(strings.TrimPrefix(mObjInfo.Key, m.basePath), &minioObject{object})
|
||||
}(object, fn); err != nil {
|
||||
return convertMinioErr(err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMinioStorageIterator(t *testing.T) {
|
||||
testStorageIterator(t, string(MinioStorageType), MinioStorageConfig{
|
||||
Endpoint: "127.0.0.1:9000",
|
||||
AccessKeyID: "123456",
|
||||
SecretAccessKey: "12345678",
|
||||
Bucket: "gitea",
|
||||
Location: "us-east-1",
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testStorageIterator(t *testing.T, typStr string, cfg interface{}) {
|
||||
l, err := NewStorage(typStr, cfg)
|
||||
assert.NoError(t, err)
|
||||
|
||||
testFiles := [][]string{
|
||||
{"a/1.txt", "a1"},
|
||||
{"/a/1.txt", "aa1"}, // same as above, but with leading slash that will be trim
|
||||
{"ab/1.txt", "ab1"},
|
||||
{"b/1.txt", "b1"},
|
||||
{"b/2.txt", "b2"},
|
||||
{"b/3.txt", "b3"},
|
||||
{"b/x 4.txt", "bx4"},
|
||||
}
|
||||
for _, f := range testFiles {
|
||||
_, err = l.Save(f[0], bytes.NewBufferString(f[1]), -1)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
expectedList := map[string][]string{
|
||||
"a": {"a/1.txt"},
|
||||
"b": {"b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
|
||||
"": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt", "ab/1.txt"},
|
||||
"/": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt", "ab/1.txt"},
|
||||
"a/b/../../a": {"a/1.txt"},
|
||||
}
|
||||
for dir, expected := range expectedList {
|
||||
count := 0
|
||||
err = l.IterateObjects(dir, func(path string, f Object) error {
|
||||
defer f.Close()
|
||||
assert.Contains(t, expected, path)
|
||||
count++
|
||||
return nil
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, expected, count)
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,9 @@ func (w *testLoggerWriterCloser) Write(p []byte) (int, error) {
|
||||
}
|
||||
|
||||
if t == nil || *t == nil {
|
||||
return fmt.Fprintf(os.Stdout, "??? [Unknown Test] %s\n", p)
|
||||
// if there is no running test, the log message should be outputted to console, to avoid losing important information.
|
||||
// the "???" prefix is used to match the "===" and "+++" in PrintCurrentTest
|
||||
return fmt.Fprintf(os.Stdout, "??? [TestLogger] %s\n", p)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
// GenerateKeyPair generates a public and private keypair
|
||||
@@ -43,3 +46,16 @@ func pemBlockForPub(pub *rsa.PublicKey) (string, error) {
|
||||
})
|
||||
return string(pubBytes), nil
|
||||
}
|
||||
|
||||
// CreatePublicKeyFingerprint creates a fingerprint of the given key.
|
||||
// The fingerprint is the sha256 sum of the PKIX structure of the key.
|
||||
func CreatePublicKeyFingerprint(key crypto.PublicKey) ([]byte, error) {
|
||||
bytes, err := x509.MarshalPKIXPublicKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
checksum := sha256.Sum256(bytes)
|
||||
|
||||
return checksum[:], nil
|
||||
}
|
||||
|
||||
@@ -114,6 +114,11 @@ unknown = Unknown
|
||||
|
||||
rss_feed = RSS Feed
|
||||
|
||||
concept_system_global = Global
|
||||
concept_user_individual = Individual
|
||||
concept_code_repository = Repository
|
||||
concept_user_organization = Organization
|
||||
|
||||
[aria]
|
||||
navbar = Navigation Bar
|
||||
footer = Footer
|
||||
@@ -3217,6 +3222,15 @@ versions = Versions
|
||||
versions.view_all = View all
|
||||
dependency.id = ID
|
||||
dependency.version = Version
|
||||
alpine.registry = Setup this registry by adding the url in your <code>/etc/apk/repositories</code> file:
|
||||
alpine.registry.key = Download the registry public RSA key into the <code>/etc/apk/keys/</code> folder to verify the index signature:
|
||||
alpine.registry.info = Choose $branch and $repository from the list below.
|
||||
alpine.install = To install the package, run the following command:
|
||||
alpine.documentation = For more information on the Alpine registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
|
||||
alpine.repository = Repository Info
|
||||
alpine.repository.branches = Branches
|
||||
alpine.repository.repositories = Repositories
|
||||
alpine.repository.architectures = Architectures
|
||||
cargo.registry = Setup this registry in the Cargo configuration file (for example <code>~/.cargo/config.toml</code>):
|
||||
cargo.install = To install the package using Cargo, run the following command:
|
||||
cargo.documentation = For more information on the Cargo registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
|
||||
@@ -3259,6 +3273,8 @@ debian.repository.components = Components
|
||||
debian.repository.architectures = Architectures
|
||||
generic.download = Download package from the command line:
|
||||
generic.documentation = For more information on the generic registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
|
||||
go.install = Install the package from the command line:
|
||||
go.documentation = For more information on the Go registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
|
||||
helm.registry = Setup this registry from the command line:
|
||||
helm.install = To install the package, run the following command:
|
||||
helm.documentation = For more information on the Helm registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
|
||||
@@ -3415,8 +3431,6 @@ runners.version = Version
|
||||
runners.reset_registration_token_success = Runner registration token reset successfully
|
||||
|
||||
runs.all_workflows = All Workflows
|
||||
runs.open_tab = %d Open
|
||||
runs.closed_tab = %d Closed
|
||||
runs.commit = Commit
|
||||
runs.pushed_by = Pushed by
|
||||
runs.invalid_workflow_helper = Workflow config file is invalid. Please check your config file: %s
|
||||
|
||||
@@ -19,6 +19,7 @@ active_stopwatch=Suivi du temps actif
|
||||
create_new=Créer…
|
||||
user_profile_and_more=Profil et réglages…
|
||||
signed_in_as=Connecté en tant que
|
||||
enable_javascript=Ce site Web nécessite JavaScript.
|
||||
toc=Sommaire
|
||||
licenses=Licences
|
||||
return_to_gitea=Revenir à Gitea
|
||||
@@ -56,6 +57,7 @@ new_mirror=Nouveau miroir
|
||||
new_fork=Nouvelle bifurcation
|
||||
new_org=Nouvelle organisation
|
||||
new_project=Nouveau projet
|
||||
new_project_column=Nouvelle colonne
|
||||
manage_org=Gérer les organisations
|
||||
admin_panel=Administration du site
|
||||
account_settings=Paramètres du compte
|
||||
@@ -82,6 +84,7 @@ add=Ajouter
|
||||
add_all=Tout Ajouter
|
||||
remove=Retirer
|
||||
remove_all=Tout Retirer
|
||||
remove_label_str=Supprimer l’élément « %s »
|
||||
edit=Éditer
|
||||
|
||||
enabled=Activé
|
||||
@@ -89,9 +92,11 @@ disabled=Désactivé
|
||||
|
||||
copy=Copier
|
||||
copy_url=Copier l'URL
|
||||
copy_content=Copier le contenu
|
||||
copy_branch=Copier le nom de la branche
|
||||
copy_success=Copié !
|
||||
copy_error=Échec de la copie
|
||||
copy_type_unsupported=Ce type de fichier ne peut pas être copié
|
||||
|
||||
write=Écrire
|
||||
preview=Aperçu
|
||||
@@ -108,12 +113,36 @@ never=Jamais
|
||||
rss_feed=Flux RSS
|
||||
|
||||
[aria]
|
||||
navbar=Barre de navigation
|
||||
footer=Pied de page
|
||||
footer.software=À propos du logiciel
|
||||
footer.links=Liens
|
||||
|
||||
[heatmap]
|
||||
number_of_contributions_in_the_last_12_months=%s contributions au cours des 12 derniers mois
|
||||
no_contributions=Aucune contribution
|
||||
less=Moins
|
||||
more=Plus
|
||||
|
||||
[editor]
|
||||
buttons.heading.tooltip=Ajouter un en-tête
|
||||
buttons.bold.tooltip=Ajouter du texte en gras
|
||||
buttons.italic.tooltip=Ajouter du texte en italique
|
||||
buttons.quote.tooltip=Citer le texte
|
||||
buttons.code.tooltip=Ajouter du code
|
||||
buttons.link.tooltip=Ajouter un lien
|
||||
buttons.list.unordered.tooltip=Ajouter une liste à puces
|
||||
buttons.list.ordered.tooltip=Ajouter une liste numérotée
|
||||
buttons.list.task.tooltip=Ajouter une liste de tâches
|
||||
buttons.mention.tooltip=Mentionner un utilisateur ou une équipe
|
||||
buttons.ref.tooltip=Référencer un ticket ou demande d’ajout
|
||||
buttons.switch_to_legacy.tooltip=Utiliser l’ancien éditeur à la place
|
||||
buttons.enable_monospace_font=Activer la police à chasse fixe
|
||||
buttons.disable_monospace_font=Désactiver la police à chasse fixe
|
||||
|
||||
[filter]
|
||||
string.asc=A - Z
|
||||
string.desc=Z - A
|
||||
|
||||
[error]
|
||||
occurred=Une erreur s’est produite
|
||||
@@ -212,6 +241,7 @@ openid_signup_popup=Activer l'inscription avec OpenID.
|
||||
enable_captcha=Activer le CAPTCHA d'inscription
|
||||
enable_captcha_popup=Demander un CAPTCHA à l'inscription.
|
||||
require_sign_in_view=Exiger la connexion à un compte pour afficher les pages
|
||||
require_sign_in_view_popup=Limiter l’accès aux pages aux utilisateurs connectés. Les visiteurs ne verront que les pages de connexion et d’inscription.
|
||||
admin_setting_desc=La création d'un compte administrateur est facultative. Le premier utilisateur enregistré deviendra automatiquement un administrateur le cas échéant.
|
||||
admin_title=Paramètres de compte administrateur
|
||||
admin_name=Nom d’utilisateur administrateur
|
||||
@@ -222,6 +252,7 @@ install_btn_confirm=Installer Gitea
|
||||
test_git_failed=Le test de la commande "git" a échoué : %v
|
||||
sqlite3_not_available=Cette version de Gitea ne supporte pas SQLite3. Veuillez télécharger la version binaire officielle de %s (pas la version 'gobuild').
|
||||
invalid_db_setting=Les paramètres de la base de données sont invalides : %v
|
||||
invalid_db_table=La table "%s" de la base de données est invalide : %v
|
||||
invalid_repo_path=Le chemin racine du dépôt est invalide : %v
|
||||
invalid_app_data_path=Le chemin des données de l'application est invalide : %v
|
||||
run_user_not_match=Le nom d'utilisateur sous lequel Gitea est configuré n'est pas le nom d'utilisateur actuel: %s -> %s
|
||||
@@ -239,6 +270,10 @@ default_enable_timetracking_popup=Activer le suivi du temps pour les nouveaux d
|
||||
no_reply_address=Domaine pour les e-mails cachés
|
||||
no_reply_address_helper=Nom de domaine pour les utilisateurs possédant une adresse email cachée. Par exemple, le nom d’utilisateur « joe » sera enregistré dans Git comme « joe@noreply.example.org » si le domaine pour les e-mails cachés a la valeur « noreply.example.org ».
|
||||
password_algorithm=Algorithme de hachage du mot de passe
|
||||
invalid_password_algorithm=Algorithme de hachage du mot de passe invalide
|
||||
password_algorithm_helper=Définissez l’algorithme de hachage du mot de passe. Les algorithmes ont des exigences matérielles et une résistance différentes. L’algorithme argon2 est bien sécurisé mais utilise beaucoup de mémoire et peut être inapproprié pour les systèmes limités en ressources.
|
||||
enable_update_checker=Activer la vérification des mises-à-jour
|
||||
enable_update_checker_helper=Vérifie les mises à jour régulièrement en se connectant à gitea.io.
|
||||
|
||||
[home]
|
||||
uname_holder=Nom d'utilisateur ou adresse e-mail
|
||||
@@ -315,6 +350,7 @@ email_not_associate=L'adresse e-mail n'est associée à aucun compte.
|
||||
send_reset_mail=Envoyer un e-mail de récupération du compte
|
||||
reset_password=Récupération du compte
|
||||
invalid_code=Votre code de confirmation est invalide ou a expiré.
|
||||
invalid_password=Votre mot de passe ne correspond pas à celui utilisé pour créer le compte.
|
||||
reset_password_helper=Récupérer un compte
|
||||
reset_password_wrong_user=Vous êtes connecté en tant que %s, mais le lien de récupération du compte est pour %s
|
||||
password_too_short=Le mot de passe doit contenir %d caractères minimum.
|
||||
@@ -416,10 +452,15 @@ repo.transfer.body=Pour l'accepter ou le rejeter, visitez %s ou ignorez-le.
|
||||
repo.collaborator.added.subject=%s vous a ajouté à %s
|
||||
repo.collaborator.added.text=Vous avez été ajouté en tant que collaborateur du dépôt :
|
||||
|
||||
team_invite.subject=%[1]s vous a invité à rejoindre l’organisation %[2]s
|
||||
team_invite.text_1=%[1]s vous a invité à rejoindre l’équipe %[2]s dans l’organisation %[3]s.
|
||||
team_invite.text_2=Veuillez cliquer sur le lien suivant pour rejoindre l'équipe :
|
||||
team_invite.text_3=Remarque : Cette invitation était destinée à %[1]s. Si vous n’attendiez pas cette invitation, vous pouvez ignorer cet e-mail.
|
||||
|
||||
[modal]
|
||||
yes=Oui
|
||||
no=Non
|
||||
confirm=Confirmer
|
||||
cancel=Annuler
|
||||
modify=Mettre à jour
|
||||
|
||||
@@ -454,8 +495,10 @@ size_error=` doit être à la taille de %s.`
|
||||
min_size_error=` %s caractères minimum `
|
||||
max_size_error=` %s caractères maximum `
|
||||
email_error=` adresse e-mail invalide `
|
||||
include_error=` doit contenir la sous-chaîne "%s".`
|
||||
glob_pattern_error=` le motif de développement est invalide : %s.`
|
||||
regex_pattern_error=` le motif regex est invalide : %s.`
|
||||
username_error=` ne peut contenir que des caractères alphanumériques ('0-9','a-z','A-Z'), tiret ('-'), tiret de soulignement ('_') et point ('.'). Il ne peut pas commencer ou se finir par des caractères non alphanumériques. Les caractères non alphanumériques consécutifs sont également interdits.`
|
||||
unknown_error=Erreur inconnue :
|
||||
captcha_incorrect=Le code CAPTCHA est incorrect.
|
||||
password_not_match=Les mots de passe ne correspondent pas.
|
||||
@@ -476,6 +519,7 @@ team_name_been_taken=Le nom d'équipe est déjà pris.
|
||||
team_no_units_error=Autoriser l’accès à au moins une section du dépôt.
|
||||
email_been_used=Cette adresse e-mail est déjà utilisée.
|
||||
email_invalid=L'adresse e-mail est invalide.
|
||||
openid_been_used=Adresse OpenID "%s" déjà utilisée.
|
||||
username_password_incorrect=Identifiant ou mot de passe invalide.
|
||||
password_complexity=Le mot de passe ne respecte pas les exigences de complexité:
|
||||
password_lowercase_one=Au moins un caractère minuscule
|
||||
@@ -490,12 +534,18 @@ user_not_exist=Cet utilisateur n'existe pas.
|
||||
team_not_exist=L'équipe n'existe pas.
|
||||
last_org_owner=Vous ne pouvez pas retirer le dernier utilisateur de l’équipe « propriétaires ». Il doit y avoir au moins un propriétaire dans chaque organisation.
|
||||
cannot_add_org_to_team=Une organisation ne peut être ajoutée comme membre d'une équipe.
|
||||
duplicate_invite_to_team=L'utilisateur a déjà été invité en tant que membre de l'équipe.
|
||||
organization_leave_success=Vous avez quitté l'organisation %s avec succès.
|
||||
|
||||
invalid_ssh_key=Impossible de vérifier votre clé SSH : %s
|
||||
invalid_gpg_key=Impossible de vérifier votre clé GPG : %s
|
||||
invalid_ssh_principal=Principal invalide : %s
|
||||
auth_failed=Échec d'authentification : %v
|
||||
|
||||
still_has_org=Votre compte est un membre d’une ou plusieurs organisations, veuillez d’abord les quitter.
|
||||
still_own_packages=Votre compte possède toujours un ou plusieurs paquets, vous devez d’abord les supprimer ou les transférer.
|
||||
org_still_own_repo=Cette organisation possède encore un ou plusieurs dépôts. Vous devez d’abord les supprimer ou les transférer.
|
||||
org_still_own_packages=Cette organisation possède encore un ou plusieurs paquets. Vous devez d’abord les supprimer.
|
||||
|
||||
target_branch_not_exist=La branche cible n'existe pas.
|
||||
|
||||
@@ -515,29 +565,73 @@ unfollow=Ne plus suivre
|
||||
heatmap.loading=Chargement de la Heatmap…
|
||||
user_bio=Biographie
|
||||
disabled_public_activity=Cet utilisateur a désactivé la visibilité publique de l'activité.
|
||||
email_visibility.limited=Votre adresse e-mail est visible pour tous les utilisateurs authentifiés
|
||||
email_visibility.private=Votre adresse e-mail n'est visible que pour vous et les administrateurs
|
||||
|
||||
form.name_reserved=Le nom d’utilisateur "%s" est réservé.
|
||||
form.name_chars_not_allowed=Le nom d'utilisateur "%s" contient des caractères non valides.
|
||||
|
||||
[settings]
|
||||
profile=Profil
|
||||
account=Compte
|
||||
appearance=Apparence
|
||||
password=Mot de passe
|
||||
security=Sécurité
|
||||
avatar=Avatar
|
||||
social=Réseaux Sociaux
|
||||
applications=Applications
|
||||
orgs=Gérer les organisations
|
||||
repos=Dépôts
|
||||
delete=Supprimer le compte
|
||||
twofa=Authentification à deux facteurs
|
||||
account_link=Comptes liés
|
||||
organization=Organisations
|
||||
|
||||
public_profile=Profil public
|
||||
biography_placeholder=Parlez-nous un peu de vous.
|
||||
profile_desc=Votre adresse e-mail sera utilisée pour les notifications et d'autres opérations.
|
||||
full_name=Non Complet
|
||||
website=Site Web
|
||||
location=Localisation
|
||||
update_language_not_found=La langue "%s" n'est pas disponible.
|
||||
update_language_success=La langue a été mise à jour.
|
||||
update_profile_success=Votre profil a été mis à jour.
|
||||
change_username=Votre nom d'utilisateur a été modifié.
|
||||
change_username_prompt=Remarque : changer votre nom d'utilisateur change également l'URL de votre compte.
|
||||
change_username_redirect_prompt=L'ancien nom d'utilisateur sera redirigé jusqu'à ce qu'il soit réclamé.
|
||||
continue=Continuer
|
||||
cancel=Annuler
|
||||
language=Langue
|
||||
ui=Thème
|
||||
hidden_comment_types=Types de commentaires masqués
|
||||
comment_type_group_reference=Référence
|
||||
comment_type_group_milestone=Jalon
|
||||
comment_type_group_assignee=Assigné à
|
||||
comment_type_group_title=Titre
|
||||
comment_type_group_branch=Branche
|
||||
comment_type_group_dependency=Dépendance
|
||||
comment_type_group_project=Projet
|
||||
comment_type_group_issue_ref=Référence du ticket
|
||||
saved_successfully=Vos paramètres ont été enregistrés avec succès.
|
||||
privacy=Confidentialité
|
||||
keep_activity_private=Masquer l'activité de la page de profil
|
||||
keep_activity_private_popup=Rend l'activité visible uniquement pour vous et les administrateurs
|
||||
|
||||
lookup_avatar_by_mail=Rechercher un avatar par adresse e-mail
|
||||
enable_custom_avatar=Utiliser un avatar personnalisé
|
||||
choose_new_avatar=Sélectionner un nouvel avatar
|
||||
delete_current_avatar=Supprimer l'avatar actuel
|
||||
uploaded_avatar_not_a_image=Le fichier téléchargé n'est pas une image.
|
||||
update_avatar_success=Votre avatar a été mis à jour.
|
||||
update_user_avatar_success=L'avatar de l'utilisateur a été mis à jour.
|
||||
|
||||
password_change_disabled=Les mots de passes des comptes utilisateurs externes ne peuvent pas être modifiées depuis l'interface web Gitea.
|
||||
|
||||
primary=Principale
|
||||
activated=Activé
|
||||
delete_email=Exclure
|
||||
openid_deletion_success=L'adresse OpenID a été supprimée.
|
||||
add_new_openid=Ajouter une nouvelle URI OpenID
|
||||
|
||||
gpg_key_verify=Vérifier
|
||||
gpg_token=Jeton
|
||||
@@ -909,6 +1003,7 @@ projects.template.desc_helper=Sélectionnez un modèle de projet pour débuter
|
||||
projects.type.uncategorized=Non catégorisé
|
||||
projects.column.edit_title=Nom
|
||||
projects.column.new_title=Nom
|
||||
projects.column.new=Nouvelle colonne
|
||||
projects.column.color=Couleur
|
||||
projects.open=Ouvrir
|
||||
projects.close=Fermer
|
||||
@@ -982,6 +1077,7 @@ issues.filter_label_exclude=`Utiliser <code>alt</code> + <code>clic/entrée</cod
|
||||
issues.filter_label_no_select=Toutes les étiquettes
|
||||
issues.filter_milestone=Jalon
|
||||
issues.filter_milestone_no_select=Tous les jalons
|
||||
issues.filter_project=Projet
|
||||
issues.filter_project_none=Pas de projet
|
||||
issues.filter_assignee=Assigné
|
||||
issues.filter_assginee_no_select=Toutes les affectations
|
||||
|
||||
@@ -19,6 +19,7 @@ active_stopwatch=Cronômetro ativo
|
||||
create_new=Criar…
|
||||
user_profile_and_more=Perfil e Configurações...
|
||||
signed_in_as=Acessado como
|
||||
enable_javascript=Este site requer JavaScript.
|
||||
toc=Índice
|
||||
licenses=Licenças
|
||||
return_to_gitea=Volte para Gitea
|
||||
@@ -83,6 +84,7 @@ add=Adicionar
|
||||
add_all=Adicionar todos
|
||||
remove=Remover
|
||||
remove_all=Excluir todos
|
||||
remove_label_str=`Remover item "%s"`
|
||||
edit=Editar
|
||||
|
||||
enabled=Habilitado
|
||||
@@ -117,8 +119,25 @@ footer.software=Sobre o Software
|
||||
footer.links=Links
|
||||
|
||||
[heatmap]
|
||||
number_of_contributions_in_the_last_12_months=%s contribuições nos últimos 12 meses
|
||||
no_contributions=Sem contribuições
|
||||
less=Menos
|
||||
more=Mais
|
||||
|
||||
[editor]
|
||||
buttons.heading.tooltip=Adicionar título
|
||||
buttons.bold.tooltip=Adicionar texto em negrito
|
||||
buttons.italic.tooltip=Adicionar texto em itálico
|
||||
buttons.quote.tooltip=Citar texto
|
||||
buttons.code.tooltip=Adicionar código
|
||||
buttons.link.tooltip=Adicionar um link
|
||||
buttons.list.unordered.tooltip=Adicionar uma lista com marcadores
|
||||
buttons.list.ordered.tooltip=Adicionar uma lista numerada
|
||||
buttons.list.task.tooltip=Adicionar uma lista de tarefas
|
||||
buttons.mention.tooltip=Mencionar um usuário ou equipe
|
||||
buttons.switch_to_legacy.tooltip=Em vez disso, usar o editor legado
|
||||
buttons.enable_monospace_font=Habilitar fonte mono espaçada
|
||||
buttons.disable_monospace_font=Desabilitar fonte mono espaçada
|
||||
|
||||
[filter]
|
||||
string.asc=A - Z
|
||||
@@ -231,6 +250,7 @@ install_btn_confirm=Instalar Gitea
|
||||
test_git_failed=Falha ao testar o comando 'git': %v
|
||||
sqlite3_not_available=Esta versão do Gitea não suporta SQLite3. Por favor faça o download da versão binária oficial em %s (não utilize a versão 'gobuild').
|
||||
invalid_db_setting=Configuração de banco de dados está inválida: %v
|
||||
invalid_db_table=A tabela "%s" do banco de dados é inválida: %v
|
||||
invalid_repo_path=A raiz do repositório está inválida: %v
|
||||
invalid_app_data_path=O caminho dos dados do aplicativo é inválido: %v
|
||||
run_user_not_match=O nome de usuário 'Executar como' não é o nome de usuário atual: %s -> %s
|
||||
@@ -249,6 +269,7 @@ no_reply_address=Domínio de e-mail oculto
|
||||
no_reply_address_helper=Nome de domínio para usuários com um endereço de e-mail oculto. Por exemplo, o nome de usuário 'joe' será registrado no Git como 'joe@noreply.example.org' se o domínio de e-mail oculto estiver definido como 'noreply.example.org'.
|
||||
password_algorithm=Algoritmo Hash de Senha
|
||||
invalid_password_algorithm=Algoritmo de hash de senha inválido
|
||||
password_algorithm_helper=Escolha o algoritmo de hash para as senhas. Diferentes algoritmos têm requerimentos e forças diversos. O algoritmo argon2 é bastante seguro, mas usa muita memória e pode ser inapropriado para sistemas com menos recursos.
|
||||
enable_update_checker=Habilitar Verificador de Atualizações
|
||||
enable_update_checker_helper=Procura por novas versões periodicamente conectando-se ao gitea.io.
|
||||
|
||||
@@ -295,6 +316,7 @@ repo_no_results=Nenhum repositório correspondente foi encontrado.
|
||||
user_no_results=Nenhum usuário correspondente foi encontrado.
|
||||
org_no_results=Nenhuma organização correspondente foi encontrada.
|
||||
code_no_results=Nenhum código-fonte correspondente ao seu termo de pesquisa foi encontrado.
|
||||
code_search_results=`Resultados da pesquisa por: "%s"`
|
||||
code_last_indexed_at=Última indexação %s
|
||||
relevant_repositories_tooltip=Repositórios que são forks ou que não possuem tópico, nem ícone e nem descrição estão ocultos.
|
||||
relevant_repositories=Apenas repositórios relevantes estão sendo mostrados, <a href="%s">mostrar resultados não filtrados</a>.
|
||||
@@ -472,6 +494,8 @@ size_error=`deve ser do tamanho %s.`
|
||||
min_size_error=` deve conter pelo menos %s caracteres.`
|
||||
max_size_error=` deve conter no máximo %s caracteres.`
|
||||
email_error=` não é um endereço de e-mail válido.`
|
||||
url_error= `"%s" não é um URL válido.`
|
||||
include_error=` deve conter "%s".`
|
||||
glob_pattern_error=` padrão glob é inválido: %s.`
|
||||
regex_pattern_error=` o regex é inválido: %s.`
|
||||
username_error=` só pode conter caracteres alfanuméricos ('0-9','a-z','A-Z'), traço ('-'), sublinhado ('_') e ponto ('.'). Não pode começar ou terminar com caracteres não alfanuméricos, e caracteres não-alfanuméricos consecutivos também são proibidos.`
|
||||
@@ -496,6 +520,7 @@ team_name_been_taken=O nome da equipe já está sendo usado.
|
||||
team_no_units_error=Permitir acesso a pelo menos uma seção de repositório.
|
||||
email_been_used=Este endereço de e-mail já está sendo usado.
|
||||
email_invalid=O endereço de email é inválido.
|
||||
openid_been_used=O endereço OpenID "%s" já está sendo usado.
|
||||
username_password_incorrect=Nome de usuário ou senha incorretos.
|
||||
password_complexity=A senha não passa pelos requisitos de complexidade:
|
||||
password_lowercase_one=Pelo menos um caractere minúsculo
|
||||
@@ -517,8 +542,12 @@ invalid_ssh_key=Não é possível verificar sua chave SSH: %s
|
||||
invalid_gpg_key=Não é possível verificar sua chave GPG: %s
|
||||
invalid_ssh_principal=Nome principal inválido: %s
|
||||
must_use_public_key=A chave que você forneceu é uma chave privada. Por favor, não envie sua chave privada em nenhum lugar. Use sua chave pública em vez disso.
|
||||
unable_verify_ssh_key=Não é possível verificar a chave SSH, verifique se há erros.
|
||||
auth_failed=Autenticação falhou: %v
|
||||
|
||||
still_own_repo=Sua conta possui um ou mais repositórios, exclua ou transfira-os primeiro.
|
||||
still_has_org=Sua conta é um membro de uma ou mais organizações, deixe-as primeiro.
|
||||
still_own_packages=Sua conta possui um ou mais pacotes, exclua-os primeiro.
|
||||
|
||||
target_branch_not_exist=O branch de destino não existe.
|
||||
|
||||
@@ -538,7 +567,12 @@ unfollow=Deixar de seguir
|
||||
heatmap.loading=Carregando mapa de calor...
|
||||
user_bio=Biografia
|
||||
disabled_public_activity=Este usuário desativou a visibilidade pública da atividade.
|
||||
email_visibility.limited=Seu endereço de e-mail está visível para todos os usuários autenticados
|
||||
email_visibility.private=Seu endereço de e-mail é visível apenas para você e administradores
|
||||
|
||||
form.name_reserved=O nome de usuário "%s" está reservado.
|
||||
form.name_pattern_not_allowed=O padrão de "%s" não é permitido em um nome de usuário.
|
||||
form.name_chars_not_allowed=Nome de usuário "%s" contém caracteres inválidos.
|
||||
|
||||
[settings]
|
||||
profile=Perfil
|
||||
@@ -569,6 +603,7 @@ location=Localização
|
||||
update_theme=Atualizar o tema
|
||||
update_profile=Atualizar o perfil
|
||||
update_language=Atualizar Idioma
|
||||
update_language_not_found=Idioma "%s" não está disponível.
|
||||
update_language_success=O idioma foi atualizado.
|
||||
update_profile_success=Seu perfil foi atualizado.
|
||||
change_username=Seu nome de usuário foi alterado.
|
||||
@@ -821,6 +856,7 @@ email_notifications.andyourown=E Suas Próprias Notificações
|
||||
|
||||
visibility=Visibilidade do usuário
|
||||
visibility.public=Pública
|
||||
visibility.public_tooltip=Visível para todos
|
||||
visibility.limited=Limitada
|
||||
visibility.private=Privada
|
||||
visibility.private_tooltip=Visível apenas para membros da organização
|
||||
@@ -2203,6 +2239,8 @@ diff.image.side_by_side=Lado a Lado
|
||||
diff.image.swipe=Deslizar
|
||||
diff.image.overlay=Sobrepor
|
||||
diff.has_escaped=Essa linha tem caracteres Unicode ocultos
|
||||
diff.show_file_tree=Mostrar árvore de arquivos
|
||||
diff.hide_file_tree=Ocultar árvore de arquivos
|
||||
|
||||
releases.desc=Acompanhe as versões e downloads do projeto.
|
||||
release.releases=Versões
|
||||
@@ -2216,6 +2254,7 @@ release.compare=Comparar
|
||||
release.edit=editar
|
||||
release.ahead.commits=<strong>%d</strong> commits
|
||||
release.ahead.target=para %s desde esta versão
|
||||
tag.ahead.target=para %s desde esta tag
|
||||
release.source_code=Código fonte
|
||||
release.new_subheader=Lançamentos organizam versões do projeto.
|
||||
release.edit_subheader=Lançamentos organizam versões do projeto.
|
||||
@@ -2224,6 +2263,9 @@ release.target=Destino
|
||||
release.tag_helper=Escolha uma tag existente, ou crie uma nova tag.
|
||||
release.tag_helper_new=Nova tag. Esta tag será criada a partir do alvo.
|
||||
release.tag_helper_existing=Tag existente.
|
||||
release.title=Título da versão
|
||||
release.title_empty=O título não pode estar em branco.
|
||||
release.message=Descreva esta versão
|
||||
release.prerelease_desc=Marcar como pré-lançamento
|
||||
release.prerelease_helper=Marcar esta versão como inadequada para uso em produção.
|
||||
release.cancel=Cancelar
|
||||
@@ -2250,7 +2292,9 @@ release.tags_for=Tags para %s
|
||||
|
||||
branch.name=Nome do Branch
|
||||
branch.search=Pesquisar branches
|
||||
branch.already_exists=Um branch com o nome "%s" já existe.
|
||||
branch.delete_head=Excluir
|
||||
branch.delete=`Excluir branch "%s"`
|
||||
branch.delete_html=Excluir Branch
|
||||
branch.delete_desc=A exclusão de um branch é permanente. Isto <strong>NÃO PODERÁ</strong> ser desfeito. Continuar?
|
||||
branch.create_branch=Criar branch <strong>%s</strong>
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
"name": "gitea",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@citation-js/core": "0.6.5",
|
||||
"@citation-js/plugin-bibtex": "0.6.6",
|
||||
"@citation-js/plugin-csl": "0.6.7",
|
||||
"@citation-js/core": "0.6.8",
|
||||
"@citation-js/plugin-bibtex": "0.6.8",
|
||||
"@citation-js/plugin-csl": "0.6.8",
|
||||
"@citation-js/plugin-software-formats": "0.6.1",
|
||||
"@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",
|
||||
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
|
||||
"@primer/octicons": "18.3.0",
|
||||
"@vue/compiler-sfc": "3.2.47",
|
||||
"@primer/octicons": "19.1.0",
|
||||
"@vue/compiler-sfc": "3.3.2",
|
||||
"@webcomponents/custom-elements": "1.6.0",
|
||||
"add-asset-webpack-plugin": "2.0.1",
|
||||
"ansi-to-html": "0.7.2",
|
||||
@@ -29,7 +29,7 @@
|
||||
"esbuild-loader": "3.0.1",
|
||||
"escape-goat": "4.0.0",
|
||||
"fast-glob": "3.2.12",
|
||||
"jquery": "3.6.4",
|
||||
"jquery": "3.7.0",
|
||||
"jquery.are-you-sure": "1.9.0",
|
||||
"katex": "0.16.7",
|
||||
"license-checker-webpack-plugin": "0.2.1",
|
||||
@@ -44,30 +44,32 @@
|
||||
"tippy.js": "6.3.7",
|
||||
"tributejs": "5.1.3",
|
||||
"uint8-to-base64": "0.2.0",
|
||||
"vue": "3.2.47",
|
||||
"vue": "3.3.2",
|
||||
"vue-bar-graph": "2.0.0",
|
||||
"vue-loader": "17.1.0",
|
||||
"vue-loader": "17.1.1",
|
||||
"vue3-calendar-heatmap": "2.0.5",
|
||||
"webpack": "5.82.0",
|
||||
"webpack-cli": "5.1.0",
|
||||
"webpack": "5.82.1",
|
||||
"webpack-cli": "5.1.1",
|
||||
"workbox-routing": "6.5.4",
|
||||
"workbox-strategies": "6.5.4",
|
||||
"wrap-ansi": "8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint-community/eslint-plugin-eslint-comments": "3.2.1",
|
||||
"@playwright/test": "1.33.0",
|
||||
"@rollup/pluginutils": "5.0.2",
|
||||
"@stoplight/spectral-cli": "6.6.0",
|
||||
"@vitejs/plugin-vue": "4.2.1",
|
||||
"@vitejs/plugin-vue": "4.2.3",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-plugin-custom-elements": "0.0.8",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jquery": "1.5.1",
|
||||
"eslint-plugin-no-jquery": "2.7.0",
|
||||
"eslint-plugin-regexp": "1.14.0",
|
||||
"eslint-plugin-regexp": "1.15.0",
|
||||
"eslint-plugin-sonarjs": "0.19.0",
|
||||
"eslint-plugin-unicorn": "47.0.0",
|
||||
"eslint-plugin-vue": "9.11.1",
|
||||
"eslint-plugin-vue": "9.12.0",
|
||||
"eslint-plugin-wc": "1.5.0",
|
||||
"jsdom": "22.0.0",
|
||||
"markdownlint-cli": "0.34.0",
|
||||
"stylelint": "15.6.1",
|
||||
@@ -81,9 +83,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@asyncapi/specs": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-4.2.1.tgz",
|
||||
"integrity": "sha512-NeOgMxl1J00PbsmStbDFE6OVA6rE5S3xv0Twm70MwMigsE28hdG9iH/+2SrMBeD/NFKVlryHcEuLtAPoqiCCFg==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-4.3.1.tgz",
|
||||
"integrity": "sha512-EfexhJu/lwF8OdQDm28NKLJHFkx0Gb6O+rcezhZYLPIoNYKXJMh2J1vFGpwmfAcTTh+ffK44Oc2Hs1Q4sLBp+A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.11"
|
||||
@@ -223,9 +225,9 @@
|
||||
"integrity": "sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg=="
|
||||
},
|
||||
"node_modules/@citation-js/core": {
|
||||
"version": "0.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.6.5.tgz",
|
||||
"integrity": "sha512-YmfL3wby/oLgggs3hqRcllL0xYOUzTaABChTEEbcfXwrvIstgHzODG1tcPAVg/EVuVH151uMR9xttuzu+Lbxcg==",
|
||||
"version": "0.6.8",
|
||||
"resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.6.8.tgz",
|
||||
"integrity": "sha512-EqnEj+0OR9t0pU0d/CQ4TKNSxxALTSm5gXxg56dQ2nnod9esIwNVDWztX5LXstiHj7k8VjUSo/TZw7O2AXFdBQ==",
|
||||
"dependencies": {
|
||||
"@citation-js/date": "^0.5.0",
|
||||
"@citation-js/name": "^0.4.2",
|
||||
@@ -253,9 +255,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@citation-js/plugin-bibtex": {
|
||||
"version": "0.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.6.6.tgz",
|
||||
"integrity": "sha512-hDcMK+e+WaA8f3b+SkIVB+41w39Yf3AVGQ6Ee1amC4KCF5kS6IoiAC5dUquCZoaJCrh5PEg1fyX2tuii6WkOhA==",
|
||||
"version": "0.6.8",
|
||||
"resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.6.8.tgz",
|
||||
"integrity": "sha512-ERCHi4TTZ/8TM/Y6lul/pcLHfMltcZqn0BrATCXwVrndwXdUfj8Z6bQdXgaOAhHjo7ngp9T0DC7skgofEGBSTA==",
|
||||
"dependencies": {
|
||||
"@citation-js/date": "^0.5.0",
|
||||
"@citation-js/name": "^0.4.2",
|
||||
@@ -281,9 +283,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@citation-js/plugin-csl": {
|
||||
"version": "0.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.7.tgz",
|
||||
"integrity": "sha512-cgMCaujDaSnYPHmmyk5vp7UTVmEEkToqh1gFH5OGUOlLOaFmRTQn8kssMrVQR/mBZlQmMeoh5NYVktNeo5eDCg==",
|
||||
"version": "0.6.8",
|
||||
"resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.8.tgz",
|
||||
"integrity": "sha512-X3cTCKWvhD580YSVcS55XhwVgPppzDIiaYgiJopAa/MAvzogt1ODqy6dbBPtb07ttdVQm8VG8FHRD2LsGViTGg==",
|
||||
"dependencies": {
|
||||
"@citation-js/date": "^0.5.0",
|
||||
"citeproc": "^2.4.6"
|
||||
@@ -765,6 +767,31 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-plugin-eslint-comments": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.1.tgz",
|
||||
"integrity": "sha512-/HZbjIGaVO2zLlWX3gRgiHmKRVvvqrC0zVu3eXnIj1ORxoyfGSj50l0PfDfqihyZAqrDYzSMdJesXzFjvAoiLQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"ignore": "^5.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=4.19.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-plugin-eslint-comments/node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
||||
@@ -1174,9 +1201,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@primer/octicons": {
|
||||
"version": "18.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-18.3.0.tgz",
|
||||
"integrity": "sha512-vyUej5rKjXfqHAmYSo2k3pA9IsL5KJaYOBVXvc188FwBfUweA+WVP3qwWyZTSQnp9LK6yOajGyr0SCMIa9ombw==",
|
||||
"version": "19.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-19.1.0.tgz",
|
||||
"integrity": "sha512-5o90F89gNPnAk1qfzl3hb/TcsUjk5g0WFI+fBRHLkBKzB3uc9EvxTpgzjXhhjyriOkrBOjFo58D0sjtwttaQww==",
|
||||
"dependencies": {
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
@@ -1630,9 +1657,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stoplight/types": {
|
||||
"version": "13.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.14.0.tgz",
|
||||
"integrity": "sha512-RqF5Cyl5227fRPIaWa5ptMvAtNUIM4yCzSUoERUXAarxpTcOrjMJ52p9lV9XrQtpLhLNMrWn08+h0ap10R22ig==",
|
||||
"version": "13.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.15.0.tgz",
|
||||
"integrity": "sha512-pBLjVRrWGVd+KzTbL3qrmufSKIEp0UfziDBdt/nrTHPKrlrtVwaHdrrQMcpM23yJDU1Wcg4cHvhIuGtKCT5OmA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.4",
|
||||
@@ -1764,9 +1791,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.1.tgz",
|
||||
"integrity": "sha512-uKBEevTNb+l6/aCQaKVnUModfEMjAl98lw2Si9P5y4hLu9tm6AlX2ZIoXZX6Wh9lJueYPrGPKk5WMCNHg/u6/A=="
|
||||
"version": "20.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.3.tgz",
|
||||
"integrity": "sha512-NP2yfZpgmf2eDRPmgGq+fjGjSwFgYbihA8/gK+ey23qT9RkxsgNTZvGOEpXgzIGqesTYkElELLgtKoMQTys5vA=="
|
||||
},
|
||||
"node_modules/@types/normalize-package-data": {
|
||||
"version": "2.4.1",
|
||||
@@ -1809,9 +1836,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vitejs/plugin-vue": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.2.1.tgz",
|
||||
"integrity": "sha512-ZTZjzo7bmxTRTkb8GSTwkPOYDIP7pwuyV+RV53c9PYUouwcbkIZIvWvNWlX2b1dYZqtOv7D6iUAnJLVNGcLrSw==",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz",
|
||||
"integrity": "sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
@@ -1930,240 +1957,257 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz",
|
||||
"integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.2.tgz",
|
||||
"integrity": "sha512-CKZWo1dzsQYTNTft7whzjL0HsrEpMfiK7pjZ2WFE3bC1NA7caUjWioHSK+49y/LK7Bsm4poJZzAMnvZMQ7OTeg==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.16.4",
|
||||
"@vue/shared": "3.2.47",
|
||||
"@babel/parser": "^7.21.3",
|
||||
"@vue/shared": "3.3.2",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map": "^0.6.1"
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz",
|
||||
"integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.2.tgz",
|
||||
"integrity": "sha512-6gS3auANuKXLw0XH6QxkWqyPYPunziS2xb6VRenM3JY7gVfZcJvkCBHkb5RuNY1FCbBO3lkIi0CdXUCW1c7SXw==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.2.47",
|
||||
"@vue/shared": "3.2.47"
|
||||
"@vue/compiler-core": "3.3.2",
|
||||
"@vue/shared": "3.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz",
|
||||
"integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.2.tgz",
|
||||
"integrity": "sha512-jG4jQy28H4BqzEKsQqqW65BZgmo3vzdLHTBjF+35RwtDdlFE+Fk1VWJYUnDMMqkFBo6Ye1ltSKVOMPgkzYj7SQ==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.16.4",
|
||||
"@vue/compiler-core": "3.2.47",
|
||||
"@vue/compiler-dom": "3.2.47",
|
||||
"@vue/compiler-ssr": "3.2.47",
|
||||
"@vue/reactivity-transform": "3.2.47",
|
||||
"@vue/shared": "3.2.47",
|
||||
"@babel/parser": "^7.20.15",
|
||||
"@vue/compiler-core": "3.3.2",
|
||||
"@vue/compiler-dom": "3.3.2",
|
||||
"@vue/compiler-ssr": "3.3.2",
|
||||
"@vue/reactivity-transform": "3.3.2",
|
||||
"@vue/shared": "3.3.2",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.25.7",
|
||||
"magic-string": "^0.30.0",
|
||||
"postcss": "^8.1.10",
|
||||
"source-map": "^0.6.1"
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc/node_modules/magic-string": {
|
||||
"version": "0.30.0",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz",
|
||||
"integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz",
|
||||
"integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.2.tgz",
|
||||
"integrity": "sha512-K8OfY5FQtZaSOJHHe8xhEfIfLrefL/Y9frv4k4NsyQL3+0lRKxr9QuJhfdBDjkl7Fhz8CzKh63mULvmOfx3l2w==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.2.47",
|
||||
"@vue/shared": "3.2.47"
|
||||
"@vue/compiler-dom": "3.3.2",
|
||||
"@vue/shared": "3.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.47.tgz",
|
||||
"integrity": "sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.2.tgz",
|
||||
"integrity": "sha512-yX8C4uTgg2Tdj+512EEMnMKbLveoITl7YdQX35AYgx8vBvQGszKiiCN46g4RY6/deeo/5DLbeUUGxCq1qWMf5g==",
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.2.47"
|
||||
"@vue/shared": "3.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity-transform": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz",
|
||||
"integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.2.tgz",
|
||||
"integrity": "sha512-iu2WaQvlJHdnONrsyv4ibIEnSsuKF+aHFngGj/y1lwpHQtalpVhKg9wsKMoiKXS9zPNjG9mNKzJS9vudvjzvyg==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.16.4",
|
||||
"@vue/compiler-core": "3.2.47",
|
||||
"@vue/shared": "3.2.47",
|
||||
"@babel/parser": "^7.20.15",
|
||||
"@vue/compiler-core": "3.3.2",
|
||||
"@vue/shared": "3.3.2",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.25.7"
|
||||
"magic-string": "^0.30.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity-transform/node_modules/magic-string": {
|
||||
"version": "0.30.0",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz",
|
||||
"integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.47.tgz",
|
||||
"integrity": "sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.2.tgz",
|
||||
"integrity": "sha512-qSl95qj0BvKfcsO+hICqFEoLhJn6++HtsPxmTkkadFbuhe3uQfJ8HmQwvEr7xbxBd2rcJB6XOJg7nWAn/ymC5A==",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.2.47",
|
||||
"@vue/shared": "3.2.47"
|
||||
"@vue/reactivity": "3.3.2",
|
||||
"@vue/shared": "3.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.47.tgz",
|
||||
"integrity": "sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.2.tgz",
|
||||
"integrity": "sha512-+drStsJT+0mtgHdarT7cXZReCcTFfm6ptxMrz0kAW5hms6UNBd8Q1pi4JKlncAhu+Ld/TevsSp7pqAZxBBoGng==",
|
||||
"dependencies": {
|
||||
"@vue/runtime-core": "3.2.47",
|
||||
"@vue/shared": "3.2.47",
|
||||
"csstype": "^2.6.8"
|
||||
"@vue/runtime-core": "3.3.2",
|
||||
"@vue/shared": "3.3.2",
|
||||
"csstype": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom/node_modules/csstype": {
|
||||
"version": "2.6.21",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz",
|
||||
"integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.47.tgz",
|
||||
"integrity": "sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.2.tgz",
|
||||
"integrity": "sha512-QCwh6OGwJg6GDLE0fbQhRTR6tnU+XDJ1iCsTYHXBiezCXAhqMygFRij7BiLF4ytvvHcg5kX9joX5R5vP85++wg==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.2.47",
|
||||
"@vue/shared": "3.2.47"
|
||||
"@vue/compiler-ssr": "3.3.2",
|
||||
"@vue/shared": "3.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.2.47"
|
||||
"vue": "3.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz",
|
||||
"integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ=="
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.2.tgz",
|
||||
"integrity": "sha512-0rFu3h8JbclbnvvKrs7Fe5FNGV9/5X2rPD7KmOzhLSUAiQH5//Hq437Gv0fR5Mev3u/nbtvmLl8XgwCU20/ZfQ=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.5.tgz",
|
||||
"integrity": "sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==",
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
|
||||
"integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/helper-numbers": "1.11.5",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.5"
|
||||
"@webassemblyjs/helper-numbers": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/floating-point-hex-parser": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz",
|
||||
"integrity": "sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ=="
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
|
||||
"integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-api-error": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz",
|
||||
"integrity": "sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA=="
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
|
||||
"integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-buffer": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz",
|
||||
"integrity": "sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg=="
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
|
||||
"integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-numbers": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz",
|
||||
"integrity": "sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA==",
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
|
||||
"integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/floating-point-hex-parser": "1.11.5",
|
||||
"@webassemblyjs/helper-api-error": "1.11.5",
|
||||
"@webassemblyjs/floating-point-hex-parser": "1.11.6",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-wasm-bytecode": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz",
|
||||
"integrity": "sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA=="
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
|
||||
"integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-wasm-section": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz",
|
||||
"integrity": "sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA==",
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
|
||||
"integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.5",
|
||||
"@webassemblyjs/helper-buffer": "1.11.5",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.5",
|
||||
"@webassemblyjs/wasm-gen": "1.11.5"
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ieee754": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz",
|
||||
"integrity": "sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg==",
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
|
||||
"integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
|
||||
"dependencies": {
|
||||
"@xtuc/ieee754": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/leb128": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.5.tgz",
|
||||
"integrity": "sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ==",
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
|
||||
"integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
|
||||
"dependencies": {
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/utf8": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.5.tgz",
|
||||
"integrity": "sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ=="
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
|
||||
"integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-edit": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz",
|
||||
"integrity": "sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ==",
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
|
||||
"integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.5",
|
||||
"@webassemblyjs/helper-buffer": "1.11.5",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.5",
|
||||
"@webassemblyjs/helper-wasm-section": "1.11.5",
|
||||
"@webassemblyjs/wasm-gen": "1.11.5",
|
||||
"@webassemblyjs/wasm-opt": "1.11.5",
|
||||
"@webassemblyjs/wasm-parser": "1.11.5",
|
||||
"@webassemblyjs/wast-printer": "1.11.5"
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-section": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-opt": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6",
|
||||
"@webassemblyjs/wast-printer": "1.11.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-gen": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz",
|
||||
"integrity": "sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA==",
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
|
||||
"integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.5",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.5",
|
||||
"@webassemblyjs/ieee754": "1.11.5",
|
||||
"@webassemblyjs/leb128": "1.11.5",
|
||||
"@webassemblyjs/utf8": "1.11.5"
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
"@webassemblyjs/leb128": "1.11.6",
|
||||
"@webassemblyjs/utf8": "1.11.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-opt": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz",
|
||||
"integrity": "sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw==",
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
|
||||
"integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.5",
|
||||
"@webassemblyjs/helper-buffer": "1.11.5",
|
||||
"@webassemblyjs/wasm-gen": "1.11.5",
|
||||
"@webassemblyjs/wasm-parser": "1.11.5"
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-parser": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz",
|
||||
"integrity": "sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew==",
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
|
||||
"integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.5",
|
||||
"@webassemblyjs/helper-api-error": "1.11.5",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.5",
|
||||
"@webassemblyjs/ieee754": "1.11.5",
|
||||
"@webassemblyjs/leb128": "1.11.5",
|
||||
"@webassemblyjs/utf8": "1.11.5"
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
"@webassemblyjs/leb128": "1.11.6",
|
||||
"@webassemblyjs/utf8": "1.11.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wast-printer": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz",
|
||||
"integrity": "sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA==",
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
|
||||
"integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.5",
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
@@ -2197,9 +2241,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@webpack-cli/serve": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.3.tgz",
|
||||
"integrity": "sha512-Bwxd73pHuYc0cyl7vulPp2I6kAYtmJPkfUivbts7by6wDAVyFdKzGX3AksbvCRyNVFUJu7o2ZTcWXdT90T3qbg==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.4.tgz",
|
||||
"integrity": "sha512-0xRgjgDLdz6G7+vvDLlaRpFatJaJ69uTalZLRSMX5B3VUrDmXcrVA3+6fXXQgmYz7bY9AAgs348XQdmtLsK41A==",
|
||||
"engines": {
|
||||
"node": ">=14.15.0"
|
||||
},
|
||||
@@ -2253,9 +2297,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-import-assertions": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
|
||||
"integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
|
||||
"integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
|
||||
"peerDependencies": {
|
||||
"acorn": "^8"
|
||||
}
|
||||
@@ -4032,9 +4076,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.386",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.386.tgz",
|
||||
"integrity": "sha512-w0VD4WR225nuNsz6FokDaqugxzue6iUVBo8QfUrl2Y6nWHxtBUhjWDnUaG/1v5oWeFPLMJAQk3zKHTHW/P8+Og=="
|
||||
"version": "1.4.392",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.392.tgz",
|
||||
"integrity": "sha512-TXQOMW9tnhIms3jGy/lJctLjICOgyueZFJ1KUtm6DTQ+QpxX3p7ZBwB6syuZ9KBuT5S4XX7bgY1ECPgfxKUdOg=="
|
||||
},
|
||||
"node_modules/elkjs": {
|
||||
"version": "0.8.2",
|
||||
@@ -4064,9 +4108,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.13.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz",
|
||||
"integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==",
|
||||
"version": "5.14.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz",
|
||||
"integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
@@ -4579,9 +4623,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-regexp": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-1.14.0.tgz",
|
||||
"integrity": "sha512-5+bBSsRTTtkSf8+/iNSjiOW6qbjAdGyqv88HxPaBNFKxROK+UAdOGDl5Jr+csV5wW2BuOOvaG82zsvTriQBRFA==",
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-1.15.0.tgz",
|
||||
"integrity": "sha512-YEtQPfdudafU7RBIFci81R/Q1yErm0mVh3BkGnXD2Dk8DLwTFdc2ITYH1wCnHKim2gnHfPFgrkh+b2ozyyU7ag==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
@@ -4646,9 +4690,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue": {
|
||||
"version": "9.11.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.11.1.tgz",
|
||||
"integrity": "sha512-SNtBGDrRkPUFsREswPceqdvZ7YVdWY+iCYiDC+RoxwVieeQ7GJU1FLDlkcaYTOD2os/YuVgI1Fdu8YGM7fmoow==",
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.12.0.tgz",
|
||||
"integrity": "sha512-xH8PgpDW2WwmFSmRfs/3iWogef1CJzQqX264I65zz77jDuxF2yLy7+GA2diUM8ZNATuSl1+UehMQkb5YEyau5w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.3.0",
|
||||
@@ -4666,6 +4710,19 @@
|
||||
"eslint": "^6.2.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-wc": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-1.5.0.tgz",
|
||||
"integrity": "sha512-KFSfiHDol/LeV7U6IX8GdgpGf/s3wG8FTG120Rml/hGNB/DkCuGYQhlf0VgdBdf7gweem8Nlsh5o64HNdj+qPA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-valid-element-name": "^1.0.0",
|
||||
"js-levenshtein-esm": "^1.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=5"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz",
|
||||
@@ -5977,6 +6034,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-valid-element-name": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-valid-element-name/-/is-valid-element-name-1.0.0.tgz",
|
||||
"integrity": "sha512-GZITEJY2LkSjQfaIPBha7eyZv+ge0PhBR7KITeCCWvy7VBQrCUdFkvpI+HrAPQjVtVjy1LvlEkqQTHckoszruw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-potential-custom-element-name": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-weakref": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
|
||||
@@ -6054,9 +6120,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jquery": {
|
||||
"version": "3.6.4",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.4.tgz",
|
||||
"integrity": "sha512-v28EW9DWDFpzcD9O5iyJXg3R3+q+mET5JhnjJzQUZMHOv67bpSIHq81GEYpPNZHG+XXHsfSme3nxp/hndKEcsQ=="
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz",
|
||||
"integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ=="
|
||||
},
|
||||
"node_modules/jquery.are-you-sure": {
|
||||
"version": "1.9.0",
|
||||
@@ -6069,6 +6135,12 @@
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-levenshtein-esm": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/js-levenshtein-esm/-/js-levenshtein-esm-1.2.0.tgz",
|
||||
"integrity": "sha512-fzreKVq1eD7eGcQr7MtRpQH94f8gIfhdrc7yeih38xh684TNMK9v5aAu2wxfIRMk/GpAJRrzcirMAPIaSDaByQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/js-sdsl": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz",
|
||||
@@ -6492,6 +6564,7 @@
|
||||
"version": "0.25.9",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
|
||||
"integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"sourcemap-codec": "^1.4.8"
|
||||
}
|
||||
@@ -6591,9 +6664,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/markdownlint-cli/node_modules/glob": {
|
||||
"version": "10.2.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz",
|
||||
"integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==",
|
||||
"version": "10.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.2.3.tgz",
|
||||
"integrity": "sha512-Kb4rfmBVE3eQTAimgmeqc2LwSnN0wIOkkUL6HmxEFxNJ4fHghYHVbFba/HcGcRjE6s9KoMNK3rSOwkL4PioZjg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
@@ -6909,15 +6982,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mlly": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.2.0.tgz",
|
||||
"integrity": "sha512-+c7A3CV0KGdKcylsI6khWyts/CYrGTrRVo4R/I7u/cUsy0Conxa6LUhiEzVKIw14lc2L5aiO4+SeVe4TeGRKww==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.2.1.tgz",
|
||||
"integrity": "sha512-1aMEByaWgBPEbWV2BOPEMySRrzl7rIHXmQxam4DM8jVjalTQDjpN2ZKOLUrwyhfZQO7IXHml2StcHMhooDeEEQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.8.2",
|
||||
"pathe": "^1.1.0",
|
||||
"pkg-types": "^1.0.2",
|
||||
"ufo": "^1.1.1"
|
||||
"pkg-types": "^1.0.3",
|
||||
"ufo": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/monaco-editor": {
|
||||
@@ -7015,9 +7088,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.10",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.10.tgz",
|
||||
"integrity": "sha512-5YytjUVbwzjE/BX4N62vnPPkGNxlJPwdA9/ArUc4pcM6cYS4Hinuv4VazzwjMGgnWuiQqcemOanib/5PpcsGug==",
|
||||
"version": "2.6.11",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
|
||||
"integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
@@ -7386,12 +7459,12 @@
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
},
|
||||
"node_modules/path-scurry": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz",
|
||||
"integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==",
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.8.0.tgz",
|
||||
"integrity": "sha512-IjTrKseM404/UAWA8bBbL3Qp6O2wXkanuIE3seCxBH7ctRuvH1QRawy1N3nVDHGkdeZsjOsSe/8AQBL/VQCy2g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^9.0.0",
|
||||
"lru-cache": "^9.1.1",
|
||||
"minipass": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -8520,9 +8593,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz",
|
||||
"integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==",
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz",
|
||||
"integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
@@ -8661,7 +8734,8 @@
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
||||
"deprecated": "Please use @jridgewell/sourcemap-codec instead"
|
||||
"deprecated": "Please use @jridgewell/sourcemap-codec instead",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/spdx-compare": {
|
||||
"version": "1.0.0",
|
||||
@@ -9130,9 +9204,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.17.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.17.2.tgz",
|
||||
"integrity": "sha512-1D1aGbOF1Mnayq5PvfMc0amAR1y5Z1nrZaGCvI5xsdEfZEVte8okonk02OiaK5fw5hG1GWuuVsakOnpZW8y25A==",
|
||||
"version": "5.17.3",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.17.3.tgz",
|
||||
"integrity": "sha512-AudpAZKmZHkG9jueayypz4duuCFJMMNGRMwaPvQKWfxKedh8Z2x3OCoDqIIi1xx5+iwx1u6Au8XQcc9Lke65Yg==",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.2",
|
||||
"acorn": "^8.5.0",
|
||||
@@ -9678,9 +9752,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite/node_modules/rollup": {
|
||||
"version": "3.21.5",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.5.tgz",
|
||||
"integrity": "sha512-a4NTKS4u9PusbUJcfF4IMxuqjFzjm6ifj76P54a7cKnvVzJaG12BLVR+hgU2YDGHzyMMQNxLAZWuALsn8q2oQg==",
|
||||
"version": "3.21.6",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.6.tgz",
|
||||
"integrity": "sha512-SXIICxvxQxR3D4dp/3LDHZIJPC8a4anKMHd4E3Jiz2/JnY+2bEjqrOokAauc5ShGVNFHlEFjBXAXlaxkJqIqSg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
@@ -9784,9 +9858,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vm2": {
|
||||
"version": "3.9.17",
|
||||
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.17.tgz",
|
||||
"integrity": "sha512-AqwtCnZ/ERcX+AVj9vUsphY56YANXxRuqMb7GsDtAr0m0PcQX3u0Aj3KWiXM0YAHy7i6JEeHrwOnwXbGYgRpAw==",
|
||||
"version": "3.9.18",
|
||||
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.18.tgz",
|
||||
"integrity": "sha512-iM7PchOElv6Uv6Q+0Hq7dcgDtWWT6SizYqVcvol+1WQc+E9HlgTCnPozbQNSP3yDV9oXHQOEQu530w2q/BCVZg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.7.0",
|
||||
@@ -9800,15 +9874,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.2.47",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.2.47.tgz",
|
||||
"integrity": "sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.2.tgz",
|
||||
"integrity": "sha512-98hJcAhyDwZoOo2flAQBSPVYG/o0HA9ivIy2ktHshjE+6/q8IMQ+kvDKQzOZTFPxvnNMcGM+zS2A00xeZMA7tA==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.2.47",
|
||||
"@vue/compiler-sfc": "3.2.47",
|
||||
"@vue/runtime-dom": "3.2.47",
|
||||
"@vue/server-renderer": "3.2.47",
|
||||
"@vue/shared": "3.2.47"
|
||||
"@vue/compiler-dom": "3.3.2",
|
||||
"@vue/compiler-sfc": "3.3.2",
|
||||
"@vue/runtime-dom": "3.3.2",
|
||||
"@vue/server-renderer": "3.3.2",
|
||||
"@vue/shared": "3.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-bar-graph": {
|
||||
@@ -9845,9 +9919,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-loader": {
|
||||
"version": "17.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.1.0.tgz",
|
||||
"integrity": "sha512-zAjrT+TNWTpgRODxqDfzbDyvuTf5kCP9xmMk8aspQKuYNnTY2r0XK/bHu1DKLpSpk0I6fkQph5OLKB7HcRIPZw==",
|
||||
"version": "17.1.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.1.1.tgz",
|
||||
"integrity": "sha512-qpqEVkKdrAsgyIBMHaiXurDeCuBWqRyKqg2GI4aG3NbggEls+BLqTZdqahbJJh7fm83sz+iz3gg6eDWdbNlG7Q==",
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
@@ -9916,9 +9990,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.82.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.0.tgz",
|
||||
"integrity": "sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg==",
|
||||
"version": "5.82.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.1.tgz",
|
||||
"integrity": "sha512-C6uiGQJ+Gt4RyHXXYt+v9f+SN1v83x68URwgxNQ98cvH8kxiuywWGP4XeNZ1paOzZ63aY3cTciCEQJNFUljlLw==",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.0",
|
||||
@@ -9929,7 +10003,7 @@
|
||||
"acorn-import-assertions": "^1.7.6",
|
||||
"browserslist": "^4.14.5",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.13.0",
|
||||
"enhanced-resolve": "^5.14.0",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
@@ -9962,14 +10036,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-cli": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.0.tgz",
|
||||
"integrity": "sha512-a7KRJnCxejFoDpYTOwzm5o21ZXMaNqtRlvS183XzGDUPRdVEzJNImcQokqYZ8BNTnk9DkKiuWxw75+DCCoZ26w==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.1.tgz",
|
||||
"integrity": "sha512-OLJwVMoXnXYH2ncNGU8gxVpUtm3ybvdioiTvHgUyBuyMLKiVvWy+QObzBsMtp5pH7qQoEuWgeEUQ/sU3ZJFzAw==",
|
||||
"dependencies": {
|
||||
"@discoveryjs/json-ext": "^0.5.0",
|
||||
"@webpack-cli/configtest": "^2.1.0",
|
||||
"@webpack-cli/info": "^2.0.1",
|
||||
"@webpack-cli/serve": "^2.0.3",
|
||||
"@webpack-cli/serve": "^2.0.4",
|
||||
"colorette": "^2.0.14",
|
||||
"commander": "^10.0.1",
|
||||
"cross-spawn": "^7.0.3",
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
"node": ">= 16.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@citation-js/core": "0.6.5",
|
||||
"@citation-js/plugin-bibtex": "0.6.6",
|
||||
"@citation-js/plugin-csl": "0.6.7",
|
||||
"@citation-js/core": "0.6.8",
|
||||
"@citation-js/plugin-bibtex": "0.6.8",
|
||||
"@citation-js/plugin-csl": "0.6.8",
|
||||
"@citation-js/plugin-software-formats": "0.6.1",
|
||||
"@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",
|
||||
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
|
||||
"@primer/octicons": "18.3.0",
|
||||
"@vue/compiler-sfc": "3.2.47",
|
||||
"@primer/octicons": "19.1.0",
|
||||
"@vue/compiler-sfc": "3.3.2",
|
||||
"@webcomponents/custom-elements": "1.6.0",
|
||||
"add-asset-webpack-plugin": "2.0.1",
|
||||
"ansi-to-html": "0.7.2",
|
||||
@@ -29,7 +29,7 @@
|
||||
"esbuild-loader": "3.0.1",
|
||||
"escape-goat": "4.0.0",
|
||||
"fast-glob": "3.2.12",
|
||||
"jquery": "3.6.4",
|
||||
"jquery": "3.7.0",
|
||||
"jquery.are-you-sure": "1.9.0",
|
||||
"katex": "0.16.7",
|
||||
"license-checker-webpack-plugin": "0.2.1",
|
||||
@@ -44,30 +44,32 @@
|
||||
"tippy.js": "6.3.7",
|
||||
"tributejs": "5.1.3",
|
||||
"uint8-to-base64": "0.2.0",
|
||||
"vue": "3.2.47",
|
||||
"vue": "3.3.2",
|
||||
"vue-bar-graph": "2.0.0",
|
||||
"vue-loader": "17.1.0",
|
||||
"vue-loader": "17.1.1",
|
||||
"vue3-calendar-heatmap": "2.0.5",
|
||||
"webpack": "5.82.0",
|
||||
"webpack-cli": "5.1.0",
|
||||
"webpack": "5.82.1",
|
||||
"webpack-cli": "5.1.1",
|
||||
"workbox-routing": "6.5.4",
|
||||
"workbox-strategies": "6.5.4",
|
||||
"wrap-ansi": "8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint-community/eslint-plugin-eslint-comments": "3.2.1",
|
||||
"@playwright/test": "1.33.0",
|
||||
"@rollup/pluginutils": "5.0.2",
|
||||
"@stoplight/spectral-cli": "6.6.0",
|
||||
"@vitejs/plugin-vue": "4.2.1",
|
||||
"@vitejs/plugin-vue": "4.2.3",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-plugin-custom-elements": "0.0.8",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jquery": "1.5.1",
|
||||
"eslint-plugin-no-jquery": "2.7.0",
|
||||
"eslint-plugin-regexp": "1.14.0",
|
||||
"eslint-plugin-regexp": "1.15.0",
|
||||
"eslint-plugin-sonarjs": "0.19.0",
|
||||
"eslint-plugin-unicorn": "47.0.0",
|
||||
"eslint-plugin-vue": "9.11.1",
|
||||
"eslint-plugin-vue": "9.12.0",
|
||||
"eslint-plugin-wc": "1.5.0",
|
||||
"jsdom": "22.0.0",
|
||||
"markdownlint-cli": "0.34.0",
|
||||
"stylelint": "15.6.1",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 186 162" class="svg gitea-alpine" width="16" height="16" aria-hidden="true"><g fill="#0d597f"><path d="M67 100.75V81.125L52.875 95.25a41.588 41.588 0 0 0 4.3 2.637c1.35.71 2.612 1.25 3.787 1.676a21.12 21.12 0 0 0 3.275.887c1.006.184 1.926.266 2.763.278m72.25-1.625c.025.02.163.137.416.298.255.163.628.372 1.123.578.494.205 1.111.409 1.85.56.745.152 1.612.252 2.625.252.838 0 1.762-.073 2.775-.25a20.93 20.93 0 0 0 3.3-.873 29.25 29.25 0 0 0 3.837-1.676 41.805 41.805 0 0 0 4.375-2.674l-10.712-10.5-35.5-35.625-15.625 15.625-21-21.625-52.75 52.125c1.55 1.075 3 1.95 4.362 2.675a28.324 28.324 0 0 0 3.838 1.675c1.189.414 2.287.696 3.3.872 1.012.177 1.937.251 2.775.251 1.005 0 1.875-.1 2.625-.252a9.726 9.726 0 0 0 1.85-.561c.495-.205.866-.414 1.121-.577s.393-.278.418-.3l23.875-23.875 8.512-8.162 23.625 23.625 8.238 8.475c.024.021.162.137.417.299.255.162.626.37 1.121.577.495.205 1.113.409 1.85.56.745.153 1.625.253 2.625.253.838 0 1.763-.074 2.775-.25a20.966 20.966 0 0 0 3.3-.874 29.323 29.323 0 0 0 3.838-1.675 41.805 41.805 0 0 0 4.375-2.675l-18.875-18.5 3.525-3.525 16.375 16.375 9.55 9.462m-.204-98.75 46.5 80.625-46.5 80.625H46.05L-.45 81.066 46.05.441z"/><path d="M110.75 77 98.363 64.625l.88-.886 12.476 12.337z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" class="svg gitea-github" width="16" height="16" aria-hidden="true"><linearGradient id="gitea-github__a" x1="30.999" x2="30.999" y1="16" y2="55.342" gradientUnits="userSpaceOnUse" spreadMethod="reflect"><stop offset="0" stop-color="#6dc7ff"/><stop offset="1" stop-color="#e6abff"/></linearGradient><path fill="url(#gitea-github__a)" d="M25.008 56.007c-.003-.368-.006-1.962-.009-3.454l-.003-1.55c-6.729.915-8.358-3.78-8.376-3.83-.934-2.368-2.211-3.045-2.266-3.073l-.124-.072c-.463-.316-1.691-1.157-1.342-2.263.315-.997 1.536-1.1 2.091-1.082 3.074.215 4.63 2.978 4.694 3.095 1.569 2.689 3.964 2.411 5.509 1.844.144-.688.367-1.32.659-1.878-4.956-.879-10.571-3.515-10.571-13.104 0-2.633.82-4.96 2.441-6.929-.362-1.206-.774-3.666.446-6.765l.174-.442.452-.144c.416-.137 2.688-.624 7.359 2.433a24.959 24.959 0 0 1 6.074-.759c2.115.01 4.158.265 6.09.759 4.667-3.058 6.934-2.565 7.351-2.433l.451.145.174.44c1.225 3.098.813 5.559.451 6.766 1.618 1.963 2.438 4.291 2.438 6.929 0 9.591-5.621 12.219-10.588 13.087.563 1.065.868 2.402.868 3.878 0 1.683-.007 7.204-.015 8.402l-2-.014c.008-1.196.015-6.708.015-8.389 0-2.442-.943-3.522-1.35-3.874l-1.73-1.497 2.274-.253c5.205-.578 10.525-2.379 10.525-11.341 0-2.33-.777-4.361-2.31-6.036l-.43-.469.242-.587c.166-.401.894-2.442-.043-5.291-.758.045-2.568.402-5.584 2.447l-.384.259-.445-.123c-1.863-.518-3.938-.796-6.001-.806-2.052.01-4.124.288-5.984.806l-.445.123-.383-.259c-3.019-2.044-4.833-2.404-5.594-2.449-.935 2.851-.206 4.892-.04 5.293l.242.587-.429.469c-1.536 1.681-2.314 3.712-2.314 6.036 0 8.958 5.31 10.77 10.504 11.361l2.252.256-1.708 1.49c-.372.325-1.03 1.112-1.254 2.727l-.075.549-.506.227c-1.321.592-5.839 2.162-8.548-2.485-.015-.025-.544-.945-1.502-1.557.646.639 1.433 1.673 2.068 3.287.066.19 1.357 3.622 7.28 2.339l1.206-.262.012 3.978c.003 1.487.006 3.076.009 3.444l-1.998.014z"/><linearGradient id="gitea-github__b" x1="32" x2="32" y1="5" y2="59.167" gradientUnits="userSpaceOnUse" spreadMethod="reflect"><stop offset="0" stop-color="#1a6dff"/><stop offset="1" stop-color="#c822ff"/></linearGradient><path fill="url(#gitea-github__b)" d="M32 58C17.663 58 6 46.337 6 32S17.663 6 32 6s26 11.663 26 26-11.663 26-26 26zm0-50C18.767 8 8 18.767 8 32s10.767 24 24 24 24-10.767 24-24S45.233 8 32 8z"/></svg>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" class="svg gitea-gitlab" width="16" height="16" aria-hidden="true"><path fill="#e53935" d="m24 43-8-23h16z"/><path fill="#ff7043" d="m24 43 18-23H32z"/><path fill="#e53935" d="m37 5 5 15H32z"/><path fill="#ffa726" d="m24 43 18-23 3 8z"/><path fill="#ff7043" d="M24 43 6 20h10z"/><path fill="#e53935" d="M11 5 6 20h10z"/><path fill="#ffa726" d="M24 43 6 20l-3 8z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" class="svg gitea-gitlab" width="16" height="16" aria-hidden="true"><path fill="#E24329" d="m31.462 12.779-.045-.115-4.35-11.35a1.137 1.137 0 0 0-.447-.541 1.163 1.163 0 0 0-1.343.071c-.187.15-.322.356-.386.587l-2.94 9.001h-11.9l-2.941-9a1.138 1.138 0 0 0-1.045-.84 1.153 1.153 0 0 0-1.13.72L.579 12.68l-.045.113a8.09 8.09 0 0 0 2.68 9.34l.016.012.038.03 6.635 4.967 3.28 2.484 1.994 1.51a1.35 1.35 0 0 0 1.627 0l1.994-1.51 3.282-2.484 6.673-4.997.018-.013a8.088 8.088 0 0 0 2.69-9.352Z"/><path fill="#FC6D26" d="m31.462 12.779-.045-.115a14.748 14.748 0 0 0-5.856 2.634l-9.553 7.24A11225.6 11225.6 0 0 0 22.1 27.14l6.673-4.997.019-.013a8.09 8.09 0 0 0 2.67-9.352Z"/><path fill="#FCA326" d="m9.908 27.14 3.275 2.485 1.994 1.51a1.35 1.35 0 0 0 1.627 0l1.994-1.51 3.282-2.484s-2.835-2.14-6.092-4.603l-6.08 4.603Z"/><path fill="#FC6D26" d="M6.435 15.305A14.712 14.712 0 0 0 .58 12.672l-.045.113a8.09 8.09 0 0 0 2.68 9.347l.016.012.038.03 6.635 4.967 6.105-4.603-9.573-7.233Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 430 B After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="24.7 77.83 205.42 76.8" class="svg gitea-go" width="16" height="16" aria-hidden="true"><g style="fill:#00acd7"><path d="M40.2 101.1c-.4 0-.5-.2-.3-.5l2.1-2.7c.2-.3.7-.5 1.1-.5h35.7c.4 0 .5.3.3.6l-1.7 2.6c-.2.3-.7.6-1 .6l-36.2-.1zM25.1 110.3c-.4 0-.5-.2-.3-.5l2.1-2.7c.2-.3.7-.5 1.1-.5h45.6c.4 0 .6.3.5.6l-.8 2.4c-.1.4-.5.6-.9.6l-47.3.1zM49.3 119.5c-.4 0-.5-.3-.3-.6l1.4-2.5c.2-.3.6-.6 1-.6h20c.4 0 .6.3.6.7l-.2 2.4c0 .4-.4.7-.7.7l-21.8-.1zM153.1 99.3c-6.3 1.6-10.6 2.8-16.8 4.4-1.5.4-1.6.5-2.9-1-1.5-1.7-2.6-2.8-4.7-3.8-6.3-3.1-12.4-2.2-18.1 1.5-6.8 4.4-10.3 10.9-10.2 19 .1 8 5.6 14.6 13.5 15.7 6.8.9 12.5-1.5 17-6.6.9-1.1 1.7-2.3 2.7-3.7h-19.3c-2.1 0-2.6-1.3-1.9-3 1.3-3.1 3.7-8.3 5.1-10.9.3-.6 1-1.6 2.5-1.6h36.4c-.2 2.7-.2 5.4-.6 8.1-1.1 7.2-3.8 13.8-8.2 19.6-7.2 9.5-16.6 15.4-28.5 17-9.8 1.3-18.9-.6-26.9-6.6-7.4-5.6-11.6-13-12.7-22.2-1.3-10.9 1.9-20.7 8.5-29.3 7.1-9.3 16.5-15.2 28-17.3 9.4-1.7 18.4-.6 26.5 4.9 5.3 3.5 9.1 8.3 11.6 14.1.6.9.2 1.4-1 1.7z"/><path d="M186.2 154.6c-9.1-.2-17.4-2.8-24.4-8.8-5.9-5.1-9.6-11.6-10.8-19.3-1.8-11.3 1.3-21.3 8.1-30.2 7.3-9.6 16.1-14.6 28-16.7 10.2-1.8 19.8-.8 28.5 5.1 7.9 5.4 12.8 12.7 14.1 22.3 1.7 13.5-2.2 24.5-11.5 33.9-6.6 6.7-14.7 10.9-24 12.8-2.7.5-5.4.6-8 .9zm23.8-40.4c-.1-1.3-.1-2.3-.3-3.3-1.8-9.9-10.9-15.5-20.4-13.3-9.3 2.1-15.3 8-17.5 17.4-1.8 7.8 2 15.7 9.2 18.9 5.5 2.4 11 2.1 16.3-.6 7.9-4.1 12.2-10.5 12.7-19.1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 2400 2400" class="svg gitea-openid" width="16" height="16" aria-hidden="true"><path fill="#ff7c00" d="m1270 218.3-173.1 84.3-.7 981.8c-.3 540 .2 981.4 1.1 981l174.5-81.8 172.3-80.8v-984.4c0-541.7-.2-984.7-.4-984.4z"/><path fill="#aaa" d="M981.9 785.5c-425.3 63.2-766.5 264.1-889 523a491.5 491.5 0 0 0-43.6 146c-4.2 29.2-4.7 95-1.2 124 19 152.6 115.2 299.9 273.2 418.8 147.7 111 350.5 196.5 568.6 239.7 59 11.6 179 29 200.5 29 2.3 0 3-23.2 3-109.1v-109.2l-5.1-1-37.9-6a1182 1182 0 0 1-305.4-90.6c-122.2-55.7-225.1-137.7-284.6-226.4-107.5-160.5-81.3-344.3 70-491.3 57-55.5 115.4-95.2 199.5-136.1a1112.6 1112.6 0 0 1 269.4-89.2l29.7-6c3.7-1.2 4-8.6 4-111.5V779.5l-6.3.2a823 823 0 0 0-44.8 5.8zm525 104c0 103 .2 110.4 4.1 111.6l29.5 6a1221.6 1221.6 0 0 1 207.7 61.3A1087.8 1087.8 0 0 1 1862 1123c4.6 3.7 1.4 5.8-88 56-51.1 28.5-93 52.7-93 53.4 0 1.9 671.6 146.8 673.2 145.2 1.2-1.2-45.5-496-47-497.6-.2-.2-38.5 21-85 47.2l-89.6 50.2c-4.2 2-8.8.2-27.9-10.7-130.8-75-289.6-132.2-460.8-166.1a1870.8 1870.8 0 0 0-132.9-21.1c-4 0-4.2 6.7-4.2 110z"/><path fill="#cbaa7c" d="M1094.5 2156.9c0 60.6.3 85.5.5 55 .5-30.2.5-79.9 0-110.3-.2-30.2-.5-5.3-.5 55.3z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="svg octicon-devices" width="16" height="16" aria-hidden="true"><path d="M0 2.75C0 1.784.784 1 1.75 1h12.5c.966 0 1.75.784 1.75 1.75V5a.75.75 0 0 1-1.5 0V2.75a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25H7A.75.75 0 0 1 7 12h-.268a5.712 5.712 0 0 1-.765 2.5H7A.75.75 0 0 1 7 16H4.5a.75.75 0 0 1-.565-1.243c.772-.885 1.193-1.716 1.292-2.757H1.75A1.75 1.75 0 0 1 0 10.25v-7.5Z"/><path d="M10.75 7h3.5c.967 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-5.5C9 7.784 9.783 7 10.75 7Zm-.25 1.75v5.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-3.5a.25.25 0 0 0-.25.25Z"/></svg>
|
||||
|
After Width: | Height: | Size: 722 B |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="svg octicon-move-to-top" width="16" height="16" aria-hidden="true"><path d="M8.53 1.22a.749.749 0 0 0-1.06 0L3.72 4.97a.749.749 0 1 0 1.06 1.06l2.47-2.469v6.689a.75.75 0 0 0 1.5 0V3.561l2.47 2.469a.749.749 0 1 0 1.06-1.06L8.53 1.22ZM3.75 13a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="svg octicon-move-to-top" width="16" height="16" aria-hidden="true"><path d="M3 2.25a.75.75 0 0 1 .75-.75h8.5a.75.75 0 0 1 0 1.5h-8.5A.75.75 0 0 1 3 2.25Zm5.53 2.97 3.75 3.75a.749.749 0 1 1-1.06 1.06L8.75 7.561v6.689a.75.75 0 0 1-1.5 0V7.561L4.78 10.03a.749.749 0 1 1-1.06-1.06l3.75-3.75a.749.749 0 0 1 1.06 0Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 364 B After Width: | Height: | Size: 385 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 16" class="svg octicon-pin-slash" width="16" height="16" aria-hidden="true"><path d="m2.155.595 13.75 13.75a.749.749 0 1 1-1.06 1.06l-3.311-3.31-.14.588c-.317 1.332-1.972 1.8-2.94.832L6.25 11.311 2.28 15.28a.749.749 0 1 1-1.06-1.06l3.969-3.97-2.204-2.204c-.968-.968-.5-2.623.832-2.94l.588-.14-3.31-3.311a.749.749 0 1 1 1.06-1.06Zm8.134 10.254L5.651 6.211l-1.486.354a.25.25 0 0 0-.119.42l2.731 2.732.003.003.003.003 2.732 2.731a.25.25 0 0 0 .42-.119ZM11.794.984l3.722 3.722a1.75 1.75 0 0 1-.504 2.826l-1.627.751a1.25 1.25 0 0 0-.355.247.749.749 0 1 1-1.06-1.06c.228-.228.494-.414.787-.549l1.627-.751a.25.25 0 0 0 .072-.404l-3.722-3.722a.25.25 0 0 0-.404.072l-.751 1.627a2.726 2.726 0 0 1-.549.787.749.749 0 1 1-1.06-1.06 1.25 1.25 0 0 0 .247-.355l.751-1.627a1.75 1.75 0 0 1 2.826-.504Z"/></svg>
|
||||
|
After Width: | Height: | Size: 849 B |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="svg octicon-pin" width="16" height="16" aria-hidden="true"><path d="M4.456.734a1.75 1.75 0 0 1 2.826.504l.613 1.327a3.08 3.08 0 0 0 2.084 1.707l2.454.584c1.332.317 1.8 1.972.832 2.94L11.06 10l3.72 3.72a.748.748 0 0 1-.332 1.265.75.75 0 0 1-.729-.205L10 11.06l-2.204 2.205c-.968.968-2.623.5-2.94-.832l-.584-2.454a3.08 3.08 0 0 0-1.707-2.084l-1.327-.613a1.75 1.75 0 0 1-.504-2.826ZM5.92 1.866a.253.253 0 0 0-.183-.142.251.251 0 0 0-.221.07L1.794 5.516a.251.251 0 0 0-.07.221c.015.08.068.149.142.183l1.328.613A4.582 4.582 0 0 1 5.73 9.63l.584 2.454a.251.251 0 0 0 .42.12l5.47-5.47a.25.25 0 0 0-.12-.42L9.63 5.73a4.583 4.583 0 0 1-3.098-2.537Z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="svg octicon-pin" width="16" height="16" aria-hidden="true"><path d="m11.294.984 3.722 3.722a1.75 1.75 0 0 1-.504 2.826l-1.327.613a3.089 3.089 0 0 0-1.707 2.084l-.584 2.454c-.317 1.332-1.972 1.8-2.94.832L5.75 11.311 1.78 15.28a.749.749 0 1 1-1.06-1.06l3.969-3.97-2.204-2.204c-.968-.968-.5-2.623.832-2.94l2.454-.584a3.08 3.08 0 0 0 2.084-1.707l.613-1.327a1.75 1.75 0 0 1 2.826-.504ZM6.283 9.723l2.732 2.731a.25.25 0 0 0 .42-.119l.584-2.454a4.586 4.586 0 0 1 2.537-3.098l1.328-.613a.25.25 0 0 0 .072-.404l-3.722-3.722a.25.25 0 0 0-.404.072l-.613 1.328a4.584 4.584 0 0 1-3.098 2.537l-2.454.584a.25.25 0 0 0-.119.42l2.731 2.732Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 715 B After Width: | Height: | Size: 699 B |