mirror of https://github.com/go-gitea/gitea.git
Merge branch 'master' into feature-activitypub
This commit is contained in:
commit
07150b33ba
113
.drone.yml
113
.drone.yml
|
@ -25,7 +25,7 @@ steps:
|
|||
- make deps-frontend
|
||||
|
||||
- name: deps-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- make deps-backend
|
||||
|
@ -45,32 +45,41 @@ steps:
|
|||
commands:
|
||||
- make lint-backend
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
depends_on: [deps-backend]
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go
|
||||
|
||||
- name: lint-backend-windows
|
||||
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
|
||||
commands:
|
||||
- make golangci-lint vet
|
||||
- make golangci-lint-windows vet
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
GOOS: windows
|
||||
GOARCH: amd64
|
||||
depends_on: [deps-backend]
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go
|
||||
|
||||
- name: lint-backend-gogit
|
||||
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
|
||||
commands:
|
||||
- make lint-backend
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
depends_on: [deps-backend]
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go
|
||||
|
||||
- name: checks-frontend
|
||||
image: node:16
|
||||
|
@ -79,7 +88,7 @@ steps:
|
|||
depends_on: [deps-frontend]
|
||||
|
||||
- name: checks-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
commands:
|
||||
- make checks-backend
|
||||
depends_on: [deps-backend]
|
||||
|
@ -100,11 +109,11 @@ steps:
|
|||
depends_on: [test-frontend]
|
||||
|
||||
- name: build-backend-no-gcc
|
||||
image: golang:1.16 # this step is kept as the lowest version of golang that we support
|
||||
image: golang:1.17 # this step is kept as the lowest version of golang that we support
|
||||
pull: always
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
commands:
|
||||
- go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
|
||||
depends_on: [deps-backend, checks-backend]
|
||||
|
@ -113,10 +122,10 @@ steps:
|
|||
path: /go
|
||||
|
||||
- name: build-backend-arm64
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
GOOS: linux
|
||||
GOARCH: arm64
|
||||
TAGS: bindata gogit
|
||||
|
@ -129,10 +138,10 @@ steps:
|
|||
path: /go
|
||||
|
||||
- name: build-backend-windows
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
GOOS: windows
|
||||
GOARCH: amd64
|
||||
TAGS: bindata gogit
|
||||
|
@ -144,10 +153,10 @@ steps:
|
|||
path: /go
|
||||
|
||||
- name: build-backend-386
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
GOOS: linux
|
||||
GOARCH: 386
|
||||
commands:
|
||||
|
@ -226,6 +235,7 @@ steps:
|
|||
image: docker:git
|
||||
pull: always
|
||||
commands:
|
||||
- git config --global --add safe.directory /drone/src
|
||||
- git fetch --tags --force
|
||||
when:
|
||||
event:
|
||||
|
@ -233,7 +243,7 @@ steps:
|
|||
- pull_request
|
||||
|
||||
- name: deps-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- make deps-backend
|
||||
|
@ -260,7 +270,7 @@ steps:
|
|||
- ./build/test-env-check.sh
|
||||
- make backend
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
depends_on: [deps-backend, prepare-test-env]
|
||||
|
@ -274,7 +284,7 @@ steps:
|
|||
commands:
|
||||
- make unit-test-coverage test-check
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
RACE_ENABLED: true
|
||||
GITHUB_READ_TOKEN:
|
||||
|
@ -290,7 +300,7 @@ steps:
|
|||
commands:
|
||||
- make unit-test-coverage test-check
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
RACE_ENABLED: true
|
||||
GITHUB_READ_TOKEN:
|
||||
|
@ -306,7 +316,7 @@ steps:
|
|||
commands:
|
||||
- make test-mysql-migration integration-test-coverage
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
RACE_ENABLED: true
|
||||
TEST_LDAP: 1
|
||||
|
@ -323,7 +333,7 @@ steps:
|
|||
commands:
|
||||
- timeout -s ABRT 40m make test-mysql8-migration test-mysql8
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
RACE_ENABLED: true
|
||||
TEST_LDAP: 1
|
||||
|
@ -339,7 +349,7 @@ steps:
|
|||
commands:
|
||||
- make test-mssql-migration test-mssql
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
RACE_ENABLED: true
|
||||
TEST_LDAP: 1
|
||||
|
@ -350,11 +360,11 @@ steps:
|
|||
path: /go
|
||||
|
||||
- name: generate-coverage
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
commands:
|
||||
- make coverage
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
depends_on: [unit-test, test-mysql]
|
||||
when:
|
||||
|
@ -418,6 +428,7 @@ steps:
|
|||
image: docker:git
|
||||
pull: always
|
||||
commands:
|
||||
- git config --global --add safe.directory /drone/src
|
||||
- git fetch --tags --force
|
||||
when:
|
||||
event:
|
||||
|
@ -425,7 +436,7 @@ steps:
|
|||
- pull_request
|
||||
|
||||
- name: deps-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- make deps-backend
|
||||
|
@ -446,7 +457,7 @@ steps:
|
|||
- ./build/test-env-check.sh
|
||||
- make backend
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
depends_on: [deps-backend, prepare-test-env]
|
||||
|
@ -460,7 +471,7 @@ steps:
|
|||
commands:
|
||||
- timeout -s ABRT 40m make test-sqlite-migration test-sqlite
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
RACE_ENABLED: true
|
||||
TEST_TAGS: gogit sqlite sqlite_unlock_notify
|
||||
|
@ -476,7 +487,7 @@ steps:
|
|||
commands:
|
||||
- timeout -s ABRT 40m make test-pgsql-migration test-pgsql
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata gogit
|
||||
RACE_ENABLED: true
|
||||
TEST_TAGS: gogit
|
||||
|
@ -567,7 +578,7 @@ trigger:
|
|||
|
||||
steps:
|
||||
- name: download
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- timeout -s ABRT 40m make generate-license generate-gitignore
|
||||
|
@ -619,6 +630,7 @@ steps:
|
|||
image: docker:git
|
||||
pull: always
|
||||
commands:
|
||||
- git config --global --add safe.directory /drone/src
|
||||
- git fetch --tags --force
|
||||
|
||||
- name: deps-frontend
|
||||
|
@ -628,7 +640,7 @@ steps:
|
|||
- make deps-frontend
|
||||
|
||||
- name: deps-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- make deps-backend
|
||||
|
@ -637,14 +649,14 @@ steps:
|
|||
path: /go
|
||||
|
||||
- name: static
|
||||
image: techknowlogick/xgo:go-1.17.x
|
||||
image: techknowlogick/xgo:go-1.18.x
|
||||
pull: always
|
||||
commands:
|
||||
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
|
||||
- export PATH=$PATH:$GOPATH/bin
|
||||
- make release
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
volumes:
|
||||
- name: deps
|
||||
|
@ -737,6 +749,7 @@ steps:
|
|||
image: docker:git
|
||||
pull: always
|
||||
commands:
|
||||
- git config --global --add safe.directory /drone/src
|
||||
- git fetch --tags --force
|
||||
|
||||
- name: deps-frontend
|
||||
|
@ -746,7 +759,7 @@ steps:
|
|||
- make deps-frontend
|
||||
|
||||
- name: deps-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- make deps-backend
|
||||
|
@ -755,14 +768,14 @@ steps:
|
|||
path: /go
|
||||
|
||||
- name: static
|
||||
image: techknowlogick/xgo:go-1.17.x
|
||||
image: techknowlogick/xgo:go-1.18.x
|
||||
pull: always
|
||||
commands:
|
||||
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
|
||||
- export PATH=$PATH:$GOPATH/bin
|
||||
- make release
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
depends_on: [fetch-tags]
|
||||
volumes:
|
||||
|
@ -882,6 +895,7 @@ steps:
|
|||
image: docker:git
|
||||
pull: always
|
||||
commands:
|
||||
- git config --global --add safe.directory /drone/src
|
||||
- git fetch --tags --force
|
||||
|
||||
- name: publish
|
||||
|
@ -892,7 +906,7 @@ steps:
|
|||
auto_tag_suffix: linux-amd64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -910,7 +924,7 @@ steps:
|
|||
auto_tag_suffix: linux-amd64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -945,6 +959,7 @@ steps:
|
|||
image: docker:git
|
||||
pull: always
|
||||
commands:
|
||||
- git config --global --add safe.directory /drone/src
|
||||
- git fetch --tags --force
|
||||
|
||||
- name: publish
|
||||
|
@ -955,7 +970,7 @@ steps:
|
|||
tags: dev-linux-amd64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -973,7 +988,7 @@ steps:
|
|||
tags: dev-linux-amd64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -1007,6 +1022,7 @@ steps:
|
|||
image: docker:git
|
||||
pull: always
|
||||
commands:
|
||||
- git config --global --add safe.directory /drone/src
|
||||
- git fetch --tags --force
|
||||
|
||||
- name: publish
|
||||
|
@ -1017,7 +1033,7 @@ steps:
|
|||
tags: ${DRONE_BRANCH##release/v}-dev-linux-amd64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -1035,7 +1051,7 @@ steps:
|
|||
tags: ${DRONE_BRANCH##release/v}-dev-linux-amd64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -1070,7 +1086,7 @@ steps:
|
|||
repo: gitea/gitea
|
||||
tags: linux-arm64
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
environment:
|
||||
PLUGIN_MIRROR:
|
||||
from_secret: plugin_mirror
|
||||
|
@ -1103,6 +1119,7 @@ steps:
|
|||
image: docker:git
|
||||
pull: always
|
||||
commands:
|
||||
- git config --global --add safe.directory /drone/src
|
||||
- git fetch --tags --force
|
||||
|
||||
- name: publish
|
||||
|
@ -1113,7 +1130,7 @@ steps:
|
|||
auto_tag_suffix: linux-arm64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -1131,7 +1148,7 @@ steps:
|
|||
auto_tag_suffix: linux-arm64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -1166,6 +1183,7 @@ steps:
|
|||
image: docker:git
|
||||
pull: always
|
||||
commands:
|
||||
- git config --global --add safe.directory /drone/src
|
||||
- git fetch --tags --force
|
||||
|
||||
- name: publish
|
||||
|
@ -1176,7 +1194,7 @@ steps:
|
|||
tags: dev-linux-arm64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -1194,7 +1212,7 @@ steps:
|
|||
tags: dev-linux-arm64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -1228,6 +1246,7 @@ steps:
|
|||
image: docker:git
|
||||
pull: always
|
||||
commands:
|
||||
- git config --global --add safe.directory /drone/src
|
||||
- git fetch --tags --force
|
||||
|
||||
- name: publish
|
||||
|
@ -1238,7 +1257,7 @@ steps:
|
|||
tags: ${DRONE_BRANCH##release/v}-dev-linux-arm64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
@ -1256,7 +1275,7 @@ steps:
|
|||
tags: ${DRONE_BRANCH##release/v}-dev-linux-arm64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
|
|
@ -280,7 +280,7 @@ rules:
|
|||
no-unused-expressions: [2]
|
||||
no-unused-labels: [2]
|
||||
no-unused-private-class-members: [2]
|
||||
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, ignoreRestSiblings: false}]
|
||||
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}]
|
||||
no-use-before-define: [2, nofunc]
|
||||
no-useless-backreference: [0]
|
||||
no-useless-call: [2]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
name: Bug Report
|
||||
description: Found something you weren't expecting? Report it here!
|
||||
labels: kind/bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
@ -19,6 +20,13 @@ body:
|
|||
6. In particular it's really important to provide pertinent logs. You must give us DEBUG level logs.
|
||||
Please read https://docs.gitea.io/en-us/logging-configuration/#debugging-problems
|
||||
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below)
|
||||
If you are using a proxy or a CDN (e.g. Cloudflare) in front of Gitea, please disable the proxy/CDN fully and access Gitea directly to confirm the issue still persists without those services.
|
||||
- type: input
|
||||
id: gitea-ver
|
||||
attributes:
|
||||
|
@ -26,6 +34,34 @@ body:
|
|||
description: Gitea version (or commit reference) of your instance
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: can-reproduce
|
||||
attributes:
|
||||
label: Can you reproduce the bug on the Gitea demo site?
|
||||
description: |
|
||||
If so, please provide a URL in the Description field
|
||||
URL of Gitea demo: https://try.gitea.io
|
||||
options:
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
It's really important to provide pertinent logs
|
||||
Please read https://docs.gitea.io/en-us/logging-configuration/#debugging-problems
|
||||
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
|
||||
- type: input
|
||||
id: logs
|
||||
attributes:
|
||||
label: Log Gist
|
||||
description: Please provide a gist URL of your logs, with any sensitive information (e.g. API keys) removed/hidden
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If this issue involves the Web Interface, please provide one or more screenshots
|
||||
- type: input
|
||||
id: git-ver
|
||||
attributes:
|
||||
|
@ -56,38 +92,3 @@ body:
|
|||
- MySQL
|
||||
- MSSQL
|
||||
- SQLite
|
||||
- type: dropdown
|
||||
id: can-reproduce
|
||||
attributes:
|
||||
label: Can you reproduce the bug on the Gitea demo site?
|
||||
description: |
|
||||
If so, please provide a URL in the Description field
|
||||
URL of Gitea demo: https://try.gitea.io
|
||||
options:
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
It's really important to provide pertinent logs
|
||||
Please read https://docs.gitea.io/en-us/logging-configuration/#debugging-problems
|
||||
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
|
||||
- type: input
|
||||
id: logs
|
||||
attributes:
|
||||
label: Log Gist
|
||||
description: Please provide a gist URL of your logs, with any sensitive information (e.g. API keys) removed/hidden
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see above)
|
||||
If you are using a proxy or a CDN (e.g. Cloudflare) in front of Gitea, please disable the proxy/CDN fully and access Gitea directly to confirm the issue still persists without those services.
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If this issue involves the Web Interface, please provide one or more screenshots
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
name: Feature Request
|
||||
description: Got an idea for a feature that Gitea doesn't have currently? Submit your idea here!
|
||||
labels: ["kind/feature", "kind/proposal"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
name: Web Interface Bug Report
|
||||
description: Something doesn't look quite as it should? Report it here!
|
||||
labels: ["kind/bug", "kind/ui"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
@ -18,6 +19,20 @@ body:
|
|||
6. In particular it's really important to provide pertinent logs. If you are certain that this is a javascript
|
||||
error, show us the javascript console. If the error appears to relate to Gitea the server you must also give us
|
||||
DEBUG level logs. (See https://docs.gitea.io/en-us/logging-configuration/#debugging-problems)
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below)
|
||||
If using a proxy or a CDN (e.g. CloudFlare) in front of gitea, please disable the proxy/CDN fully and connect to gitea directly to confirm the issue still persists without those services.
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: Please provide at least 1 screenshot showing the issue.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: gitea-ver
|
||||
attributes:
|
||||
|
@ -25,18 +40,6 @@ body:
|
|||
description: Gitea version (or commit reference) your instance is running
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os-ver
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: The operating system you are using to access Gitea
|
||||
- type: input
|
||||
id: browser-ver
|
||||
attributes:
|
||||
label: Browser Version
|
||||
description: The browser and version that you are using to access Gitea
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: can-reproduce
|
||||
attributes:
|
||||
|
@ -49,17 +52,15 @@ body:
|
|||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
- type: input
|
||||
id: os-ver
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see above)
|
||||
If using a proxy or a CDN (e.g. CloudFlare) in front of gitea, please disable the proxy/CDN fully and connect to gitea directly to confirm the issue still persists without those services.
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
label: Operating System
|
||||
description: The operating system you are using to access Gitea
|
||||
- type: input
|
||||
id: browser-ver
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: Please provide at least 1 screenshot showing the issue.
|
||||
label: Browser Version
|
||||
description: The browser and version that you are using to access Gitea
|
||||
validations:
|
||||
required: true
|
||||
|
|
|
@ -18,12 +18,14 @@ linters:
|
|||
- ineffassign
|
||||
- revive
|
||||
- gofumpt
|
||||
- depguard
|
||||
enable-all: false
|
||||
disable-all: true
|
||||
fast: false
|
||||
|
||||
run:
|
||||
timeout: 3m
|
||||
go: 1.18
|
||||
timeout: 10m
|
||||
skip-dirs:
|
||||
- node_modules
|
||||
- public
|
||||
|
@ -64,7 +66,15 @@ linters-settings:
|
|||
- name: modifies-value-receiver
|
||||
gofumpt:
|
||||
extra-rules: true
|
||||
lang-version: 1.16
|
||||
lang-version: "1.18"
|
||||
depguard:
|
||||
# TODO: use depguard to replace import checks in gitea-vet
|
||||
list-type: denylist
|
||||
# Check the list against standard lib.
|
||||
include-go-root: true
|
||||
packages-with-error-message:
|
||||
- encoding/json: "use gitea's modules/json instead of encoding/json"
|
||||
- github.com/unknwon/com: "use gitea's util and replacements"
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
|
@ -152,3 +162,6 @@ issues:
|
|||
- path: models/user/openid.go
|
||||
linters:
|
||||
- golint
|
||||
- linters:
|
||||
- staticcheck
|
||||
text: "strings.Title is deprecated: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead."
|
||||
|
|
188
CHANGELOG.md
188
CHANGELOG.md
|
@ -4,6 +4,194 @@ This changelog goes through all the changes that have been made in each release
|
|||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.16.7](https://github.com/go-gitea/gitea/releases/tag/v1.16.7) - 2022-05-02
|
||||
|
||||
* SECURITY
|
||||
* Escape git fetch remote (#19487) (#19490)
|
||||
* BUGFIXES
|
||||
* Don't overwrite err with nil (#19572) (#19574)
|
||||
* On Migrations, only write commit-graph if wiki clone was successful (#19563) (#19568)
|
||||
* Respect DefaultUserIsRestricted system default when creating new user (#19310) (#19560)
|
||||
* Don't error when branch's commit doesn't exist (#19547) (#19548)
|
||||
* Support `hostname:port` to pass host matcher's check (#19543) (#19544)
|
||||
* Prevent intermittent race in attribute reader close (#19537) (#19539)
|
||||
* Fix 64-bit atomic operations on 32-bit machines (#19531) (#19532)
|
||||
* Prevent dangling archiver goroutine (#19516) (#19526)
|
||||
* Fix migrate release from github (#19510) (#19523)
|
||||
* When view _Siderbar or _Footer, just display once (#19501) (#19522)
|
||||
* Fix blame page select range error and some typos (#19503)
|
||||
* Fix name of doctor fix "authorized-keys" in hints (#19464) (#19484)
|
||||
* User specific repoID or xorm builder conditions for issue search (#19475) (#19476)
|
||||
* Prevent dangling cat-file calls (goroutine alternative) (#19454) (#19466)
|
||||
* RepoAssignment ensure to close before overwrite (#19449) (#19460)
|
||||
* Set correct PR status on 3way on conflict checking (#19457) (#19458)
|
||||
* Mark TemplateLoading error as "UnprocessableEntity" (#19445) (#19446)
|
||||
|
||||
## [1.16.6](https://github.com/go-gitea/gitea/releases/tag/v1.16.6) - 2022-04-20
|
||||
|
||||
* ENHANCEMENTS
|
||||
* Only request write when necessary (#18657) (#19422)
|
||||
* Disable service worker by default (#18914) (#19342)
|
||||
* BUGFIXES
|
||||
* When dumping trim the standard suffices instead of a random suffix (#19440) (#19447)
|
||||
* Fix DELETE request for non-existent public key (#19443) (#19444)
|
||||
* Don't panic on ErrEmailInvalid (#19441) (#19442)
|
||||
* Add uploadpack.allowAnySHA1InWant to allow --filter=blob:none with older git clients (#19430) (#19438)
|
||||
* Warn on SSH connection for incorrect configuration (#19317) (#19437)
|
||||
* Search Issues via API, dont show 500 if filter result in empty list (#19244) (#19436)
|
||||
* When updating mirror repo intervals by API reschedule next update too (#19429) (#19433)
|
||||
* Fix nil error when some pages are rendered outside request context (#19427) (#19428)
|
||||
* Fix double blob-hunk on diff page (#19404) (#19405)
|
||||
* Don't allow merging PR's which are being conflict checked (#19357) (#19358)
|
||||
* Fix middleware function's placements (#19377) (#19378)
|
||||
* Fix invalid CSRF token bug, make sure CSRF tokens can be up-to-date (#19338)
|
||||
* Restore user autoregistration with email addresses (#19261) (#19312)
|
||||
* Move checks for pulls before merge into own function (#19271) (#19277)
|
||||
* Granular webhook events in editHook (#19251) (#19257)
|
||||
* Only send webhook events to active system webhooks and only deliver to active hooks (#19234) (#19248)
|
||||
* Use full output of git show-ref --tags to get tags for PushUpdateAddTag (#19235) (#19236)
|
||||
* Touch mirrors on even on fail to update (#19217) (#19233)
|
||||
* Hide sensitive content on admin panel progress monitor (#19218 & #19226) (#19231)
|
||||
* Fix clone url JS error for the empty repo page (#19209)
|
||||
* Bump goldmark to v1.4.11 (#19201) (#19203)
|
||||
* TESTING
|
||||
* Prevent intermittent failures in RepoIndexerTest (#19225 #19229) (#19228)
|
||||
* BUILD
|
||||
* Revert the minimal golang version requirement from 1.17 to 1.16 and add a warning in Makefile (#19319)
|
||||
* MISC
|
||||
* Performance improvement for add team user when org has more than 1000 repositories (#19227) (#19289)
|
||||
* Check go and nodejs version by go.mod and package.json (#19197) (#19254)
|
||||
|
||||
## [1.16.5](https://github.com/go-gitea/gitea/releases/tag/v1.16.5) - 2022-03-23
|
||||
|
||||
* BREAKING
|
||||
* Bump to build with go1.18 (#19120 et al) (#19127)
|
||||
* SECURITY
|
||||
* Prevent redirect to Host (2) (#19175) (#19186)
|
||||
* Try to prevent autolinking of displaynames by email readers (#19169) (#19183)
|
||||
* Clean paths when looking in Storage (#19124) (#19179)
|
||||
* Do not send notification emails to inactive users (#19131) (#19139)
|
||||
* Do not send activation email if manual confirm is set (#19119) (#19122)
|
||||
* ENHANCEMENTS
|
||||
* Use the new/choose link for New Issue on project page (#19172) (#19176)
|
||||
* BUGFIXES
|
||||
* Fix showing issues in your repositories (#18916) (#19191)
|
||||
* Fix compare link in active feeds for new branch (#19149) (#19185)
|
||||
* Redirect .wiki/* ui link to /wiki (#18831) (#19184)
|
||||
* Ensure deploy keys with write access can push (#19010) (#19182)
|
||||
* Ensure that setting.LocalURL always has a trailing slash (#19171) (#19177)
|
||||
* Cleanup protected branches when deleting users & teams (#19158) (#19174)
|
||||
* Use IterateBufferSize whilst querying repositories during adoption check (#19140) (#19160)
|
||||
* Fix NPE /repos/issues/search when not signed in (#19154) (#19155)
|
||||
* Use custom favicon when viewing static files if it exists (#19130) (#19152)
|
||||
* Fix the editor height in review box (#19003) (#19147)
|
||||
* Ensure isSSH is set whenever DISABLE_HTTP_GIT is set (#19028) (#19146)
|
||||
* Fix wrong scopes caused by empty scope input (#19029) (#19145)
|
||||
* Make migrations SKIP_TLS_VERIFY apply to git too (#19132) (#19141)
|
||||
* Handle email address not exist (#19089) (#19121)
|
||||
* MISC
|
||||
* Update json-iterator to allow compilation with go1.18 (#18644) (#19100)
|
||||
* Update golang.org/x/crypto (#19097) (#19098)
|
||||
|
||||
## [1.16.4](https://github.com/go-gitea/gitea/releases/tag/v1.16.4) - 2022-03-14
|
||||
|
||||
* SECURITY
|
||||
* Restrict email address validation (#17688) (#19085)
|
||||
* Fix lfs bug (#19072) (#19080)
|
||||
* ENHANCEMENTS
|
||||
* Improve SyncMirrors logging (#19045) (#19050)
|
||||
* BUGFIXES
|
||||
* Refactor mirror code & fix `StartToMirror` (#18904) (#19075)
|
||||
* Update the webauthn_credential_id_sequence in Postgres (#19048) (#19060)
|
||||
* Prevent 500 when there is an error during new auth source post (#19041) (#19059)
|
||||
* If rendering has failed due to a net.OpError stop rendering (attempt 2) (#19049) (#19056)
|
||||
* Fix flag validation (#19046) (#19051)
|
||||
* Add pam account authorization check (#19040) (#19047)
|
||||
* Ignore missing comment for user notifications (#18954) (#19043)
|
||||
* Set `rel="nofollow noindex"` on new issue links (#19023) (#19042)
|
||||
* Upgrading binding package (#19034) (#19035)
|
||||
* Don't show context cancelled errors in attribute reader (#19006) (#19027)
|
||||
* Fix update hint bug (#18996) (#19002)
|
||||
* MISC
|
||||
* Fix potential assignee query for repo (#18994) (#18999)
|
||||
|
||||
## [1.16.3](https://github.com/go-gitea/gitea/releases/tag/v1.16.3) - 2022-03-02
|
||||
|
||||
* SECURITY
|
||||
* Git backend ignore replace objects (#18979) (#18980)
|
||||
* ENHANCEMENTS
|
||||
* Adjust error for already locked db and prevent level db lock on malformed connstr (#18923) (#18938)
|
||||
* BUGFIXES
|
||||
* Set max text height to prevent overflow (#18862) (#18977)
|
||||
* Fix newAttachmentPaths deletion for DeleteRepository() (#18973) (#18974)
|
||||
* Accounts with WebAuthn only (no TOTP) now exist ... fix code to handle that case (#18897) (#18964)
|
||||
* Send 404 on `/{org}.gpg` (#18959) (#18962)
|
||||
* Fix admin user list pagination (#18957) (#18960)
|
||||
* Fix lfs management setting (#18947) (#18946)
|
||||
* Fix login with email panic when email is not exist (#18942)
|
||||
* Update go-org to v1.6.1 (#18932) (#18933)
|
||||
* Fix `<strong>` html in translation (#18929) (#18931)
|
||||
* Fix page and missing return on unadopted repos API (#18848) (#18927)
|
||||
* Allow adminstrator teams members to see other teams (#18918) (#18919)
|
||||
* Don't treat BOM escape sequence as hidden character. (#18909) (#18910)
|
||||
* Correctly link URLs to users/repos with dashes, dots or underscores (… (#18908)
|
||||
* Fix redirect when using lowercase repo name (#18775) (#18902)
|
||||
* Fix migration v210 (#18893) (#18892)
|
||||
* Fix team management UI (#18887) (18886)
|
||||
* BeforeSourcePath should point to base commit (#18880) (#18799)
|
||||
* TRANSLATION
|
||||
* Backport locales from master (#18944)
|
||||
* MISC
|
||||
* Don't update email for organisation (#18905) (#18906)
|
||||
|
||||
## [1.16.2](https://github.com/go-gitea/gitea/releases/tag/v1.16.2) - 2022-02-24
|
||||
|
||||
* ENHANCEMENTS
|
||||
* Show fullname on issue edits and gpg/ssh signing info (#18828)
|
||||
* Immediately Hammer if second kill is sent (#18823) (#18826)
|
||||
* Allow mermaid render error to wrap (#18791)
|
||||
* BUGFIXES
|
||||
* Fix ldap user sync missed email in email_address table (#18786) (#18876)
|
||||
* Update assignees check to include any writing team and change org sidebar (#18680) (#18873)
|
||||
* Don't report signal: killed errors in serviceRPC (#18850) (#18865)
|
||||
* Fix bug where certain LDAP settings were reverted (#18859)
|
||||
* Update go-org to 1.6.0 (#18824) (#18839)
|
||||
* Fix login with email for ldap users (#18800) (#18836)
|
||||
* Fix bug for get user by email (#18834)
|
||||
* Fix panic in EscapeReader (#18820) (#18821)
|
||||
* Fix ldap loginname (#18789) (#18804)
|
||||
* Remove redundant call to UpdateRepoStats during migration (#18591) (#18794)
|
||||
* In disk_channel queues synchronously push to disk on shutdown (#18415) (#18788)
|
||||
* Fix template bug of LFS lock (#18784) (#18787)
|
||||
* Attempt to fix the webauthn migration again - part 3 (#18770) (#18771)
|
||||
* Send mail to issue/pr assignee/reviewer also when OnMention is set (#18707) (#18765)
|
||||
* Fix a broken link in commits_list_small.tmpl (#18763) (#18764)
|
||||
* Increase the size of the webauthn_credential credential_id field (#18739) (#18756)
|
||||
* Prevent dangling GetAttribute calls (#18754) (#18755)
|
||||
* Fix isempty detection of git repository (#18746) (#18750)
|
||||
* Fix source code line highlighting on external tracker (#18729) (#18740)
|
||||
* Prevent double encoding of branch names in delete branch (#18714) (#18738)
|
||||
* Always set PullRequestWorkInProgressPrefixes in PrepareViewPullInfo (#18713) (#18737)
|
||||
* Fix forked repositories missed tags (#18719) (#18735)
|
||||
* Fix release typo (#18728) (#18731)
|
||||
* Separate the details links of commit-statuses in headers (#18661) (#18730)
|
||||
* Update object repo with the migrated repository (#18684) (#18726)
|
||||
* Fix bug for version update hint (#18701) (#18705)
|
||||
* Fix issue with docker-rootless shimming script (#18690) (#18699)
|
||||
* Let `MinUnitAccessMode` return correct perm (#18675) (#18689)
|
||||
* Prevent security failure due to bad APP_ID (#18678) (#18682)
|
||||
* Restart zero worker if there is still work to do (#18658) (#18672)
|
||||
* If rendering has failed due to a net.OpError stop rendering (#18642) (#18645)
|
||||
* TESTING
|
||||
* Ensure git tag tests and others create test repos in tmpdir (#18447) (#18767)
|
||||
* BUILD
|
||||
* Reduce CI go module downloads, add make targets (#18708, #18475, #18443) (#18741)
|
||||
* MISC
|
||||
* Put buttons back in org dashboard (#18817) (#18825)
|
||||
* Various Mermaid improvements (#18776) (#18780)
|
||||
* C preprocessor colors improvement (#18671) (#18696)
|
||||
* Fix the missing i18n key for update checker (#18646) (#18665)
|
||||
|
||||
## [1.16.1](https://github.com/go-gitea/gitea/releases/tag/v1.16.1) - 2022-02-06
|
||||
|
||||
* SECURITY
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#Build stage
|
||||
FROM golang:1.17-alpine3.15 AS build-env
|
||||
FROM golang:1.18-alpine3.15 AS build-env
|
||||
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY ${GOPROXY:-direct}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#Build stage
|
||||
FROM golang:1.17-alpine3.15 AS build-env
|
||||
FROM golang:1.18-alpine3.15 AS build-env
|
||||
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY ${GOPROXY:-direct}
|
||||
|
|
113
Makefile
113
Makefile
|
@ -24,10 +24,17 @@ SHASUM ?= shasum -a 256
|
|||
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
|
||||
COMMA := ,
|
||||
|
||||
XGO_VERSION := go-1.17.x
|
||||
MIN_GO_VERSION := 001016000
|
||||
MIN_NODE_VERSION := 012017000
|
||||
MIN_GOLANGCI_LINT_VERSION := 001044000
|
||||
XGO_VERSION := go-1.18.x
|
||||
|
||||
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.29.0
|
||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.4.0
|
||||
ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.0
|
||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.0
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.2
|
||||
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
|
||||
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
|
||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.29.0
|
||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||
|
||||
DOCKER_IMAGE ?= gitea/gitea
|
||||
DOCKER_TAG ?= latest
|
||||
|
@ -125,8 +132,6 @@ ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
|
|||
GO_SOURCES += $(BINDATA_DEST)
|
||||
endif
|
||||
|
||||
#To update swagger use: GO111MODULE=on go get -u github.com/go-swagger/go-swagger/cmd/swagger
|
||||
SWAGGER := $(GO) run github.com/go-swagger/go-swagger/cmd/swagger
|
||||
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
|
||||
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|g
|
||||
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|"basePath": "/api/v1"|g
|
||||
|
@ -196,9 +201,11 @@ help:
|
|||
|
||||
.PHONY: go-check
|
||||
go-check:
|
||||
$(eval MIN_GO_VERSION_STR := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2))
|
||||
$(eval MIN_GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' ')))
|
||||
$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
|
||||
@if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \
|
||||
echo "Gitea requires Go 1.16 or greater to build. You can get it at https://golang.org/dl/"; \
|
||||
echo "Gitea requires Go $(MIN_GO_VERSION_STR) or greater to build. You can get it at https://go.dev/dl/"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
|
@ -211,11 +218,12 @@ git-check:
|
|||
|
||||
.PHONY: node-check
|
||||
node-check:
|
||||
$(eval MIN_NODE_VERSION_STR := $(shell grep -Eo '"node":.*[0-9.]+"' package.json | sed -n 's/.*[^0-9.]\([0-9.]*\)"/\1/p'))
|
||||
$(eval MIN_NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_NODE_VERSION_STR)' | tr '.' ' ')))
|
||||
$(eval NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v | cut -c2- | tr '.' ' ');))
|
||||
$(eval MIN_NODE_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_NODE_VERSION) | grep -o ...)))
|
||||
$(eval NPM_MISSING := $(shell hash npm > /dev/null 2>&1 || echo 1))
|
||||
@if [ "$(NODE_VERSION)" -lt "$(MIN_NODE_VERSION)" -o "$(NPM_MISSING)" = "1" ]; then \
|
||||
echo "Gitea requires Node.js $(MIN_NODE_VER_FMT) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \
|
||||
echo "Gitea requires Node.js $(MIN_NODE_VERSION_STR) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
|
@ -234,11 +242,8 @@ clean:
|
|||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
@hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install mvdan.cc/gofumpt@v0.3.0; \
|
||||
fi
|
||||
@echo "Running gitea-fmt (with gofumpt)..."
|
||||
@$(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
|
||||
@MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
|
||||
|
||||
.PHONY: vet
|
||||
vet:
|
||||
|
@ -257,7 +262,7 @@ endif
|
|||
|
||||
.PHONY: generate-swagger
|
||||
generate-swagger:
|
||||
$(SWAGGER) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
|
||||
$(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)'
|
||||
|
||||
|
@ -273,24 +278,18 @@ swagger-check: generate-swagger
|
|||
.PHONY: swagger-validate
|
||||
swagger-validate:
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)'
|
||||
$(SWAGGER) validate './$(SWAGGER_SPEC)'
|
||||
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
||||
|
||||
.PHONY: errcheck
|
||||
errcheck:
|
||||
@hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/kisielk/errcheck@8ddee489636a8311a376fc92e27a6a13c6658344; \
|
||||
fi
|
||||
@echo "Running errcheck..."
|
||||
@errcheck $(GO_PACKAGES)
|
||||
$(GO) run $(ERRCHECK_PACKAGE) $(GO_PACKAGES)
|
||||
|
||||
.PHONY: fmt-check
|
||||
fmt-check:
|
||||
@hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install mvdan.cc/gofumpt@0.3.0; \
|
||||
fi
|
||||
# get all go files and run gitea-fmt (with gofmt) on them
|
||||
@diff=$$($(GO) run build/code-batch-process.go gitea-fmt -l '{file-list}'); \
|
||||
@diff=$$(MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -l '{file-list}'); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make fmt' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
|
@ -328,10 +327,7 @@ watch-frontend: node-check node_modules
|
|||
|
||||
.PHONY: watch-backend
|
||||
watch-backend: go-check
|
||||
@hash air > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/cosmtrek/air@bedc18201271882c2be66d216d0e1a275b526ec4; \
|
||||
fi
|
||||
air -c .air.toml
|
||||
$(GO) run $(AIR_PACKAGE) -c .air.toml
|
||||
|
||||
.PHONY: test
|
||||
test: test-frontend test-backend
|
||||
|
@ -611,12 +607,9 @@ $(DIST_DIRS):
|
|||
|
||||
.PHONY: release-windows
|
||||
release-windows: | $(DIST_DIRS)
|
||||
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install src.techknowlogick.com/xgo@latest; \
|
||||
fi
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
ifeq (,$(findstring gogit,$(TAGS)))
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||
endif
|
||||
ifeq ($(CI),drone)
|
||||
cp /build/* $(DIST)/binaries
|
||||
|
@ -624,20 +617,14 @@ endif
|
|||
|
||||
.PHONY: release-linux
|
||||
release-linux: | $(DIST_DIRS)
|
||||
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install src.techknowlogick.com/xgo@latest; \
|
||||
fi
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
||||
ifeq ($(CI),drone)
|
||||
cp /build/* $(DIST)/binaries
|
||||
endif
|
||||
|
||||
.PHONY: release-darwin
|
||||
release-darwin: | $(DIST_DIRS)
|
||||
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install src.techknowlogick.com/xgo@latest; \
|
||||
fi
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
||||
ifeq ($(CI),drone)
|
||||
cp /build/* $(DIST)/binaries
|
||||
endif
|
||||
|
@ -652,17 +639,16 @@ release-check: | $(DIST_DIRS)
|
|||
|
||||
.PHONY: release-compress
|
||||
release-compress: | $(DIST_DIRS)
|
||||
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/ulikunitz/xz/cmd/gxz@v0.5.10; \
|
||||
fi
|
||||
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
|
||||
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && $(GO) run $(GXZ_PAGAGE) -k -9 $${file}; done;
|
||||
|
||||
.PHONY: release-sources
|
||||
release-sources: | $(DIST_DIRS)
|
||||
echo $(VERSION) > $(STORED_VERSION_FILE)
|
||||
# bsdtar needs a ^ to prevent matching subdirectories
|
||||
$(eval EXCL := --exclude=$(shell tar --help | grep -q bsdtar && echo "^")./)
|
||||
tar $(addprefix $(EXCL),$(TAR_EXCLUDES)) -czf $(DIST)/release/gitea-src-$(VERSION).tar.gz .
|
||||
# use transform to a add a release-folder prefix; in bsdtar the transform parameter equivalent is -s
|
||||
$(eval TRANSFORM := $(shell tar --help | grep -q bsdtar && echo "-s '/^./gitea-src-$(VERSION)/'" || echo "--transform 's|^./|gitea-src-$(VERSION)/|'"))
|
||||
tar $(addprefix $(EXCL),$(TAR_EXCLUDES)) $(TRANSFORM) -czf $(DIST)/release/gitea-src-$(VERSION).tar.gz .
|
||||
rm -f $(STORED_VERSION_FILE)
|
||||
|
||||
.PHONY: release-docs
|
||||
|
@ -685,6 +671,15 @@ deps-frontend: node_modules
|
|||
.PHONY: deps-backend
|
||||
deps-backend:
|
||||
$(GO) mod download
|
||||
$(GO) install $(AIR_PACKAGE)
|
||||
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
|
||||
$(GO) install $(ERRCHECK_PACKAGE)
|
||||
$(GO) install $(GOFUMPT_PACKAGE)
|
||||
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
$(GO) install $(GXZ_PAGAGE)
|
||||
$(GO) install $(MISSPELL_PACKAGE)
|
||||
$(GO) install $(SWAGGER_PACKAGE)
|
||||
$(GO) install $(XGO_PACKAGE)
|
||||
|
||||
node_modules: package-lock.json
|
||||
npm install --no-save
|
||||
|
@ -778,29 +773,19 @@ pr\#%: clean-all
|
|||
$(GO) run contrib/pr/checkout.go $*
|
||||
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint: golangci-lint-check
|
||||
golangci-lint run --timeout 10m
|
||||
golangci-lint:
|
||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
||||
|
||||
.PHONY: golangci-lint-check
|
||||
golangci-lint-check:
|
||||
$(eval GOLANGCI_LINT_VERSION := $(shell printf "%03d%03d%03d" $(shell golangci-lint --version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
|
||||
$(eval MIN_GOLANGCI_LINT_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_GOLANGCI_LINT_VERSION) | grep -o ...)))
|
||||
@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
echo "Downloading golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
|
||||
export BINARY="golangci-lint"; \
|
||||
curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \
|
||||
elif [ "$(GOLANGCI_LINT_VERSION)" -lt "$(MIN_GOLANGCI_LINT_VERSION)" ]; then \
|
||||
echo "Downloading newer version of golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
|
||||
export BINARY="golangci-lint"; \
|
||||
curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \
|
||||
fi
|
||||
# workaround step for the lint-backend-windows CI task because 'go run' can not
|
||||
# have distinct GOOS/GOARCH for its build and run steps
|
||||
.PHONY: golangci-lint-windows
|
||||
golangci-lint-windows:
|
||||
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
golangci-lint run
|
||||
|
||||
.PHONY: editorconfig-checker
|
||||
editorconfig-checker:
|
||||
@hash editorconfig-checker > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@50adf46752da119dfef66e57be3ce2693ea4aa9c; \
|
||||
fi
|
||||
editorconfig-checker templates
|
||||
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates
|
||||
|
||||
.PHONY: docker
|
||||
docker:
|
||||
|
|
|
@ -73,7 +73,7 @@ or if SQLite support is required:
|
|||
|
||||
The `build` target is split into two sub-targets:
|
||||
|
||||
- `make backend` which requires [Go 1.16](https://golang.org/dl/) or greater.
|
||||
- `make backend` which requires [Go 1.17](https://go.dev/dl/) or greater.
|
||||
- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and Internet connectivity to download npm dependencies.
|
||||
|
||||
When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js and Internet connectivity.
|
||||
|
|
1
build.go
1
build.go
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build vendor
|
||||
// +build vendor
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
|
@ -40,7 +39,7 @@ func passThroughCmd(cmd string, args []string) error {
|
|||
}
|
||||
c := exec.Cmd{
|
||||
Path: foundCmd,
|
||||
Args: args,
|
||||
Args: append([]string{cmd}, args...),
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
|
@ -271,9 +270,9 @@ func main() {
|
|||
log.Print("the -d option is not supported by gitea-fmt")
|
||||
}
|
||||
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-l"), containsString(subArgs, "-w")))
|
||||
cmdErrors = append(cmdErrors, passThroughCmd("gofumpt", append([]string{"-extra", "-lang", "1.16"}, substArgs...)))
|
||||
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", "1.17"}, substArgs...)))
|
||||
case "misspell":
|
||||
cmdErrors = append(cmdErrors, passThroughCmd("misspell", substArgs))
|
||||
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("MISSPELL_PACKAGE")}, substArgs...)))
|
||||
default:
|
||||
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// merges them into one profile
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
|
|
26
cmd/admin.go
26
cmd/admin.go
|
@ -25,6 +25,7 @@ import (
|
|||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
auth_service "code.gitea.io/gitea/services/auth"
|
||||
"code.gitea.io/gitea/services/auth/source/oauth2"
|
||||
"code.gitea.io/gitea/services/auth/source/smtp"
|
||||
|
@ -114,6 +115,10 @@ var (
|
|||
Name: "access-token",
|
||||
Usage: "Generate access token for the user",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "restricted",
|
||||
Usage: "Make a restricted user account",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -493,7 +498,7 @@ func runChangePassword(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err = user_model.UpdateUserCols(db.DefaultContext, user, "passwd", "passwd_hash_algo", "salt"); err != nil {
|
||||
if err = user_model.UpdateUserCols(ctx, user, "passwd", "passwd_hash_algo", "salt"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -551,7 +556,7 @@ func runCreateUser(c *cli.Context) error {
|
|||
|
||||
// If this is the first user being created.
|
||||
// Take it as the admin and don't force a password update.
|
||||
if n := user_model.CountUsers(); n == 0 {
|
||||
if n := user_model.CountUsers(nil); n == 0 {
|
||||
changePassword = false
|
||||
}
|
||||
|
||||
|
@ -559,17 +564,26 @@ func runCreateUser(c *cli.Context) error {
|
|||
changePassword = c.Bool("must-change-password")
|
||||
}
|
||||
|
||||
restricted := util.OptionalBoolNone
|
||||
|
||||
if c.IsSet("restricted") {
|
||||
restricted = util.OptionalBoolOf(c.Bool("restricted"))
|
||||
}
|
||||
|
||||
u := &user_model.User{
|
||||
Name: username,
|
||||
Email: c.String("email"),
|
||||
Passwd: password,
|
||||
IsActive: true,
|
||||
IsAdmin: c.Bool("admin"),
|
||||
MustChangePassword: changePassword,
|
||||
Theme: setting.UI.DefaultTheme,
|
||||
}
|
||||
|
||||
if err := user_model.CreateUser(u); err != nil {
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
IsRestricted: restricted,
|
||||
}
|
||||
|
||||
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
|
||||
return fmt.Errorf("CreateUser: %v", err)
|
||||
}
|
||||
|
||||
|
@ -724,7 +738,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
|
|||
log.Trace("Processing next %d repos of %d", len(repos), count)
|
||||
for _, repo := range repos {
|
||||
log.Trace("Synchronizing repo %s with path %s", repo.FullName(), repo.RepoPath())
|
||||
gitRepo, err := git.OpenRepositoryCtx(ctx, repo.RepoPath())
|
||||
gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Warn("OpenRepository: %v", err)
|
||||
continue
|
||||
|
|
67
cmd/dump.go
67
cmd/dump.go
|
@ -7,6 +7,7 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
@ -25,10 +26,21 @@ import (
|
|||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func addFile(w archiver.Writer, filePath, absPath string, verbose bool) error {
|
||||
func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error {
|
||||
if verbose {
|
||||
log.Info("Adding file %s\n", filePath)
|
||||
log.Info("Adding file %s", customName)
|
||||
}
|
||||
|
||||
return w.Write(archiver.File{
|
||||
FileInfo: archiver.FileInfo{
|
||||
FileInfo: info,
|
||||
CustomName: customName,
|
||||
},
|
||||
ReadCloser: r,
|
||||
})
|
||||
}
|
||||
|
||||
func addFile(w archiver.Writer, filePath, absPath string, verbose bool) error {
|
||||
file, err := os.Open(absPath)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -39,13 +51,7 @@ func addFile(w archiver.Writer, filePath, absPath string, verbose bool) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return w.Write(archiver.File{
|
||||
FileInfo: archiver.FileInfo{
|
||||
FileInfo: fileInfo,
|
||||
CustomName: filePath,
|
||||
},
|
||||
ReadCloser: file,
|
||||
})
|
||||
return addReader(w, file, fileInfo, filePath, verbose)
|
||||
}
|
||||
|
||||
func isSubdir(upper, lower string) (bool, error) {
|
||||
|
@ -86,7 +92,7 @@ func (o outputType) String() string {
|
|||
}
|
||||
|
||||
var outputTypeEnum = &outputType{
|
||||
Enum: []string{"zip", "rar", "tar", "sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"},
|
||||
Enum: []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"},
|
||||
Default: "zip",
|
||||
}
|
||||
|
||||
|
@ -136,6 +142,10 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
|
|||
Name: "skip-attachment-data",
|
||||
Usage: "Skip attachment data",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "skip-package-data",
|
||||
Usage: "Skip package data",
|
||||
},
|
||||
cli.GenericFlag{
|
||||
Name: "type",
|
||||
Value: outputTypeEnum,
|
||||
|
@ -160,7 +170,12 @@ func runDump(ctx *cli.Context) error {
|
|||
fatal("Deleting default logger failed. Can not write to stdout: %v", err)
|
||||
}
|
||||
} else {
|
||||
fileName = strings.TrimSuffix(fileName, path.Ext(fileName))
|
||||
for _, suffix := range outputTypeEnum.Enum {
|
||||
if strings.HasSuffix(fileName, "."+suffix) {
|
||||
fileName = strings.TrimSuffix(fileName, "."+suffix)
|
||||
break
|
||||
}
|
||||
}
|
||||
fileName += "." + outType
|
||||
}
|
||||
setting.LoadFromExisting()
|
||||
|
@ -236,13 +251,7 @@ func runDump(ctx *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return w.Write(archiver.File{
|
||||
FileInfo: archiver.FileInfo{
|
||||
FileInfo: info,
|
||||
CustomName: path.Join("data", "lfs", objPath),
|
||||
},
|
||||
ReadCloser: object,
|
||||
})
|
||||
return addReader(w, object, info, path.Join("data", "lfs", objPath), verbose)
|
||||
}); err != nil {
|
||||
fatal("Failed to dump LFS objects: %v", err)
|
||||
}
|
||||
|
@ -321,6 +330,7 @@ func runDump(ctx *cli.Context) error {
|
|||
excludes = append(excludes, setting.RepoRootPath)
|
||||
excludes = append(excludes, setting.LFS.Path)
|
||||
excludes = append(excludes, setting.Attachment.Path)
|
||||
excludes = append(excludes, setting.Packages.Path)
|
||||
excludes = append(excludes, setting.LogRootPath)
|
||||
excludes = append(excludes, absFileName)
|
||||
if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil {
|
||||
|
@ -336,17 +346,24 @@ func runDump(ctx *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return w.Write(archiver.File{
|
||||
FileInfo: archiver.FileInfo{
|
||||
FileInfo: info,
|
||||
CustomName: path.Join("data", "attachments", objPath),
|
||||
},
|
||||
ReadCloser: object,
|
||||
})
|
||||
return addReader(w, object, info, path.Join("data", "attachments", objPath), verbose)
|
||||
}); err != nil {
|
||||
fatal("Failed to dump attachments: %v", err)
|
||||
}
|
||||
|
||||
if ctx.IsSet("skip-package-data") && ctx.Bool("skip-package-data") {
|
||||
log.Info("Skip dumping package data")
|
||||
} else if err := storage.Packages.IterateObjects(func(objPath string, object storage.Object) error {
|
||||
info, err := object.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return addReader(w, object, info, path.Join("data", "packages", objPath), verbose)
|
||||
}); err != nil {
|
||||
fatal("Failed to dump packages: %v", err)
|
||||
}
|
||||
|
||||
// Doesn't check if LogRootPath exists before processing --skip-log intentionally,
|
||||
// ensuring that it's clear the dump is skipped whether the directory's initialized
|
||||
// yet or not.
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build bindata
|
||||
// +build bindata
|
||||
|
||||
package cmd
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !bindata
|
||||
// +build !bindata
|
||||
|
||||
package cmd
|
||||
|
||||
|
|
40
cmd/hook.go
40
cmd/hook.go
|
@ -15,9 +15,9 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
|
@ -162,7 +162,7 @@ func (n *nilWriter) WriteString(s string) (int, error) {
|
|||
}
|
||||
|
||||
func runHookPreReceive(c *cli.Context) error {
|
||||
if os.Getenv(models.EnvIsInternal) == "true" {
|
||||
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
||||
return nil
|
||||
}
|
||||
ctx, cancel := installSignals()
|
||||
|
@ -180,12 +180,12 @@ Gitea or set your environment appropriately.`, "")
|
|||
}
|
||||
|
||||
// the environment is set by serv command
|
||||
isWiki := os.Getenv(models.EnvRepoIsWiki) == "true"
|
||||
username := os.Getenv(models.EnvRepoUsername)
|
||||
reponame := os.Getenv(models.EnvRepoName)
|
||||
userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
|
||||
prID, _ := strconv.ParseInt(os.Getenv(models.EnvPRID), 10, 64)
|
||||
isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey))
|
||||
isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki))
|
||||
username := os.Getenv(repo_module.EnvRepoUsername)
|
||||
reponame := os.Getenv(repo_module.EnvRepoName)
|
||||
userID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
|
||||
prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64)
|
||||
deployKeyID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvDeployKeyID), 10, 64)
|
||||
|
||||
hookOptions := private.HookOptions{
|
||||
UserID: userID,
|
||||
|
@ -194,7 +194,7 @@ Gitea or set your environment appropriately.`, "")
|
|||
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
|
||||
GitPushOptions: pushOptions(),
|
||||
PullRequestID: prID,
|
||||
IsDeployKey: isDeployKey,
|
||||
DeployKeyID: deployKeyID,
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
@ -309,12 +309,12 @@ func runHookPostReceive(c *cli.Context) error {
|
|||
defer cancel()
|
||||
|
||||
// First of all run update-server-info no matter what
|
||||
if _, err := git.NewCommand(ctx, "update-server-info").Run(); err != nil {
|
||||
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
|
||||
return fmt.Errorf("Failed to call 'git update-server-info': %v", err)
|
||||
}
|
||||
|
||||
// Now if we're an internal don't do anything else
|
||||
if os.Getenv(models.EnvIsInternal) == "true" {
|
||||
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -343,11 +343,11 @@ Gitea or set your environment appropriately.`, "")
|
|||
}
|
||||
|
||||
// the environment is set by serv command
|
||||
repoUser := os.Getenv(models.EnvRepoUsername)
|
||||
isWiki := os.Getenv(models.EnvRepoIsWiki) == "true"
|
||||
repoName := os.Getenv(models.EnvRepoName)
|
||||
pusherID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
|
||||
pusherName := os.Getenv(models.EnvPusherName)
|
||||
repoUser := os.Getenv(repo_module.EnvRepoUsername)
|
||||
isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki))
|
||||
repoName := os.Getenv(repo_module.EnvRepoName)
|
||||
pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
|
||||
pusherName := os.Getenv(repo_module.EnvPusherName)
|
||||
|
||||
hookOptions := private.HookOptions{
|
||||
UserName: pusherName,
|
||||
|
@ -503,10 +503,10 @@ Gitea or set your environment appropriately.`, "")
|
|||
}
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
repoUser := os.Getenv(models.EnvRepoUsername)
|
||||
repoName := os.Getenv(models.EnvRepoName)
|
||||
pusherID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
|
||||
pusherName := os.Getenv(models.EnvPusherName)
|
||||
repoUser := os.Getenv(repo_module.EnvRepoUsername)
|
||||
repoName := os.Getenv(repo_module.EnvRepoName)
|
||||
pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
|
||||
pusherName := os.Getenv(repo_module.EnvPusherName)
|
||||
|
||||
// 1. Version and features negotiation.
|
||||
// S: PKT-LINE(version=1\0push-options atomic...) / PKT-LINE(version=1\n)
|
||||
|
|
377
cmd/manager.go
377
cmd/manager.go
|
@ -10,7 +10,6 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
@ -27,6 +26,7 @@ var (
|
|||
subcmdRestart,
|
||||
subcmdFlushQueues,
|
||||
subcmdLogging,
|
||||
subCmdProcesses,
|
||||
},
|
||||
}
|
||||
subcmdShutdown = cli.Command{
|
||||
|
@ -68,326 +68,38 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
defaultLoggingFlags = []cli.Flag{
|
||||
subCmdProcesses = cli.Command{
|
||||
Name: "processes",
|
||||
Usage: "Display running processes within the current process",
|
||||
Action: runProcesses,
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "flat",
|
||||
Usage: "Show processes as flat table rather than as tree",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-system",
|
||||
Usage: "Do not show system proceses",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "stacktraces",
|
||||
Usage: "Show stacktraces",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "json",
|
||||
Usage: "Output as json",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "group, g",
|
||||
Usage: "Group to add logger to - will default to \"default\"",
|
||||
}, cli.StringFlag{
|
||||
Name: "name, n",
|
||||
Usage: "Name of the new logger - will default to mode",
|
||||
}, cli.StringFlag{
|
||||
Name: "level, l",
|
||||
Usage: "Logging level for the new logger",
|
||||
}, cli.StringFlag{
|
||||
Name: "stacktrace-level, L",
|
||||
Usage: "Stacktrace logging level",
|
||||
}, cli.StringFlag{
|
||||
Name: "flags, F",
|
||||
Usage: "Flags for the logger",
|
||||
}, cli.StringFlag{
|
||||
Name: "expression, e",
|
||||
Usage: "Matching expression for the logger",
|
||||
}, cli.StringFlag{
|
||||
Name: "prefix, p",
|
||||
Usage: "Prefix for the logger",
|
||||
}, cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "Use color in the logs",
|
||||
}, cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
}
|
||||
subcmdLogging = cli.Command{
|
||||
Name: "logging",
|
||||
Usage: "Adjust logging commands",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "pause",
|
||||
Usage: "Pause logging (Gitea will buffer logs up to a certain point and will drop them after that point)",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
},
|
||||
Action: runPauseLogging,
|
||||
}, {
|
||||
Name: "resume",
|
||||
Usage: "Resume logging",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
},
|
||||
Action: runResumeLogging,
|
||||
}, {
|
||||
Name: "release-and-reopen",
|
||||
Usage: "Cause Gitea to release and re-open files used for logging",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
},
|
||||
Action: runReleaseReopenLogging,
|
||||
}, {
|
||||
Name: "remove",
|
||||
Usage: "Remove a logger",
|
||||
ArgsUsage: "[name] Name of logger to remove",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
}, cli.StringFlag{
|
||||
Name: "group, g",
|
||||
Usage: "Group to add logger to - will default to \"default\"",
|
||||
},
|
||||
},
|
||||
Action: runRemoveLogger,
|
||||
}, {
|
||||
Name: "add",
|
||||
Usage: "Add a logger",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "console",
|
||||
Usage: "Add a console logger",
|
||||
Flags: append(defaultLoggingFlags,
|
||||
cli.BoolFlag{
|
||||
Name: "stderr",
|
||||
Usage: "Output console logs to stderr - only relevant for console",
|
||||
}),
|
||||
Action: runAddConsoleLogger,
|
||||
}, {
|
||||
Name: "file",
|
||||
Usage: "Add a file logger",
|
||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "filename, f",
|
||||
Usage: "Filename for the logger - this must be set.",
|
||||
}, cli.BoolTFlag{
|
||||
Name: "rotate, r",
|
||||
Usage: "Rotate logs",
|
||||
}, cli.Int64Flag{
|
||||
Name: "max-size, s",
|
||||
Usage: "Maximum size in bytes before rotation",
|
||||
}, cli.BoolTFlag{
|
||||
Name: "daily, d",
|
||||
Usage: "Rotate logs daily",
|
||||
}, cli.IntFlag{
|
||||
Name: "max-days, D",
|
||||
Usage: "Maximum number of daily logs to keep",
|
||||
}, cli.BoolTFlag{
|
||||
Name: "compress, z",
|
||||
Usage: "Compress rotated logs",
|
||||
}, cli.IntFlag{
|
||||
Name: "compression-level, Z",
|
||||
Usage: "Compression level to use",
|
||||
},
|
||||
}...),
|
||||
Action: runAddFileLogger,
|
||||
}, {
|
||||
Name: "conn",
|
||||
Usage: "Add a net conn logger",
|
||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "reconnect-on-message, R",
|
||||
Usage: "Reconnect to host for every message",
|
||||
}, cli.BoolFlag{
|
||||
Name: "reconnect, r",
|
||||
Usage: "Reconnect to host when connection is dropped",
|
||||
}, cli.StringFlag{
|
||||
Name: "protocol, P",
|
||||
Usage: "Set protocol to use: tcp, unix, or udp (defaults to tcp)",
|
||||
}, cli.StringFlag{
|
||||
Name: "address, a",
|
||||
Usage: "Host address and port to connect to (defaults to :7020)",
|
||||
},
|
||||
}...),
|
||||
Action: runAddConnLogger,
|
||||
}, {
|
||||
Name: "smtp",
|
||||
Usage: "Add an SMTP logger",
|
||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "username, u",
|
||||
Usage: "Mail server username",
|
||||
}, cli.StringFlag{
|
||||
Name: "password, P",
|
||||
Usage: "Mail server password",
|
||||
}, cli.StringFlag{
|
||||
Name: "host, H",
|
||||
Usage: "Mail server host (defaults to: 127.0.0.1:25)",
|
||||
}, cli.StringSliceFlag{
|
||||
Name: "send-to, s",
|
||||
Usage: "Email address(es) to send to",
|
||||
}, cli.StringFlag{
|
||||
Name: "subject, S",
|
||||
Usage: "Subject header of sent emails",
|
||||
},
|
||||
}...),
|
||||
Action: runAddSMTPLogger,
|
||||
},
|
||||
},
|
||||
Name: "cancel",
|
||||
Usage: "Process PID to cancel. (Only available for non-system processes.)",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func runRemoveLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
group := c.String("group")
|
||||
if len(group) == 0 {
|
||||
group = log.DEFAULT
|
||||
}
|
||||
name := c.Args().First()
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
statusCode, msg := private.RemoveLogger(ctx, group, name)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runAddSMTPLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "smtp"
|
||||
if c.IsSet("host") {
|
||||
vals["host"] = c.String("host")
|
||||
} else {
|
||||
vals["host"] = "127.0.0.1:25"
|
||||
}
|
||||
|
||||
if c.IsSet("username") {
|
||||
vals["username"] = c.String("username")
|
||||
}
|
||||
if c.IsSet("password") {
|
||||
vals["password"] = c.String("password")
|
||||
}
|
||||
|
||||
if !c.IsSet("send-to") {
|
||||
return fmt.Errorf("Some recipients must be provided")
|
||||
}
|
||||
vals["sendTos"] = c.StringSlice("send-to")
|
||||
|
||||
if c.IsSet("subject") {
|
||||
vals["subject"] = c.String("subject")
|
||||
} else {
|
||||
vals["subject"] = "Diagnostic message from Gitea"
|
||||
}
|
||||
|
||||
return commonAddLogger(c, mode, vals)
|
||||
}
|
||||
|
||||
func runAddConnLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "conn"
|
||||
vals["net"] = "tcp"
|
||||
if c.IsSet("protocol") {
|
||||
switch c.String("protocol") {
|
||||
case "udp":
|
||||
vals["net"] = "udp"
|
||||
case "unix":
|
||||
vals["net"] = "unix"
|
||||
}
|
||||
}
|
||||
if c.IsSet("address") {
|
||||
vals["address"] = c.String("address")
|
||||
} else {
|
||||
vals["address"] = ":7020"
|
||||
}
|
||||
if c.IsSet("reconnect") {
|
||||
vals["reconnect"] = c.Bool("reconnect")
|
||||
}
|
||||
if c.IsSet("reconnect-on-message") {
|
||||
vals["reconnectOnMsg"] = c.Bool("reconnect-on-message")
|
||||
}
|
||||
return commonAddLogger(c, mode, vals)
|
||||
}
|
||||
|
||||
func runAddFileLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "file"
|
||||
if c.IsSet("filename") {
|
||||
vals["filename"] = c.String("filename")
|
||||
} else {
|
||||
return fmt.Errorf("filename must be set when creating a file logger")
|
||||
}
|
||||
if c.IsSet("rotate") {
|
||||
vals["rotate"] = c.Bool("rotate")
|
||||
}
|
||||
if c.IsSet("max-size") {
|
||||
vals["maxsize"] = c.Int64("max-size")
|
||||
}
|
||||
if c.IsSet("daily") {
|
||||
vals["daily"] = c.Bool("daily")
|
||||
}
|
||||
if c.IsSet("max-days") {
|
||||
vals["maxdays"] = c.Int("max-days")
|
||||
}
|
||||
if c.IsSet("compress") {
|
||||
vals["compress"] = c.Bool("compress")
|
||||
}
|
||||
if c.IsSet("compression-level") {
|
||||
vals["compressionLevel"] = c.Int("compression-level")
|
||||
}
|
||||
return commonAddLogger(c, mode, vals)
|
||||
}
|
||||
|
||||
func runAddConsoleLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "console"
|
||||
if c.IsSet("stderr") && c.Bool("stderr") {
|
||||
vals["stderr"] = c.Bool("stderr")
|
||||
}
|
||||
return commonAddLogger(c, mode, vals)
|
||||
}
|
||||
|
||||
func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) error {
|
||||
if len(c.String("level")) > 0 {
|
||||
vals["level"] = log.FromString(c.String("level")).String()
|
||||
}
|
||||
if len(c.String("stacktrace-level")) > 0 {
|
||||
vals["stacktraceLevel"] = log.FromString(c.String("stacktrace-level")).String()
|
||||
}
|
||||
if len(c.String("expression")) > 0 {
|
||||
vals["expression"] = c.String("expression")
|
||||
}
|
||||
if len(c.String("prefix")) > 0 {
|
||||
vals["prefix"] = c.String("prefix")
|
||||
}
|
||||
if len(c.String("flags")) > 0 {
|
||||
vals["flags"] = log.FlagsFromString(c.String("flags"))
|
||||
}
|
||||
if c.IsSet("color") {
|
||||
vals["colorize"] = c.Bool("color")
|
||||
}
|
||||
group := "default"
|
||||
if c.IsSet("group") {
|
||||
group = c.String("group")
|
||||
}
|
||||
name := mode
|
||||
if c.IsSet("name") {
|
||||
name = c.String("name")
|
||||
}
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
statusCode, msg := private.AddLogger(ctx, group, name, mode, vals)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runShutdown(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
@ -433,47 +145,16 @@ func runFlushQueues(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runPauseLogging(c *cli.Context) error {
|
||||
func runProcesses(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("manager", c.Bool("debug"))
|
||||
statusCode, msg := private.PauseLogging(ctx)
|
||||
statusCode, msg := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runResumeLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("manager", c.Bool("debug"))
|
||||
statusCode, msg := private.ResumeLogging(ctx)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runReleaseReopenLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("manager", c.Bool("debug"))
|
||||
statusCode, msg := private.ReleaseReopenLogging(ctx)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,383 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultLoggingFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "group, g",
|
||||
Usage: "Group to add logger to - will default to \"default\"",
|
||||
}, cli.StringFlag{
|
||||
Name: "name, n",
|
||||
Usage: "Name of the new logger - will default to mode",
|
||||
}, cli.StringFlag{
|
||||
Name: "level, l",
|
||||
Usage: "Logging level for the new logger",
|
||||
}, cli.StringFlag{
|
||||
Name: "stacktrace-level, L",
|
||||
Usage: "Stacktrace logging level",
|
||||
}, cli.StringFlag{
|
||||
Name: "flags, F",
|
||||
Usage: "Flags for the logger",
|
||||
}, cli.StringFlag{
|
||||
Name: "expression, e",
|
||||
Usage: "Matching expression for the logger",
|
||||
}, cli.StringFlag{
|
||||
Name: "prefix, p",
|
||||
Usage: "Prefix for the logger",
|
||||
}, cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "Use color in the logs",
|
||||
}, cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
}
|
||||
|
||||
subcmdLogging = cli.Command{
|
||||
Name: "logging",
|
||||
Usage: "Adjust logging commands",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "pause",
|
||||
Usage: "Pause logging (Gitea will buffer logs up to a certain point and will drop them after that point)",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
},
|
||||
Action: runPauseLogging,
|
||||
}, {
|
||||
Name: "resume",
|
||||
Usage: "Resume logging",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
},
|
||||
Action: runResumeLogging,
|
||||
}, {
|
||||
Name: "release-and-reopen",
|
||||
Usage: "Cause Gitea to release and re-open files used for logging",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
},
|
||||
},
|
||||
Action: runReleaseReopenLogging,
|
||||
}, {
|
||||
Name: "remove",
|
||||
Usage: "Remove a logger",
|
||||
ArgsUsage: "[name] Name of logger to remove",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
}, cli.StringFlag{
|
||||
Name: "group, g",
|
||||
Usage: "Group to add logger to - will default to \"default\"",
|
||||
},
|
||||
},
|
||||
Action: runRemoveLogger,
|
||||
}, {
|
||||
Name: "add",
|
||||
Usage: "Add a logger",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "console",
|
||||
Usage: "Add a console logger",
|
||||
Flags: append(defaultLoggingFlags,
|
||||
cli.BoolFlag{
|
||||
Name: "stderr",
|
||||
Usage: "Output console logs to stderr - only relevant for console",
|
||||
}),
|
||||
Action: runAddConsoleLogger,
|
||||
}, {
|
||||
Name: "file",
|
||||
Usage: "Add a file logger",
|
||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "filename, f",
|
||||
Usage: "Filename for the logger - this must be set.",
|
||||
}, cli.BoolTFlag{
|
||||
Name: "rotate, r",
|
||||
Usage: "Rotate logs",
|
||||
}, cli.Int64Flag{
|
||||
Name: "max-size, s",
|
||||
Usage: "Maximum size in bytes before rotation",
|
||||
}, cli.BoolTFlag{
|
||||
Name: "daily, d",
|
||||
Usage: "Rotate logs daily",
|
||||
}, cli.IntFlag{
|
||||
Name: "max-days, D",
|
||||
Usage: "Maximum number of daily logs to keep",
|
||||
}, cli.BoolTFlag{
|
||||
Name: "compress, z",
|
||||
Usage: "Compress rotated logs",
|
||||
}, cli.IntFlag{
|
||||
Name: "compression-level, Z",
|
||||
Usage: "Compression level to use",
|
||||
},
|
||||
}...),
|
||||
Action: runAddFileLogger,
|
||||
}, {
|
||||
Name: "conn",
|
||||
Usage: "Add a net conn logger",
|
||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "reconnect-on-message, R",
|
||||
Usage: "Reconnect to host for every message",
|
||||
}, cli.BoolFlag{
|
||||
Name: "reconnect, r",
|
||||
Usage: "Reconnect to host when connection is dropped",
|
||||
}, cli.StringFlag{
|
||||
Name: "protocol, P",
|
||||
Usage: "Set protocol to use: tcp, unix, or udp (defaults to tcp)",
|
||||
}, cli.StringFlag{
|
||||
Name: "address, a",
|
||||
Usage: "Host address and port to connect to (defaults to :7020)",
|
||||
},
|
||||
}...),
|
||||
Action: runAddConnLogger,
|
||||
}, {
|
||||
Name: "smtp",
|
||||
Usage: "Add an SMTP logger",
|
||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "username, u",
|
||||
Usage: "Mail server username",
|
||||
}, cli.StringFlag{
|
||||
Name: "password, P",
|
||||
Usage: "Mail server password",
|
||||
}, cli.StringFlag{
|
||||
Name: "host, H",
|
||||
Usage: "Mail server host (defaults to: 127.0.0.1:25)",
|
||||
}, cli.StringSliceFlag{
|
||||
Name: "send-to, s",
|
||||
Usage: "Email address(es) to send to",
|
||||
}, cli.StringFlag{
|
||||
Name: "subject, S",
|
||||
Usage: "Subject header of sent emails",
|
||||
},
|
||||
}...),
|
||||
Action: runAddSMTPLogger,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func runRemoveLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
group := c.String("group")
|
||||
if len(group) == 0 {
|
||||
group = log.DEFAULT
|
||||
}
|
||||
name := c.Args().First()
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
statusCode, msg := private.RemoveLogger(ctx, group, name)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runAddSMTPLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "smtp"
|
||||
if c.IsSet("host") {
|
||||
vals["host"] = c.String("host")
|
||||
} else {
|
||||
vals["host"] = "127.0.0.1:25"
|
||||
}
|
||||
|
||||
if c.IsSet("username") {
|
||||
vals["username"] = c.String("username")
|
||||
}
|
||||
if c.IsSet("password") {
|
||||
vals["password"] = c.String("password")
|
||||
}
|
||||
|
||||
if !c.IsSet("send-to") {
|
||||
return fmt.Errorf("Some recipients must be provided")
|
||||
}
|
||||
vals["sendTos"] = c.StringSlice("send-to")
|
||||
|
||||
if c.IsSet("subject") {
|
||||
vals["subject"] = c.String("subject")
|
||||
} else {
|
||||
vals["subject"] = "Diagnostic message from Gitea"
|
||||
}
|
||||
|
||||
return commonAddLogger(c, mode, vals)
|
||||
}
|
||||
|
||||
func runAddConnLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "conn"
|
||||
vals["net"] = "tcp"
|
||||
if c.IsSet("protocol") {
|
||||
switch c.String("protocol") {
|
||||
case "udp":
|
||||
vals["net"] = "udp"
|
||||
case "unix":
|
||||
vals["net"] = "unix"
|
||||
}
|
||||
}
|
||||
if c.IsSet("address") {
|
||||
vals["address"] = c.String("address")
|
||||
} else {
|
||||
vals["address"] = ":7020"
|
||||
}
|
||||
if c.IsSet("reconnect") {
|
||||
vals["reconnect"] = c.Bool("reconnect")
|
||||
}
|
||||
if c.IsSet("reconnect-on-message") {
|
||||
vals["reconnectOnMsg"] = c.Bool("reconnect-on-message")
|
||||
}
|
||||
return commonAddLogger(c, mode, vals)
|
||||
}
|
||||
|
||||
func runAddFileLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "file"
|
||||
if c.IsSet("filename") {
|
||||
vals["filename"] = c.String("filename")
|
||||
} else {
|
||||
return fmt.Errorf("filename must be set when creating a file logger")
|
||||
}
|
||||
if c.IsSet("rotate") {
|
||||
vals["rotate"] = c.Bool("rotate")
|
||||
}
|
||||
if c.IsSet("max-size") {
|
||||
vals["maxsize"] = c.Int64("max-size")
|
||||
}
|
||||
if c.IsSet("daily") {
|
||||
vals["daily"] = c.Bool("daily")
|
||||
}
|
||||
if c.IsSet("max-days") {
|
||||
vals["maxdays"] = c.Int("max-days")
|
||||
}
|
||||
if c.IsSet("compress") {
|
||||
vals["compress"] = c.Bool("compress")
|
||||
}
|
||||
if c.IsSet("compression-level") {
|
||||
vals["compressionLevel"] = c.Int("compression-level")
|
||||
}
|
||||
return commonAddLogger(c, mode, vals)
|
||||
}
|
||||
|
||||
func runAddConsoleLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "console"
|
||||
if c.IsSet("stderr") && c.Bool("stderr") {
|
||||
vals["stderr"] = c.Bool("stderr")
|
||||
}
|
||||
return commonAddLogger(c, mode, vals)
|
||||
}
|
||||
|
||||
func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) error {
|
||||
if len(c.String("level")) > 0 {
|
||||
vals["level"] = log.FromString(c.String("level")).String()
|
||||
}
|
||||
if len(c.String("stacktrace-level")) > 0 {
|
||||
vals["stacktraceLevel"] = log.FromString(c.String("stacktrace-level")).String()
|
||||
}
|
||||
if len(c.String("expression")) > 0 {
|
||||
vals["expression"] = c.String("expression")
|
||||
}
|
||||
if len(c.String("prefix")) > 0 {
|
||||
vals["prefix"] = c.String("prefix")
|
||||
}
|
||||
if len(c.String("flags")) > 0 {
|
||||
vals["flags"] = log.FlagsFromString(c.String("flags"))
|
||||
}
|
||||
if c.IsSet("color") {
|
||||
vals["colorize"] = c.Bool("color")
|
||||
}
|
||||
group := "default"
|
||||
if c.IsSet("group") {
|
||||
group = c.String("group")
|
||||
}
|
||||
name := mode
|
||||
if c.IsSet("name") {
|
||||
name = c.String("name")
|
||||
}
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
statusCode, msg := private.AddLogger(ctx, group, name, mode, vals)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runPauseLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("manager", c.Bool("debug"))
|
||||
statusCode, msg := private.PauseLogging(ctx)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runResumeLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("manager", c.Bool("debug"))
|
||||
statusCode, msg := private.ResumeLogging(ctx)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runReleaseReopenLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("manager", c.Bool("debug"))
|
||||
statusCode, msg := private.ReleaseReopenLogging(ctx)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
}
|
32
cmd/serv.go
32
cmd/serv.go
|
@ -24,6 +24,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/pprof"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/services/lfs"
|
||||
|
||||
|
@ -235,17 +236,17 @@ func runServ(c *cli.Context) error {
|
|||
}
|
||||
return fail("Internal Server Error", "%s", err.Error())
|
||||
}
|
||||
os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki))
|
||||
os.Setenv(models.EnvRepoName, results.RepoName)
|
||||
os.Setenv(models.EnvRepoUsername, results.OwnerName)
|
||||
os.Setenv(models.EnvPusherName, results.UserName)
|
||||
os.Setenv(models.EnvPusherEmail, results.UserEmail)
|
||||
os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
|
||||
os.Setenv(models.EnvRepoID, strconv.FormatInt(results.RepoID, 10))
|
||||
os.Setenv(models.EnvPRID, fmt.Sprintf("%d", 0))
|
||||
os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey))
|
||||
os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
|
||||
os.Setenv(models.EnvAppURL, setting.AppURL)
|
||||
os.Setenv(repo_module.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki))
|
||||
os.Setenv(repo_module.EnvRepoName, results.RepoName)
|
||||
os.Setenv(repo_module.EnvRepoUsername, results.OwnerName)
|
||||
os.Setenv(repo_module.EnvPusherName, results.UserName)
|
||||
os.Setenv(repo_module.EnvPusherEmail, results.UserEmail)
|
||||
os.Setenv(repo_module.EnvPusherID, strconv.FormatInt(results.UserID, 10))
|
||||
os.Setenv(repo_module.EnvRepoID, strconv.FormatInt(results.RepoID, 10))
|
||||
os.Setenv(repo_module.EnvPRID, fmt.Sprintf("%d", 0))
|
||||
os.Setenv(repo_module.EnvDeployKeyID, fmt.Sprintf("%d", results.DeployKeyID))
|
||||
os.Setenv(repo_module.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
|
||||
os.Setenv(repo_module.EnvAppURL, setting.AppURL)
|
||||
|
||||
// LFS token authentication
|
||||
if verb == lfsAuthenticateVerb {
|
||||
|
@ -296,6 +297,15 @@ func runServ(c *cli.Context) error {
|
|||
gitcmd = exec.CommandContext(ctx, verb, repoPath)
|
||||
}
|
||||
|
||||
// Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when
|
||||
// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
|
||||
if _, err := os.Stat(setting.RepoRootPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return fail("Incorrect configuration.",
|
||||
"Directory `[repository]` `ROOT` was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.")
|
||||
}
|
||||
}
|
||||
|
||||
gitcmd.Dir = setting.RepoRootPath
|
||||
gitcmd.Stdout = os.Stdout
|
||||
gitcmd.Stdin = os.Stdin
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers"
|
||||
"code.gitea.io/gitea/routers/install"
|
||||
|
@ -59,6 +60,9 @@ and it takes care of all the other things for you`,
|
|||
}
|
||||
|
||||
func runHTTPRedirector() {
|
||||
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: HTTP Redirector", process.SystemProcessType, true)
|
||||
defer finished()
|
||||
|
||||
source := fmt.Sprintf("%s:%s", setting.HTTPAddr, setting.PortToRedirect)
|
||||
dest := strings.TrimSuffix(setting.AppURL, "/")
|
||||
log.Info("Redirecting: %s to %s", source, dest)
|
||||
|
@ -141,8 +145,10 @@ func runWeb(ctx *cli.Context) error {
|
|||
|
||||
if setting.EnablePprof {
|
||||
go func() {
|
||||
_, _, finished := process.GetManager().AddTypedContext(context.Background(), "Web: PProf Server", process.SystemProcessType, true)
|
||||
log.Info("Starting pprof server on localhost:6060")
|
||||
log.Info("%v", http.ListenAndServe("localhost:6060", nil))
|
||||
finished()
|
||||
}()
|
||||
}
|
||||
|
||||
|
@ -204,6 +210,8 @@ func listen(m http.Handler, handleRedirector bool) error {
|
|||
if setting.Protocol != setting.HTTPUnix && setting.Protocol != setting.FCGIUnix {
|
||||
listenAddr = net.JoinHostPort(listenAddr, setting.HTTPPort)
|
||||
}
|
||||
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: Gitea Server", process.SystemProcessType, true)
|
||||
defer finished()
|
||||
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL)
|
||||
// This can be useful for users, many users do wrong to their config and get strange behaviors behind a reverse-proxy.
|
||||
// A user may fix the configuration mistake when he sees this log.
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/caddyserver/certmagic"
|
||||
|
@ -107,6 +108,9 @@ func runACME(listenAddr string, m http.Handler) error {
|
|||
|
||||
if enableHTTPChallenge {
|
||||
go func() {
|
||||
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: ACME HTTP challenge server", process.SystemProcessType, true)
|
||||
defer finished()
|
||||
|
||||
log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
|
||||
// all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
|
||||
err := runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, "Let's Encrypt HTTP Challenge", myACME.HTTPChallengeHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)))
|
||||
|
@ -128,5 +132,5 @@ func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
|
|||
// URI always contains a leading slash, which would result in a double
|
||||
// slash
|
||||
target := strings.TrimSuffix(setting.AppURL, "/") + r.URL.RequestURI()
|
||||
http.Redirect(w, r, target, http.StatusFound)
|
||||
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
gitea_git "code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/markup/external"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers"
|
||||
|
@ -111,8 +111,8 @@ func runPR() {
|
|||
}
|
||||
unittest.LoadFixtures()
|
||||
util.RemoveAll(setting.RepoRootPath)
|
||||
util.RemoveAll(models.LocalCopyPath())
|
||||
util.CopyDir(path.Join(curDir, "integrations/gitea-repositories-meta"), setting.RepoRootPath)
|
||||
util.RemoveAll(repo_module.LocalCopyPath())
|
||||
unittest.CopyDir(path.Join(curDir, "integrations/gitea-repositories-meta"), setting.RepoRootPath)
|
||||
|
||||
log.Printf("[PR] Setting up router\n")
|
||||
// routers.GlobalInit()
|
||||
|
|
|
@ -3,26 +3,33 @@
|
|||
# from dl.gitea.io on linux as systemd service. It performs a backup and updates
|
||||
# Gitea in place.
|
||||
# NOTE: This adds the GPG Signing Key of the Gitea maintainers to the keyring.
|
||||
# Depends on: bash, curl, xz, sha256sum, gpg. optionally jq.
|
||||
# Usage: [environment vars] upgrade.sh [version]
|
||||
# Depends on: bash, curl, xz, sha256sum. optionally jq, gpg
|
||||
# See section below for available environment vars.
|
||||
# When no version is specified, updates to the latest release.
|
||||
# Examples:
|
||||
# upgrade.sh 1.15.10
|
||||
# giteahome=/opt/gitea giteaconf=$giteahome/app.ini upgrade.sh
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-v | --version ) ver="$2"; shift 2 ;;
|
||||
-y | --yes ) no_confirm="yes"; shift ;;
|
||||
--ignore-gpg) ignore_gpg="yes"; shift ;;
|
||||
-- ) shift; break ;;
|
||||
* ) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -euo pipefail
|
||||
# apply variables from environment
|
||||
: "${giteabin:="/usr/local/bin/gitea"}"
|
||||
: "${giteahome:="/var/lib/gitea"}"
|
||||
: "${giteaconf:="/etc/gitea/app.ini"}"
|
||||
: "${giteauser:="git"}"
|
||||
: "${sudocmd:="sudo"}"
|
||||
: "${arch:="linux-amd64"}"
|
||||
: "${service_start:="$sudocmd systemctl start gitea"}"
|
||||
: "${service_stop:="$sudocmd systemctl stop gitea"}"
|
||||
: "${service_status:="$sudocmd systemctl status gitea"}"
|
||||
: "${backupopts:=""}" # see `gitea dump --help` for available options
|
||||
|
||||
function giteacmd {
|
||||
if [[ $sudocmd = "su" ]]; then
|
||||
# `-c` only accept one string as argument.
|
||||
"$sudocmd" - "$giteauser" -c "$(printf "%q " "$giteabin" "--config" "$giteaconf" "--work-path" "$giteahome" "$@")"
|
||||
else
|
||||
"$sudocmd" --user "$giteauser" "$giteabin" --config "$giteaconf" --work-path "$giteahome" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
function require {
|
||||
for exe in "$@"; do
|
||||
|
@ -30,8 +37,19 @@ function require {
|
|||
done
|
||||
}
|
||||
|
||||
# parse command line arguments
|
||||
while true; do
|
||||
case "$1" in
|
||||
-v | --version ) giteaversion="$2"; shift 2 ;;
|
||||
-y | --yes ) no_confirm="yes"; shift ;;
|
||||
--ignore-gpg) ignore_gpg="yes"; shift ;;
|
||||
"" | -- ) shift; break ;;
|
||||
* ) echo "Usage: [<environment vars>] upgrade.sh [-v <version>] [-y] [--ignore-gpg]"; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
require curl xz sha256sum gpg
|
||||
# exit once any command fails. this means that each step should be idempotent!
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
os_release=$(cat /etc/os-release)
|
||||
|
@ -46,38 +64,17 @@ if [[ -f /etc/os-release ]]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
|
||||
# apply variables from environment
|
||||
: "${giteabin:="/usr/local/bin/gitea"}"
|
||||
: "${giteahome:="/var/lib/gitea"}"
|
||||
: "${giteaconf:="/etc/gitea/app.ini"}"
|
||||
: "${giteauser:="git"}"
|
||||
: "${sudocmd:="sudo"}"
|
||||
: "${arch:="linux-amd64"}"
|
||||
: "${service_start:="$sudocmd systemctl start gitea"}"
|
||||
: "${service_stop:="$sudocmd systemctl stop gitea"}"
|
||||
: "${service_status:="$sudocmd systemctl status gitea"}"
|
||||
: "${backupopts:=""}" # see `gitea dump --help` for available options
|
||||
|
||||
|
||||
function giteacmd {
|
||||
if [[ $sudocmd = "su" ]]; then
|
||||
"$sudocmd" - "$giteauser" -c "$giteabin" --config "$giteaconf" --work-path "$giteahome" "$@"
|
||||
else
|
||||
"$sudocmd" --user "$giteauser" "$giteabin" --config "$giteaconf" --work-path "$giteahome" "$@"
|
||||
fi
|
||||
}
|
||||
require curl xz sha256sum "$sudocmd"
|
||||
|
||||
# select version to install
|
||||
if [[ -z "${ver:-}" ]]; then
|
||||
if [[ -z "${giteaversion:-}" ]]; then
|
||||
require jq
|
||||
giteaversion=$(curl --connect-timeout 10 -sL https://dl.gitea.io/gitea/version.json | jq -r .latest.version)
|
||||
else
|
||||
giteaversion="$ver"
|
||||
echo "Latest available version is $giteaversion"
|
||||
fi
|
||||
|
||||
|
||||
# confirm update
|
||||
echo "Checking currently installed version..."
|
||||
current=$(giteacmd --version | cut -d ' ' -f 3)
|
||||
[[ "$current" == "$giteaversion" ]] && echo "$current is already installed, stopping." && exit 1
|
||||
if [[ -z "${no_confirm:-}" ]]; then
|
||||
|
@ -98,22 +95,24 @@ binurl="https://dl.gitea.io/gitea/${giteaversion}/${binname}.xz"
|
|||
echo "Downloading $binurl..."
|
||||
curl --connect-timeout 10 --silent --show-error --fail --location -O "$binurl{,.sha256,.asc}"
|
||||
|
||||
# validate checksum & gpg signature (exit script if error)
|
||||
# validate checksum & gpg signature
|
||||
sha256sum -c "${binname}.xz.sha256"
|
||||
if [[ -z "${ignore_gpg:-}" ]]; then
|
||||
require gpg
|
||||
gpg --keyserver keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2
|
||||
gpg --verify "${binname}.xz.asc" "${binname}.xz" || { echo 'Signature does not match'; exit 1; }
|
||||
fi
|
||||
rm "${binname}".xz.{sha256,asc}
|
||||
|
||||
# unpack binary + make executable
|
||||
xz --decompress "${binname}.xz"
|
||||
xz --decompress --force "${binname}.xz"
|
||||
chown "$giteauser" "$binname"
|
||||
chmod +x "$binname"
|
||||
|
||||
# stop gitea, create backup, replace binary, restart gitea
|
||||
echo "Stopping gitea at $(date)"
|
||||
echo "Flushing gitea queues at $(date)"
|
||||
giteacmd manager flush-queues
|
||||
echo "Stopping gitea at $(date)"
|
||||
$service_stop
|
||||
echo "Creating backup in $giteahome"
|
||||
giteacmd dump $backupopts
|
||||
|
|
|
@ -61,7 +61,7 @@ RUN_MODE = ; prod
|
|||
;; SSL Cipher Suites
|
||||
;SSL_CIPHER_SUITES=; Will default to "ecdhe_ecdsa_with_aes_256_gcm_sha384,ecdhe_rsa_with_aes_256_gcm_sha384,ecdhe_ecdsa_with_aes_128_gcm_sha256,ecdhe_rsa_with_aes_128_gcm_sha256,ecdhe_ecdsa_with_chacha20_poly1305,ecdhe_rsa_with_chacha20_poly1305" if aes is supported by hardware, otherwise chacha will be first.
|
||||
;;
|
||||
;; Timeout for any write to the connection. (Set to 0 to disable all timeouts.)
|
||||
;; Timeout for any write to the connection. (Set to -1 to disable all timeouts.)
|
||||
;PER_WRITE_TIMEOUT = 30s
|
||||
;;
|
||||
;; Timeout per Kb written to connections.
|
||||
|
@ -117,7 +117,7 @@ RUN_MODE = ; prod
|
|||
;;
|
||||
;; For the built-in SSH server, choose the key exchange algorithms to support for SSH connections,
|
||||
;; for system SSH this setting has no effect
|
||||
;SSH_SERVER_KEY_EXCHANGES = curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group14-sha1
|
||||
;SSH_SERVER_KEY_EXCHANGES = curve25519-sha256, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1
|
||||
;;
|
||||
;; For the built-in SSH server, choose the MACs to support for SSH connections,
|
||||
;; for system SSH this setting has no effect
|
||||
|
@ -163,7 +163,7 @@ RUN_MODE = ; prod
|
|||
;; Enable exposure of SSH clone URL to anonymous visitors, default is false
|
||||
;SSH_EXPOSE_ANONYMOUS = false
|
||||
;;
|
||||
;; Timeout for any write to ssh connections. (Set to 0 to disable all timeouts.)
|
||||
;; Timeout for any write to ssh connections. (Set to -1 to disable all timeouts.)
|
||||
;; Will default to the PER_WRITE_TIMEOUT.
|
||||
;SSH_PER_WRITE_TIMEOUT = 30s
|
||||
;;
|
||||
|
@ -237,7 +237,7 @@ RUN_MODE = ; prod
|
|||
;; PPROF_DATA_PATH, use an absolute path when you start gitea as service
|
||||
;PPROF_DATA_PATH = data/tmp/pprof
|
||||
;;
|
||||
;; Landing page, can be "home", "explore", "organizations" or "login"
|
||||
;; Landing page, can be "home", "explore", "organizations", "login", or any URL such as "/org/repo" or even "https://anotherwebsite.com"
|
||||
;; The "login" choice is not a security measure but just a UI flow change, use REQUIRE_SIGNIN_VIEW to force users to log in.
|
||||
;LANDING_PAGE = home
|
||||
;;
|
||||
|
@ -398,6 +398,7 @@ INTERNAL_TOKEN=
|
|||
;; By modifying the Gitea database, users can gain Gitea administrator privileges.
|
||||
;; It also enables them to access other resources available to the user on the operating system that is running the Gitea instance and perform arbitrary actions in the name of the Gitea OS user.
|
||||
;; WARNING: This maybe harmful to you website or your operating system.
|
||||
;; WARNING: Setting this to true does not change existing hooks in git repos; adjust it before if necessary.
|
||||
;DISABLE_GIT_HOOKS = true
|
||||
;;
|
||||
;; Set to true to disable webhooks feature.
|
||||
|
@ -424,6 +425,23 @@ INTERNAL_TOKEN=
|
|||
;; This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
|
||||
;SUCCESSFUL_TOKENS_CACHE_SIZE = 20
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[camo]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; At the moment we only support images
|
||||
;;
|
||||
;; if the camo is enabled
|
||||
;ENABLED = false
|
||||
;; url to a camo image proxy, it **is required** if camo is enabled.
|
||||
;SERVER_URL =
|
||||
;; HMAC to encode urls with, it **is required** if camo is enabled.
|
||||
;HMAC_KEY =
|
||||
;; Set to true to use camo for https too lese only non https urls are proxyed
|
||||
;ALLWAYS = false
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[oauth2]
|
||||
|
@ -862,7 +880,7 @@ PATH =
|
|||
;DISABLE_STARS = false
|
||||
;;
|
||||
;; The default branch name of new repositories
|
||||
;DEFAULT_BRANCH = master
|
||||
;DEFAULT_BRANCH = main
|
||||
;;
|
||||
;; Allow adoption of unadopted repositories
|
||||
;ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES = false
|
||||
|
@ -1160,7 +1178,7 @@ PATH =
|
|||
;;
|
||||
;; Control how often the notification endpoint is polled to update the notification
|
||||
;; The timeout will increase to MAX_TIMEOUT in TIMEOUT_STEPs if the notification count is unchanged
|
||||
;; Set MIN_TIMEOUT to 0 to turn off
|
||||
;; Set MIN_TIMEOUT to -1 to turn off
|
||||
;MIN_TIMEOUT = 10s
|
||||
;MAX_TIMEOUT = 60s
|
||||
;TIMEOUT_STEP = 10s
|
||||
|
@ -1245,7 +1263,7 @@ PATH =
|
|||
;ISSUE_INDEXER_NAME = gitea_issues
|
||||
;;
|
||||
;; Timeout the indexer if it takes longer than this to start.
|
||||
;; Set to zero to disable timeout.
|
||||
;; Set to -1 to disable timeout.
|
||||
;STARTUP_TIMEOUT = 30s
|
||||
;;
|
||||
;; Issue indexer queue, currently support: channel, levelqueue or redis, default is levelqueue (deprecated - use [queue.issue_indexer])
|
||||
|
@ -1533,6 +1551,7 @@ PATH =
|
|||
;SENDMAIL_PATH = sendmail
|
||||
;;
|
||||
;; Specify any extra sendmail arguments
|
||||
;; WARNING: if your sendmail program interprets options you should set this to "--" or terminate these args with "--"
|
||||
;SENDMAIL_ARGS =
|
||||
;;
|
||||
;; Timeout for Sendmail
|
||||
|
@ -1563,7 +1582,7 @@ PATH =
|
|||
;HOST =
|
||||
;;
|
||||
;; Time to keep items in cache if not used, default is 16 hours.
|
||||
;; Setting it to 0 disables caching
|
||||
;; Setting it to -1 disables caching
|
||||
;ITEM_TTL = 16h
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1577,7 +1596,7 @@ PATH =
|
|||
;ENABLED = true
|
||||
;;
|
||||
;; Time to keep items in cache if not used, default is 8760 hours.
|
||||
;; Setting it to 0 disables caching
|
||||
;; Setting it to -1 disables caching
|
||||
;ITEM_TTL = 8760h
|
||||
;;
|
||||
;; Only enable the cache when repository's commits count great than
|
||||
|
@ -1751,8 +1770,8 @@ PATH =
|
|||
;ENABLED = true
|
||||
;; Whether to always run at least once at start up time (if ENABLED)
|
||||
;RUN_AT_START = true
|
||||
;; Notice if not success
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;; Whether to emit notice on successful execution too
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;; Time interval for job to run
|
||||
;SCHEDULE = @midnight
|
||||
;; Archives created more than OLDER_THAN ago are subject to deletion
|
||||
|
@ -1771,7 +1790,7 @@ PATH =
|
|||
;; Run Update mirrors task when Gitea starts.
|
||||
;RUN_AT_START = false
|
||||
;; Notice if not success
|
||||
;NO_SUCCESS_NOTICE = true
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;; Limit the number of mirrors added to the queue to this number
|
||||
;; (negative values mean no limit, 0 will result in no result in no mirrors being queued effectively disabling pull mirror updating.)
|
||||
;PULL_LIMIT=50
|
||||
|
@ -1792,7 +1811,7 @@ PATH =
|
|||
;; Run Repository health check task when Gitea starts.
|
||||
;RUN_AT_START = false
|
||||
;; Notice if not success
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;TIMEOUT = 60s
|
||||
;; Arguments for command 'git fsck', e.g. "--unreachable --tags"
|
||||
;; see more on http://git-scm.com/docs/git-fsck
|
||||
|
@ -1810,7 +1829,7 @@ PATH =
|
|||
;; Run check repository statistics task when Gitea starts.
|
||||
;RUN_AT_START = true
|
||||
;; Notice if not success
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;SCHEDULE = @midnight
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1823,7 +1842,7 @@ PATH =
|
|||
;; Update migrated repositories' issues and comments' posterid when starting server (default true)
|
||||
;RUN_AT_START = true
|
||||
;; Notice if not success
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;; Interval as a duration between each synchronization. (default every 24h)
|
||||
;SCHEDULE = @midnight
|
||||
|
||||
|
@ -1838,7 +1857,7 @@ PATH =
|
|||
;; Synchronize external user data when starting server (default false)
|
||||
;RUN_AT_START = false
|
||||
;; Notice if not success
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;; Interval as a duration between each synchronization (default every 24h)
|
||||
;SCHEDULE = @midnight
|
||||
;; Create new users, update existing user data and disable users that are not in external source anymore (default)
|
||||
|
@ -1856,7 +1875,7 @@ PATH =
|
|||
;; Clean-up deleted branches when starting server (default true)
|
||||
;RUN_AT_START = true
|
||||
;; Notice if not success
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;; Interval as a duration between each synchronization (default every 24h)
|
||||
;SCHEDULE = @midnight
|
||||
;; deleted branches than OLDER_THAN ago are subject to deletion
|
||||
|
@ -1882,6 +1901,24 @@ PATH =
|
|||
;; If CLEANUP_TYPE is set to PerWebhook, this is number of hook_task records to keep for a webhook (i.e. keep the most recent x deliveries).
|
||||
;NUMBER_TO_KEEP = 10
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Cleanup expired packages
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;[cron.cleanup_packages]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Whether to enable the job
|
||||
;ENABLED = true
|
||||
;; Whether to always run at least once at start up time (if ENABLED)
|
||||
;RUN_AT_START = true
|
||||
;; Whether to emit notice on successful execution too
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;; Time interval for job to run
|
||||
;SCHEDULE = @midnight
|
||||
;; Unreferenced blobs created more than OLDER_THAN ago are subject to deletion
|
||||
;OLDER_THAN = 24h
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1899,7 +1936,7 @@ PATH =
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;ENABLED = false
|
||||
;RUN_AT_START = false
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;SCHEDULE = @annually
|
||||
;OLDER_THAN = 168h
|
||||
|
||||
|
@ -1912,7 +1949,7 @@ PATH =
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;ENABLED = false
|
||||
;RUN_AT_START = false
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;SCHEDULE = @annually;
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1924,7 +1961,7 @@ PATH =
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;ENABLED = false
|
||||
;RUN_AT_START = false
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;SCHEDULE = @every 72h
|
||||
;TIMEOUT = 60s
|
||||
;; Arguments for command 'git gc'
|
||||
|
@ -1940,7 +1977,7 @@ PATH =
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;ENABLED = false
|
||||
;RUN_AT_START = false
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;SCHEDULE = @every 72h
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1952,7 +1989,7 @@ PATH =
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;ENABLED = false
|
||||
;RUN_AT_START = false
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;SCHEDULE = @every 72h
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1964,7 +2001,7 @@ PATH =
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;ENABLED = false
|
||||
;RUN_AT_START = false
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;SCHEDULE = @every 72h
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1976,7 +2013,7 @@ PATH =
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;ENABLED = false
|
||||
;RUN_AT_START = false
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;SCHEDULE = @every 72h
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1988,7 +2025,7 @@ PATH =
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;ENABLED = false
|
||||
;RUN_AT_START = false
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;SCHEDULE = @every 72h
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -2000,7 +2037,7 @@ PATH =
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;ENABLED = false
|
||||
;RUN_AT_START = false
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;NOTICE_ON_SUCCESS = false
|
||||
;SCHEDULE = @every 168h
|
||||
;OLDER_THAN = 8760h
|
||||
|
||||
|
@ -2017,6 +2054,19 @@ PATH =
|
|||
;SCHEDULE = @every 168h
|
||||
;HTTP_ENDPOINT = https://dl.gitea.io/gitea/version.json
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Delete all old system notices from database
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;[cron.delete_old_system_notices]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;ENABLED = false
|
||||
;RUN_AT_START = false
|
||||
;NO_SUCCESS_NOTICE = false
|
||||
;SCHEDULE = @every 168h
|
||||
;OLDER_THAN = 8760h
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Git Operation timeout in seconds
|
||||
|
@ -2068,6 +2118,7 @@ PATH =
|
|||
;[i18n]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; The first locale will be used as the default if user browser's language doesn't match any locale in the list.
|
||||
;LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN
|
||||
;NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어,ελληνικά,فارسی,magyar nyelv,bahasa Indonesia,മലയാളം
|
||||
|
||||
|
@ -2189,6 +2240,21 @@ PATH =
|
|||
;;
|
||||
;; Enable/Disable federation capabilities
|
||||
; ENABLED = true
|
||||
;;
|
||||
;; Enable/Disable user statistics for nodeinfo if federation is enabled
|
||||
; SHARE_USER_STATISTICS = true
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;[packages]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; Enable/Disable package registry capabilities
|
||||
;ENABLED = true
|
||||
;;
|
||||
;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload`
|
||||
;CHUNKED_UPLOAD_PATH = tmp/package-upload
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -2220,6 +2286,16 @@ PATH =
|
|||
;; Where your lfs files reside, default is data/lfs.
|
||||
;PATH = data/lfs
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; settings for packages, will override storage setting
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;[storage.packages]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; storage type
|
||||
;STORAGE_TYPE = local
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; customize storage
|
||||
|
|
|
@ -49,6 +49,7 @@ if [ -d /etc/ssh ]; then
|
|||
SSH_DSA_CERT="${SSH_DSA_CERT:+"HostCertificate "}${SSH_DSA_CERT}" \
|
||||
SSH_MAX_STARTUPS="${SSH_MAX_STARTUPS:+"MaxStartups "}${SSH_MAX_STARTUPS}" \
|
||||
SSH_MAX_SESSIONS="${SSH_MAX_SESSIONS:+"MaxSessions "}${SSH_MAX_SESSIONS}" \
|
||||
SSH_LOG_LEVEL=${SSH_LOG_LEVEL:-"INFO"} \
|
||||
envsubst < /etc/templates/sshd_config > /etc/ssh/sshd_config
|
||||
|
||||
chmod 0644 /etc/ssh/sshd_config
|
||||
|
|
|
@ -8,7 +8,7 @@ ListenAddress ::
|
|||
${SSH_MAX_STARTUPS}
|
||||
${SSH_MAX_SESSIONS}
|
||||
|
||||
LogLevel INFO
|
||||
LogLevel ${SSH_LOG_LEVEL}
|
||||
|
||||
HostKey /data/ssh/ssh_host_ed25519_key
|
||||
${SSH_ED25519_CERT}
|
||||
|
|
|
@ -18,10 +18,10 @@ params:
|
|||
description: Git with a cup of tea
|
||||
author: The Gitea Authors
|
||||
website: https://docs.gitea.io
|
||||
version: 1.16.3
|
||||
minGoVersion: 1.16
|
||||
goVersion: 1.17
|
||||
minNodeVersion: 12.17
|
||||
version: 1.16.7
|
||||
minGoVersion: 1.17
|
||||
goVersion: 1.18
|
||||
minNodeVersion: 14
|
||||
|
||||
outputs:
|
||||
home:
|
||||
|
|
|
@ -75,7 +75,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
|||
- `PREFIX_ARCHIVE_FILES`: **true**: Prefix archive files by placing them in a directory named after the repository.
|
||||
- `DISABLE_MIGRATIONS`: **false**: Disable migrating feature.
|
||||
- `DISABLE_STARS`: **false**: Disable stars feature.
|
||||
- `DEFAULT_BRANCH`: **master**: Default branch name of all repositories.
|
||||
- `DEFAULT_BRANCH`: **main**: Default branch name of all repositories.
|
||||
- `ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES`: **false**: Allow non-admin users to adopt unadopted repositories
|
||||
- `ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES`: **false**: Allow non-admin users to delete unadopted repositories
|
||||
|
||||
|
@ -206,7 +206,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
|||
|
||||
### UI - Notification (`ui.notification`)
|
||||
|
||||
- `MIN_TIMEOUT`: **10s**: These options control how often notification endpoint is polled to update the notification count. On page load the notification count will be checked after `MIN_TIMEOUT`. The timeout will increase to `MAX_TIMEOUT` by `TIMEOUT_STEP` if the notification count is unchanged. Set MIN_TIMEOUT to 0 to turn off.
|
||||
- `MIN_TIMEOUT`: **10s**: These options control how often notification endpoint is polled to update the notification count. On page load the notification count will be checked after `MIN_TIMEOUT`. The timeout will increase to `MAX_TIMEOUT` by `TIMEOUT_STEP` if the notification count is unchanged. Set MIN_TIMEOUT to -1 to turn off.
|
||||
- `MAX_TIMEOUT`: **60s**.
|
||||
- `TIMEOUT_STEP`: **10s**.
|
||||
- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource` and `SharedWorker`, a `SharedWorker` will be used in preference to polling notification endpoint. Set to **-1** to disable the `EventSource`.
|
||||
|
@ -258,7 +258,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
|||
most cases you do not need to change the default value. Alter it only if
|
||||
your SSH server node is not the same as HTTP node. Do not set this variable
|
||||
if `PROTOCOL` is set to `http+unix`.
|
||||
- `PER_WRITE_TIMEOUT`: **30s**: Timeout for any write to the connection. (Set to 0 to
|
||||
- `PER_WRITE_TIMEOUT`: **30s**: Timeout for any write to the connection. (Set to -1 to
|
||||
disable all timeouts.)
|
||||
- `PER_WRITE_PER_KB_TIMEOUT`: **10s**: Timeout per Kb written to connections.
|
||||
|
||||
|
@ -280,14 +280,14 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
|||
- `SSH_AUTHORIZED_PRINCIPALS_BACKUP`: **false/true**: Enable SSH Authorized Principals Backup when rewriting all keys, default is true if `SSH_AUTHORIZED_PRINCIPALS_ALLOW` is not `off`.
|
||||
- `SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE`: **{{.AppPath}} --config={{.CustomConf}} serv key-{{.Key.ID}}**: Set the template for the command to passed on authorized keys. Possible keys are: AppPath, AppWorkPath, CustomConf, CustomPath, Key - where Key is a `models/asymkey.PublicKey` and the others are strings which are shellquoted.
|
||||
- `SSH_SERVER_CIPHERS`: **chacha20-poly1305@openssh.com, aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, aes256-gcm@openssh.com**: For the built-in SSH server, choose the ciphers to support for SSH connections, for system SSH this setting has no effect.
|
||||
- `SSH_SERVER_KEY_EXCHANGES`: **curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group14-sha1**: For the built-in SSH server, choose the key exchange algorithms to support for SSH connections, for system SSH this setting has no effect.
|
||||
- `SSH_SERVER_KEY_EXCHANGES`: **curve25519-sha256, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1**: For the built-in SSH server, choose the key exchange algorithms to support for SSH connections, for system SSH this setting has no effect.
|
||||
- `SSH_SERVER_MACS`: **hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1**: For the built-in SSH server, choose the MACs to support for SSH connections, for system SSH this setting has no effect
|
||||
- `SSH_SERVER_HOST_KEYS`: **ssh/gitea.rsa, ssh/gogs.rsa**: For the built-in SSH server, choose the keypairs to offer as the host key. The private key should be at `SSH_SERVER_HOST_KEY` and the public `SSH_SERVER_HOST_KEY.pub`. Relative paths are made absolute relative to the `APP_DATA_PATH`. If no key exists a 4096 bit RSA key will be created for you.
|
||||
- `SSH_KEY_TEST_PATH`: **/tmp**: Directory to create temporary files in when testing public keys using ssh-keygen, default is the system temporary directory.
|
||||
- `SSH_KEYGEN_PATH`: **ssh-keygen**: Path to ssh-keygen, default is 'ssh-keygen' which means the shell is responsible for finding out which one to call.
|
||||
- `SSH_EXPOSE_ANONYMOUS`: **false**: Enable exposure of SSH clone URL to anonymous visitors, default is false.
|
||||
- `SSH_PER_WRITE_TIMEOUT`: **30s**: Timeout for any write to the SSH connections. (Set to
|
||||
0 to disable all timeouts.)
|
||||
-1 to disable all timeouts.)
|
||||
- `SSH_PER_WRITE_PER_KB_TIMEOUT`: **10s**: Timeout per Kb written to SSH connections.
|
||||
- `MINIMUM_KEY_SIZE_CHECK`: **true**: Indicate whether to check minimum key size with corresponding type.
|
||||
|
||||
|
@ -300,8 +300,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
|||
- `ENABLE_GZIP`: **false**: Enable gzip compression for runtime-generated content, static resources excluded.
|
||||
- `ENABLE_PPROF`: **false**: Application profiling (memory and cpu). For "web" command it listens on localhost:6060. For "serv" command it dumps to disk at `PPROF_DATA_PATH` as `(cpuprofile|memprofile)_<username>_<temporary id>`
|
||||
- `PPROF_DATA_PATH`: **data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start Gitea as service
|
||||
- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login\].
|
||||
|
||||
- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login, **custom**\]. Where custom would instead be any URL such as "/org/repo" or even `https://anotherwebsite.com`
|
||||
- `LFS_START_SERVER`: **false**: Enables Git LFS support.
|
||||
- `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)/lfs**: Default LFS content path. (if it is on local storage.) **DEPRECATED** use settings in `[lfs]`.
|
||||
- `LFS_JWT_SECRET`: **\<empty\>**: LFS authentication secret, change this a unique string.
|
||||
|
@ -416,7 +415,7 @@ relation to port exhaustion.
|
|||
- `REPO_INDEXER_EXCLUDE_VENDORED`: **true**: Exclude vendored files from index.
|
||||
- `UPDATE_BUFFER_LEN`: **20**: Buffer length of index request. **DEPRECATED** use settings in `[queue.issue_indexer]`.
|
||||
- `MAX_FILE_SIZE`: **1048576**: Maximum size in bytes of files to be indexed.
|
||||
- `STARTUP_TIMEOUT`: **30s**: If the indexer takes longer than this timeout to start - fail. (This timeout will be added to the hammer time above for child processes - as bleve will not start until the previous parent is shutdown.) Set to zero to never timeout.
|
||||
- `STARTUP_TIMEOUT`: **30s**: If the indexer takes longer than this timeout to start - fail. (This timeout will be added to the hammer time above for child processes - as bleve will not start until the previous parent is shutdown.) Set to -1 to never timeout.
|
||||
|
||||
## Queue (`queue` and `queue.*`)
|
||||
|
||||
|
@ -498,6 +497,7 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o
|
|||
It also enables them to access other resources available to the user on the operating system that is running the
|
||||
Gitea instance and perform arbitrary actions in the name of the Gitea OS user.
|
||||
This maybe harmful to you website or your operating system.
|
||||
Setting this to true does not change existing hooks in git repos; adjust it before if necessary.
|
||||
- `DISABLE_WEBHOOKS`: **false**: Set to `true` to disable webhooks feature.
|
||||
- `ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET`: **true**: Set to `false` to allow local users to push to gitea-repositories without setting up the Gitea environment. This is not recommended and if you want local users to push to Gitea repositories you should set the environment appropriately.
|
||||
- `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server.
|
||||
|
@ -515,6 +515,13 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o
|
|||
- `PASSWORD_CHECK_PWN`: **false**: Check [HaveIBeenPwned](https://haveibeenpwned.com/Passwords) to see if a password has been exposed.
|
||||
- `SUCCESSFUL_TOKENS_CACHE_SIZE`: **20**: Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations. This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
|
||||
|
||||
## Camo (`camo`)
|
||||
|
||||
- `ENABLED`: **false**: Enable media proxy, we support images only at the moment.
|
||||
- `SERVER_URL`: **<empty>**: url of camo server, it **is required** if camo is enabled.
|
||||
- `HMAC_KEY`: **<empty>**: Provide the HMAC key for encoding urls, it **is required** if camo is enabled.
|
||||
- `ALLWAYS`: **false**: Set to true to use camo for https too lese only non https urls are proxyed
|
||||
|
||||
## OpenID (`openid`)
|
||||
|
||||
- `ENABLE_OPENID_SIGNIN`: **false**: Allow authentication in via OpenID.
|
||||
|
@ -666,7 +673,7 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
|
|||
- Enabling dummy will ignore all settings except `ENABLED`, `SUBJECT_PREFIX` and `FROM`.
|
||||
- `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be
|
||||
command or full path).
|
||||
- `SENDMAIL_ARGS`: **_empty_**: Specify any extra sendmail arguments.
|
||||
- `SENDMAIL_ARGS`: **_empty_**: Specify any extra sendmail arguments. (NOTE: you should be aware that email addresses can look like options - if your `sendmail` command takes options you must set the option terminator `--`)
|
||||
- `SENDMAIL_TIMEOUT`: **5m**: default timeout for sending email through sendmail
|
||||
- `SENDMAIL_CONVERT_CRLF`: **true**: Most versions of sendmail prefer LF line endings rather than CRLF line endings. Set this to false if your version of sendmail requires CRLF line endings.
|
||||
- `SEND_BUFFER_LEN`: **100**: Buffer length of mailing queue. **DEPRECATED** use `LENGTH` in `[queue.mailer]`
|
||||
|
@ -680,12 +687,12 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
|
|||
- Redis: `redis://: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 0 disables caching.
|
||||
- `ITEM_TTL`: **16h**: Time to keep items in cache if not used, Setting it to -1 disables caching.
|
||||
|
||||
## Cache - LastCommitCache settings (`cache.last_commit`)
|
||||
|
||||
- `ENABLED`: **true**: Enable the cache.
|
||||
- `ITEM_TTL`: **8760h**: Time to keep items in cache if not used, Setting it to 0 disables caching.
|
||||
- `ITEM_TTL`: **8760h**: Time to keep items in cache if not used, Setting it to -1 disables caching.
|
||||
- `COMMITS_COUNT`: **1000**: Only enable the cache when repository's commits count great than.
|
||||
|
||||
## Session (`session`)
|
||||
|
@ -816,7 +823,7 @@ Default templates for project boards:
|
|||
|
||||
- `ENABLED`: **false**: Enable to run all cron tasks periodically with default settings.
|
||||
- `RUN_AT_START`: **false**: Run cron tasks at application start-up.
|
||||
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
|
||||
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
|
||||
|
||||
- `SCHEDULE` accept formats
|
||||
- Full crontab specs, e.g. `* * * * * ?`
|
||||
|
@ -835,7 +842,6 @@ Default templates for project boards:
|
|||
#### Cron - Update Mirrors (`cron.update_mirrors`)
|
||||
|
||||
- `SCHEDULE`: **@every 10m**: Cron syntax for scheduling update mirrors, e.g. `@every 3h`.
|
||||
- `NO_SUCCESS_NOTICE`: **true**: The cron task for update mirrors success report is not very useful - as it just means that the mirrors have been queued. Therefore this is turned off by default.
|
||||
- `PULL_LIMIT`: **50**: Limit the number of mirrors added to the queue to this number (negative values mean no limit, 0 will result in no mirrors being queued effectively disabling pull mirror updating).
|
||||
- `PUSH_LIMIT`: **50**: Limit the number of mirrors added to the queue to this number (negative values mean no limit, 0 will result in no mirrors being queued effectively disabling push mirror updating).
|
||||
|
||||
|
@ -850,7 +856,7 @@ Default templates for project boards:
|
|||
- `RUN_AT_START`: **true**: Run repository statistics check at start time.
|
||||
- `SCHEDULE`: **@midnight**: Cron syntax for scheduling repository statistics check.
|
||||
|
||||
### Cron - Cleanup hook_task Table (`cron.cleanup_hook_task_table`)
|
||||
#### Cron - Cleanup hook_task Table (`cron.cleanup_hook_task_table`)
|
||||
|
||||
- `ENABLED`: **true**: Enable cleanup hook_task job.
|
||||
- `RUN_AT_START`: **false**: Run cleanup hook_task at start time (if ENABLED).
|
||||
|
@ -859,6 +865,14 @@ Default templates for project boards:
|
|||
- `OLDER_THAN`: **168h**: If CLEANUP_TYPE is set to OlderThan, then any delivered hook_task records older than this expression will be deleted.
|
||||
- `NUMBER_TO_KEEP`: **10**: If CLEANUP_TYPE is set to PerWebhook, this is number of hook_task records to keep for a webhook (i.e. keep the most recent x deliveries).
|
||||
|
||||
#### Cron - Cleanup expired packages (`cron.cleanup_packages`)
|
||||
|
||||
- `ENABLED`: **true**: Enable cleanup expired packages job.
|
||||
- `RUN_AT_START`: **true**: Run job at start time (if ENABLED).
|
||||
- `NOTICE_ON_SUCCESS`: **false**: Notify every time this job runs.
|
||||
- `SCHEDULE`: **@midnight**: Cron syntax for the job.
|
||||
- `OLDER_THAN`: **24h**: Unreferenced package data created more than OLDER_THAN ago is subject to deletion.
|
||||
|
||||
#### Cron - Update Migration Poster ID (`cron.update_migration_poster_id`)
|
||||
|
||||
- `SCHEDULE`: **@midnight** : Interval as a duration between each synchronization, it will always attempt synchronization when the instance starts.
|
||||
|
@ -875,43 +889,43 @@ Default templates for project boards:
|
|||
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
||||
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
|
||||
- `TIMEOUT`: **60s**: Time duration syntax for garbage collection execution timeout.
|
||||
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
|
||||
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
|
||||
- `ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`. The default value is same with [git] -> GC_ARGS
|
||||
|
||||
#### Cron - Update the '.ssh/authorized_keys' file with Gitea SSH keys ('cron.resync_all_sshkeys')
|
||||
- `ENABLED`: **false**: Enable service.
|
||||
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
||||
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
|
||||
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
|
||||
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
|
||||
|
||||
#### Cron - Resynchronize pre-receive, update and post-receive hooks of all repositories ('cron.resync_all_hooks')
|
||||
- `ENABLED`: **false**: Enable service.
|
||||
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
||||
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
|
||||
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
|
||||
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
|
||||
|
||||
#### Cron - Reinitialize all missing Git repositories for which records exist ('cron.reinit_missing_repos')
|
||||
- `ENABLED`: **false**: Enable service.
|
||||
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
||||
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
|
||||
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
|
||||
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
|
||||
|
||||
#### Cron - Delete all repositories missing their Git files ('cron.delete_missing_repos')
|
||||
- `ENABLED`: **false**: Enable service.
|
||||
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
||||
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
|
||||
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
|
||||
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
|
||||
|
||||
#### Cron - Delete generated repository avatars ('cron.delete_generated_repository_avatars')
|
||||
- `ENABLED`: **false**: Enable service.
|
||||
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
||||
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
|
||||
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
|
||||
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
|
||||
|
||||
#### Cron - Delete all old actions from database ('cron.delete_old_actions')
|
||||
- `ENABLED`: **false**: Enable service.
|
||||
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
||||
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
|
||||
- `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.
|
||||
|
||||
|
@ -922,6 +936,13 @@ Default templates for project boards:
|
|||
- `SCHEDULE`: **@every 168h**: Cron syntax for scheduling a work, e.g. `@every 168h`.
|
||||
- `HTTP_ENDPOINT`: **https://dl.gitea.io/gitea/version.json**: the endpoint that Gitea will check for newer versions
|
||||
|
||||
#### Cron - Delete all old system notices from database ('cron.delete_old_system_notices')
|
||||
- `ENABLED`: **false**: Enable service.
|
||||
- `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.
|
||||
|
||||
## Git (`git`)
|
||||
|
||||
- `PATH`: **""**: The path of Git executable. If empty, Gitea searches through the PATH environment.
|
||||
|
@ -976,7 +997,8 @@ Default templates for project boards:
|
|||
|
||||
## i18n (`i18n`)
|
||||
|
||||
- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN**: List of locales shown in language selector
|
||||
- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN**:
|
||||
List of locales shown in language selector. The first locale will be used as the default if user browser's language doesn't match any locale in the list.
|
||||
- `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어,ελληνικά,فارسی,magyar nyelv,bahasa Indonesia,മലയാളം**: Visible names corresponding to the locales
|
||||
|
||||
## U2F (`U2F`) **DEPRECATED**
|
||||
|
@ -1063,6 +1085,12 @@ Task queue configuration has been moved to `queue.task`. However, the below conf
|
|||
## Federation (`federation`)
|
||||
|
||||
- `ENABLED`: **true**: Enable/Disable federation capabilities
|
||||
- `SHARE_USER_STATISTICS`: **true**: Enable/Disable user statistics for nodeinfo if federation is enabled
|
||||
|
||||
## Packages (`packages`)
|
||||
|
||||
- `ENABLED`: **true**: Enable/Disable package registry capabilities
|
||||
- `CHUNKED_UPLOAD_PATH`: **tmp/package-upload**: Path for chunked uploads. Defaults to `APP_DATA_PATH` + `tmp/package-upload`
|
||||
|
||||
## Mirror (`mirror`)
|
||||
|
||||
|
|
|
@ -175,12 +175,12 @@ menu:
|
|||
- `HOST`: **\<empty\>**: 针对redis和memcache有效,主机地址和端口。
|
||||
- Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180`
|
||||
- Memache: `127.0.0.1:9090;127.0.0.1:9091`
|
||||
- `ITEM_TTL`: **16h**: 缓存项目失效时间,设置为 0 则禁用缓存。
|
||||
- `ITEM_TTL`: **16h**: 缓存项目失效时间,设置为 -1 则禁用缓存。
|
||||
|
||||
## Cache - LastCommitCache settings (`cache.last_commit`)
|
||||
|
||||
- `ENABLED`: **true**: 是否启用。
|
||||
- `ITEM_TTL`: **8760h**: 缓存项目失效时间,设置为 0 则禁用缓存。
|
||||
- `ITEM_TTL`: **8760h**: 缓存项目失效时间,设置为 -1 则禁用缓存。
|
||||
- `COMMITS_COUNT`: **1000**: 仅当仓库的提交数大于时才启用缓存。
|
||||
|
||||
## Session (`session`)
|
||||
|
|
|
@ -132,15 +132,18 @@ copy javascript files from https://gitea.com/davidsvantesson/plantuml-code-highl
|
|||
`$GITEA_CUSTOM/public` folder. Then add the following to `custom/footer.tmpl`:
|
||||
|
||||
```html
|
||||
{{if .RequireHighlightJS}}
|
||||
<script src="https://your-server.com/deflate.js"></script>
|
||||
<script src="https://your-server.com/encode.js"></script>
|
||||
<script src="https://your-server.com/plantuml_codeblock_parse.js"></script>
|
||||
<script>
|
||||
<!-- Replace call with address to your plantuml server-->
|
||||
parsePlantumlCodeBlocks("http://www.plantuml.com/plantuml");
|
||||
$(async () => {
|
||||
if (!$('.language-plantuml').length) return;
|
||||
await Promise.all([
|
||||
$.getScript('https://your-server.com/deflate.js'),
|
||||
$.getScript('https://your-server.com/encode.js'),
|
||||
$.getScript('https://your-server.com/plantuml_codeblock_parse.js'),
|
||||
]);
|
||||
// Replace call with address to your plantuml server
|
||||
parsePlantumlCodeBlocks("https://www.plantuml.com/plantuml");
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
||||
```
|
||||
|
||||
You can then add blocks like the following to your markdown:
|
||||
|
@ -299,6 +302,8 @@ LANGS = en-US,foo-BAR
|
|||
NAMES = English,FooBar
|
||||
```
|
||||
|
||||
The first locale will be used as the default if user browser's language doesn't match any locale in the list.
|
||||
|
||||
Locales may change between versions, so keeping track of your customized locales is highly encouraged.
|
||||
|
||||
### Readmes
|
||||
|
|
|
@ -287,6 +287,7 @@ MODE = console
|
|||
LEVEL = debug ; please set the level to debug when we are debugging a problem
|
||||
ROUTER = console
|
||||
COLORIZE = false ; this can be true if you can strip out the ansi coloring
|
||||
ENABLE_SSH_LOG = true ; shows logs related to git over SSH.
|
||||
```
|
||||
|
||||
Sometimes it will be helpful get some specific `TRACE` level logging restricted
|
||||
|
|
|
@ -8,6 +8,6 @@ draft: false
|
|||
menu:
|
||||
sidebar:
|
||||
name: "Developers"
|
||||
weight: 50
|
||||
weight: 55
|
||||
identifier: "developers"
|
||||
---
|
||||
|
|
|
@ -8,6 +8,6 @@ draft: false
|
|||
menu:
|
||||
sidebar:
|
||||
name: "開發人員"
|
||||
weight: 50
|
||||
weight: 55
|
||||
identifier: "developers"
|
||||
---
|
||||
|
|
|
@ -42,7 +42,7 @@ To maintain understandable code and avoid circular dependencies it is important
|
|||
- `modules/setting`: Store all system configurations read from ini files and has been referenced by everywhere. But they should be used as function parameters when possible.
|
||||
- `modules/git`: Package to interactive with `Git` command line or Gogit package.
|
||||
- `public`: Compiled frontend files (javascript, images, css, etc.)
|
||||
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers.
|
||||
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) must not depend on routers.
|
||||
- `routers/api` Contains routers for `/api/v1` aims to handle RESTful API requests.
|
||||
- `routers/install` Could only respond when system is in INSTALL mode (INSTALL_LOCK=false).
|
||||
- `routers/private` will only be invoked by internal sub commands, especially `serv` and `hooks`.
|
||||
|
@ -106,10 +106,20 @@ i.e. `servcies/user`, `models/repository`.
|
|||
Since there are some packages which use the same package name, it is possible that you find packages like `modules/user`, `models/user`, and `services/user`. When these packages are imported in one Go file, it's difficult to know which package we are using and if it's a variable name or an import name. So, we always recommend to use import aliases. To differ from package variables which are commonly in camelCase, just use **snake_case** for import aliases.
|
||||
i.e. `import user_service "code.gitea.io/gitea/services/user"`
|
||||
|
||||
### Important Gotchas
|
||||
|
||||
- Never write `x.Update(exemplar)` without an explicit `WHERE` clause:
|
||||
- This will cause all rows in the table to be updated with the non-zero values of the exemplar - including IDs.
|
||||
- You should usually write `x.ID(id).Update(exemplar)`.
|
||||
- If during a migration you are inserting into a table using `x.Insert(exemplar)` where the ID is preset:
|
||||
- You will need to ``SET IDENTITY_INSERT `table` ON`` for the MSSQL variant (the migration will fail otherwise)
|
||||
- However, you will also need to update the id sequence for postgres - the migration will silently pass here but later insertions will fail:
|
||||
``SELECT setval('table_name_id_seq', COALESCE((SELECT MAX(id)+1 FROM `table_name`), 1), false)``
|
||||
|
||||
### Future Tasks
|
||||
|
||||
Currently, we are creating some refactors to do the following things:
|
||||
|
||||
- Correct that codes which doesn't follow the rules.
|
||||
- There are too many files in `models`, so we are moving some of them into a sub package `models/xxx`.
|
||||
- Some `modules` sub packages should be moved to `services` because they depends on `models`.
|
||||
- Some `modules` sub packages should be moved to `services` because they depend on `models`.
|
||||
|
|
|
@ -23,7 +23,13 @@ menu:
|
|||
|
||||
Gitea uses [Less CSS](https://lesscss.org), [Fomantic-UI](https://fomantic-ui.com/introduction/getting-started.html) (based on [jQuery](https://api.jquery.com)) and [Vue2](https://vuejs.org/v2/guide/) for its frontend.
|
||||
|
||||
The HTML pages are rendered by [Go HTML Template](https://pkg.go.dev/html/template)
|
||||
The HTML pages are rendered by [Go HTML Template](https://pkg.go.dev/html/template).
|
||||
|
||||
The source files can be found in the following directories:
|
||||
* **Less styles:** `web_src/less/`
|
||||
* **Javascript files:** `web_src/js/`
|
||||
* **Vue layouts:** `web_src/js/components/`
|
||||
* **HTML templates:** `templates/`
|
||||
|
||||
## General Guidelines
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ _Symbols used in table:_
|
|||
## General Features
|
||||
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE |
|
||||
| ----------------------------------- | -------------------------------------------------- | ---- | --------- | --------- | --------- | -------------- | ------------ |
|
||||
| ----------------------------------- | ---------------------------------------------------| ---- | --------- | --------- | --------- | -------------- | ------------ |
|
||||
| Open source and free | ✓ | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ |
|
||||
| Low resource usage (RAM/CPU) | ✓ | ✓ | ✘ | ✘ | ✘ | ✘ | ✘ |
|
||||
| Multiple database support | ✓ | ✓ | ✘ | ⁄ | ⁄ | ✓ | ✓ |
|
||||
|
@ -48,7 +48,7 @@ _Symbols used in table:_
|
|||
| Integrated Git-powered wiki | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ (cloud only) | ✘ |
|
||||
| Deploy Tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Repository Tokens with write rights | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Built-in Container Registry | [✘](https://github.com/go-gitea/gitea/issues/2316) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Built-in Package/Container Registry | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| External git mirroring | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ |
|
||||
| WebAuthn (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ? |
|
||||
| Built-in CI/CD | ✘ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
|
|
|
@ -50,7 +50,8 @@ Of note, configuring `GITEA_WORK_DIR` will tell Gitea where to base its working
|
|||
|
||||
### Prepare environment
|
||||
|
||||
Check that Git is installed on the server. If it is not, install it first.
|
||||
Check that Git is installed on the server. If it is not, install it first. Gitea requires Git version >= 2.0.
|
||||
|
||||
```sh
|
||||
git --version
|
||||
```
|
||||
|
|
|
@ -25,3 +25,47 @@ helm install gitea gitea-charts/gitea
|
|||
```
|
||||
|
||||
If you would like to customize your install, which includes kubernetes ingress, please refer to the complete [Gitea helm chart configuration details](https://gitea.com/gitea/helm-chart/)
|
||||
|
||||
## Health check endpoint
|
||||
|
||||
Gitea comes with a health check endpoint `/api/healthz`, you can configure it in kubernetes like this:
|
||||
|
||||
```yaml
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/healthz
|
||||
port: http
|
||||
initialDelaySeconds: 200
|
||||
timeoutSeconds: 5
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
failureThreshold: 10
|
||||
```
|
||||
|
||||
a successful health check response will respond with http code `200`, here's example:
|
||||
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
|
||||
|
||||
{
|
||||
"status": "pass",
|
||||
"description": "Gitea: Git with a cup of tea",
|
||||
"checks": {
|
||||
"cache:ping": [
|
||||
{
|
||||
"status": "pass",
|
||||
"time": "2022-02-19T09:16:08Z"
|
||||
}
|
||||
],
|
||||
"database:ping": [
|
||||
{
|
||||
"status": "pass",
|
||||
"time": "2022-02-19T09:16:08Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
for more information, please reference to kubernetes documentation [Define a liveness HTTP request](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-liveness-http-request)
|
||||
|
|
|
@ -25,3 +25,47 @@ helm install gitea gitea-charts/gitea
|
|||
```
|
||||
|
||||
若您想自訂安裝(包括使用 kubernetes ingress),請前往完整的 [Gitea helm chart configuration details](https://gitea.com/gitea/helm-chart/)
|
||||
|
||||
##運行狀況檢查終端節點
|
||||
|
||||
Gitea 附帶了一個運行狀況檢查端點 `/api/healthz`,你可以像這樣在 kubernetes 中配置它:
|
||||
|
||||
```yaml
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/healthz
|
||||
port: http
|
||||
initialDelaySeconds: 200
|
||||
timeoutSeconds: 5
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
failureThreshold: 10
|
||||
```
|
||||
|
||||
成功的運行狀況檢查回應將使用 HTTP 代碼 `200` 進行回應,下面是示例:
|
||||
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
|
||||
|
||||
{
|
||||
"status": "pass",
|
||||
"description": "Gitea: Git with a cup of tea",
|
||||
"checks": {
|
||||
"cache:ping": [
|
||||
{
|
||||
"status": "pass",
|
||||
"time": "2022-02-19T09:16:08Z"
|
||||
}
|
||||
],
|
||||
"database:ping": [
|
||||
{
|
||||
"status": "pass",
|
||||
"time": "2022-02-19T09:16:08Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
有關更多信息,請參考kubernetes文檔[定義一個存活態 HTTP請求接口](https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/)
|
||||
|
|
|
@ -147,7 +147,7 @@ services:
|
|||
+ - db
|
||||
+
|
||||
+ db:
|
||||
+ image: postgres:13
|
||||
+ image: postgres:14
|
||||
+ restart: always
|
||||
+ environment:
|
||||
+ - POSTGRES_USER=gitea
|
||||
|
|
|
@ -187,7 +187,7 @@ services:
|
|||
+ - db
|
||||
+
|
||||
+ db:
|
||||
+ image: postgres:13
|
||||
+ image: postgres:14
|
||||
+ restart: always
|
||||
+ environment:
|
||||
+ - POSTGRES_USER=gitea
|
||||
|
@ -590,7 +590,7 @@ Add the following block to `/etc/ssh/sshd_config`, on the host:
|
|||
```bash
|
||||
Match User git
|
||||
AuthorizedKeysCommandUser git
|
||||
AuthorizedKeysCommand ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k
|
||||
AuthorizedKeysCommand /usr/bin/ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k
|
||||
```
|
||||
|
||||
(From 1.16.0 you will not need to set the `-c /data/gitea/conf/app.ini` option.)
|
||||
|
|
|
@ -43,7 +43,7 @@ Vous devriez avoir une instance fonctionnelle de Gitea. Pour accèder à l'inter
|
|||
|
||||
## Named Volumes
|
||||
|
||||
Ce guide aboutira à une installation avec les données Gita et PostgreSQL stockées dans des volumes nommés. Cela permet une sauvegarde, une restauration et des mises à niveau en toute simplicité.
|
||||
Ce guide aboutira à une installation avec les données Gitea et PostgreSQL stockées dans des volumes nommés. Cela permet une sauvegarde, une restauration et des mises à niveau en toute simplicité.
|
||||
|
||||
### The Database
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ services:
|
|||
+ - db
|
||||
+
|
||||
+ db:
|
||||
+ image: postgres:13
|
||||
+ image: postgres:14
|
||||
+ restart: always
|
||||
+ environment:
|
||||
+ - POSTGRES_USER=gitea
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "Package Registry"
|
||||
slug: "packages"
|
||||
toc: false
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
name: "Package Registry"
|
||||
weight: 45
|
||||
identifier: "packages"
|
||||
---
|
|
@ -0,0 +1,120 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "Composer Packages Repository"
|
||||
slug: "packages/composer"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "Composer"
|
||||
weight: 10
|
||||
identifier: "composer"
|
||||
---
|
||||
|
||||
# Composer Packages Repository
|
||||
|
||||
Publish [Composer](https://getcomposer.org/) packages for your user or organization.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the Composer package registry, you can use [Composer](https://getcomposer.org/download/) to consume and a HTTP upload client like `curl` to publish packages.
|
||||
|
||||
## Publish a package
|
||||
|
||||
To publish a Composer package perform a HTTP PUT operation with the package content in the request body.
|
||||
The package content must be the zipped PHP project with the `composer.json` file.
|
||||
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
|
||||
|
||||
```
|
||||
PUT https://gitea.example.com/api/packages/{owner}/composer
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ---------- | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
|
||||
If the `composer.json` file does not contain a `version` property, you must provide it as a query parameter:
|
||||
|
||||
```
|
||||
PUT https://gitea.example.com/api/packages/{owner}/composer?version={x.y.z}
|
||||
```
|
||||
|
||||
Example request using HTTP Basic authentication:
|
||||
|
||||
```shell
|
||||
curl --user your_username:your_password_or_token \
|
||||
--upload-file path/to/project.zip \
|
||||
https://gitea.example.com/api/packages/testuser/composer
|
||||
```
|
||||
|
||||
Or specify the package version as query parameter:
|
||||
|
||||
```shell
|
||||
curl --user your_username:your_password_or_token \
|
||||
--upload-file path/to/project.zip \
|
||||
https://gitea.example.com/api/packages/testuser/composer?version=1.0.3
|
||||
```
|
||||
|
||||
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 and/or version are invalid or a package with the same name and version already exist. |
|
||||
|
||||
## Configuring the package registry
|
||||
|
||||
To register the package registry you need to add it to the Composer `config.json` file (which can usually be found under `<user-home-dir>/.composer/config.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"repositories": [{
|
||||
"type": "composer",
|
||||
"url": "https://gitea.example.com/api/packages/{owner}/composer"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
To access the package registry using credentials, you must specify them in the `auth.json` file as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"http-basic": {
|
||||
"gitea.example.com": {
|
||||
"username": "{username}",
|
||||
"password": "{password}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ---------- | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
| `username` | Your Gitea username. |
|
||||
| `password` | Your Gitea password or a personal access token. |
|
||||
|
||||
## Install a package
|
||||
|
||||
To install a package from the package registry, execute the following command:
|
||||
|
||||
```shell
|
||||
composer require {package_name}
|
||||
```
|
||||
|
||||
Optional you can specify the package version:
|
||||
|
||||
```shell
|
||||
composer require {package_name}:{package_version}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------------- | ----------- |
|
||||
| `package_name` | The package name. |
|
||||
| `package_version` | The package version. |
|
|
@ -0,0 +1,101 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "Conan Packages Repository"
|
||||
slug: "packages/conan"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "Conan"
|
||||
weight: 20
|
||||
identifier: "conan"
|
||||
---
|
||||
|
||||
# Conan Packages Repository
|
||||
|
||||
Publish [Conan](https://conan.io/) packages for your user or organization.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the Conan package registry, you need to use the [conan](https://conan.io/downloads.html) command line tool to consume and publish packages.
|
||||
|
||||
## Configuring the package registry
|
||||
|
||||
To register the package registry you need to configure a new Conan remote:
|
||||
|
||||
```shell
|
||||
conan remote add {remote} https://gitea.example.com/api/packages/{owner}/conan
|
||||
conan user --remote {remote} --password {password} {username}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| -----------| ----------- |
|
||||
| `remote` | The remote name. |
|
||||
| `username` | Your Gitea username. |
|
||||
| `password` | Your Gitea password or a personal access token. |
|
||||
| `owner` | The owner of the package. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
conan remote add gitea https://gitea.example.com/api/packages/testuser/conan
|
||||
conan user --remote gitea --password password123 testuser
|
||||
```
|
||||
|
||||
## Publish a package
|
||||
|
||||
Publish a Conan package by running the following command:
|
||||
|
||||
```shell
|
||||
conan upload --remote={remote} {recipe}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------| ----------- |
|
||||
| `remote` | The remote name. |
|
||||
| `recipe` | The recipe to upload. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
conan upload --remote=gitea ConanPackage/1.2@gitea/final
|
||||
```
|
||||
|
||||
The Gitea Conan package registry has full [revision](https://docs.conan.io/en/latest/versioning/revisions.html) support.
|
||||
|
||||
## Install a package
|
||||
|
||||
To install a Conan package from the package registry, execute the following command:
|
||||
|
||||
```shell
|
||||
conan install --remote={remote} {recipe}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------| ----------- |
|
||||
| `remote` | The remote name. |
|
||||
| `recipe` | The recipe to download. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
conan install --remote=gitea ConanPackage/1.2@gitea/final
|
||||
```
|
||||
|
||||
## Supported commands
|
||||
|
||||
```
|
||||
conan install
|
||||
conan get
|
||||
conan info
|
||||
conan search
|
||||
conan upload
|
||||
conan user
|
||||
conan download
|
||||
conan remove
|
||||
```
|
|
@ -0,0 +1,91 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "Container Registry"
|
||||
slug: "packages/container"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "Container Registry"
|
||||
weight: 30
|
||||
identifier: "container"
|
||||
---
|
||||
|
||||
# Container Registry
|
||||
|
||||
Publish [Open Container Initiative](https://opencontainers.org/) compliant images for your user or organization.
|
||||
The container registry follows the OCI specs and supports all compatible images like [Docker](https://www.docker.com/) and [Helm Charts](https://helm.sh/).
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the Container registry, you can use the tools for your specific image type.
|
||||
The following examples use the `docker` client.
|
||||
|
||||
## Login to the container registry
|
||||
|
||||
To push an image or if the image is in a private registry, you have to authenticate:
|
||||
|
||||
```shell
|
||||
docker login gitea.example.com
|
||||
```
|
||||
|
||||
## Image naming convention
|
||||
|
||||
Images must follow this naming convention:
|
||||
|
||||
`{registry}/{owner}/{image}`
|
||||
|
||||
For example, these are all valid image names for the owner `testuser`:
|
||||
|
||||
`gitea.example.com/testuser/myimage`
|
||||
|
||||
`gitea.example.com/testuser/my-image`
|
||||
|
||||
`gitea.example.com/testuser/my/image`
|
||||
|
||||
**NOTE:** The registry only supports case-insensitive tag names. So `image:tag` and `image:Tag` get treated as the same image and tag.
|
||||
|
||||
## Push an image
|
||||
|
||||
Push an image by executing the following command:
|
||||
|
||||
```shell
|
||||
docker push gitea.example.com/{owner}/{image}:{tag}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------| ----------- |
|
||||
| `owner` | The owner of the image. |
|
||||
| `image` | The name of the image. |
|
||||
| `tag` | The tag of the image. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
docker push gitea.example.com/testuser/myimage:latest
|
||||
```
|
||||
|
||||
## Pull an image
|
||||
|
||||
Pull an image by executing the following command:
|
||||
|
||||
```shell
|
||||
docker pull gitea.example.com/{owner}/{image}:{tag}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------| ----------- |
|
||||
| `owner` | The owner of the image. |
|
||||
| `image` | The name of the image. |
|
||||
| `tag` | The tag of the image. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
docker pull gitea.example.com/testuser/myimage:latest
|
||||
```
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "Generic Packages Repository"
|
||||
slug: "packages/generic"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "Generic"
|
||||
weight: 40
|
||||
identifier: "generic"
|
||||
---
|
||||
|
||||
# Generic Packages Repository
|
||||
|
||||
Publish generic files, like release binaries or other output, for your user or organization.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Authenticate to the package registry
|
||||
|
||||
To authenticate to the Package Registry, you need to provide [custom HTTP headers or use HTTP Basic authentication]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}).
|
||||
|
||||
## Publish a package
|
||||
|
||||
To publish a generic 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.
|
||||
|
||||
```
|
||||
PUT https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version}/{file_name}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------------- | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
| `package_name` | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`). |
|
||||
| `package_version` | The package version as described in the [SemVer](https://semver.org/) spec. |
|
||||
| `file_name` | The filename. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`). |
|
||||
|
||||
Example request using HTTP Basic authentication:
|
||||
|
||||
```shell
|
||||
curl --user your_username:your_password_or_token \
|
||||
--upload-file path/to/file.bin \
|
||||
https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin
|
||||
```
|
||||
|
||||
The server reponds with the following HTTP Status codes.
|
||||
|
||||
| HTTP Status Code | Meaning |
|
||||
| ----------------- | ------- |
|
||||
| `201 Created` | The package has been published. |
|
||||
| `400 Bad Request` | The package name and/or version are invalid or a package with the same name and version already exist. |
|
||||
|
||||
## Download a package
|
||||
|
||||
To download a generic package perform a HTTP GET operation.
|
||||
|
||||
```
|
||||
GET https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version}/{file_name}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------------- | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
| `package_name` | The package name. |
|
||||
| `package_version` | The package version. |
|
||||
| `file_name` | The filename. |
|
||||
|
||||
The file content is served in the response body. The response content type is `application/octet-stream`.
|
||||
|
||||
Example request using HTTP Basic authentication:
|
||||
|
||||
```shell
|
||||
curl --user your_username:your_token_or_password \
|
||||
https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin
|
||||
```
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
date: "2022-04-14T00:00:00+00:00"
|
||||
title: "Helm Chart Registry"
|
||||
slug: "packages/helm"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "Helm"
|
||||
weight: 50
|
||||
identifier: "helm"
|
||||
---
|
||||
|
||||
# Helm Chart Registry
|
||||
|
||||
Publish [Helm](https://helm.sh/) charts for your user or organization.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the Helm Chart registry use a simple HTTP client like `curl` or the [`helm cm-push`](https://github.com/chartmuseum/helm-push/) plugin.
|
||||
|
||||
## Publish a package
|
||||
|
||||
Publish a package by running the following command:
|
||||
|
||||
```shell
|
||||
curl --user {username}:{password} -X POST --upload-file ./{chart_file}.tgz https://gitea.example.com/api/packages/{owner}/helm/api/charts
|
||||
```
|
||||
|
||||
or with the `helm cm-push` plugin:
|
||||
|
||||
```shell
|
||||
helm repo add --username {username} --password {password} {repo} https://gitea.example.com/api/packages/{owner}/helm
|
||||
helm cm-push ./{chart_file}.tgz {repo}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------ | ----------- |
|
||||
| `username` | Your Gitea username. |
|
||||
| `password` | Your Gitea password or a personal access token. |
|
||||
| `repo` | The name for the repository. |
|
||||
| `chart_file` | The Helm Chart archive. |
|
||||
| `owner` | The owner of the package. |
|
||||
|
||||
## Install a package
|
||||
|
||||
To install a Helm char from the registry, execute the following command:
|
||||
|
||||
```shell
|
||||
helm repo add --username {username} --password {password} {repo} https://gitea.example.com/api/packages/{owner}/helm
|
||||
helm repo update
|
||||
helm install {name} {repo}/{chart}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ---------- | ----------- |
|
||||
| `username` | Your Gitea username. |
|
||||
| `password` | Your Gitea password or a personal access token. |
|
||||
| `repo` | The name for the repository. |
|
||||
| `owner` | The owner of the package. |
|
||||
| `name` | The local name. |
|
||||
| `chart` | The name Helm Chart. |
|
|
@ -0,0 +1,110 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "Maven Packages Repository"
|
||||
slug: "packages/maven"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "Maven"
|
||||
weight: 60
|
||||
identifier: "maven"
|
||||
---
|
||||
|
||||
# Maven Packages Repository
|
||||
|
||||
Publish [Maven](https://maven.apache.org) packages for your user or organization.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the Maven package registry, you can use [Maven](https://maven.apache.org/install.html) or [Gradle](https://gradle.org/install/).
|
||||
The following examples use `Maven`.
|
||||
|
||||
## Configuring the package registry
|
||||
|
||||
To register the package registry you first need to add your access token to the [`settings.xml`](https://maven.apache.org/settings.html) file:
|
||||
|
||||
```xml
|
||||
<settings>
|
||||
<servers>
|
||||
<server>
|
||||
<id>gitea</id>
|
||||
<configuration>
|
||||
<httpHeaders>
|
||||
<property>
|
||||
<name>Authorization</name>
|
||||
<value>token {access_token}</value>
|
||||
</property>
|
||||
</httpHeaders>
|
||||
</configuration>
|
||||
</server>
|
||||
</servers>
|
||||
</settings>
|
||||
```
|
||||
|
||||
Afterwards add the following sections to your project `pom.xml` file:
|
||||
|
||||
```xml
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>gitea</id>
|
||||
<url>https://gitea.example.com/api/packages/{owner}/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>gitea</id>
|
||||
<url>https://gitea.example.com/api/packages/{owner}/maven</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>gitea</id>
|
||||
<url>https://gitea.example.com/api/packages/{owner}/maven</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| -------------- | ----------- |
|
||||
| `access_token` | Your [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}). |
|
||||
| `owner` | The owner of the package. |
|
||||
|
||||
## Publish a package
|
||||
|
||||
To publish a package simply run:
|
||||
|
||||
```shell
|
||||
mvn deploy
|
||||
```
|
||||
|
||||
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
|
||||
|
||||
## Install a package
|
||||
|
||||
To install a Maven package from the package registry, add a new dependency to your project `pom.xml` file:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.test.package</groupId>
|
||||
<artifactId>test_project</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Afterwards run:
|
||||
|
||||
```shell
|
||||
mvn install
|
||||
```
|
||||
|
||||
## Supported commands
|
||||
|
||||
```
|
||||
mvn install
|
||||
mvn deploy
|
||||
mvn dependency:get:
|
||||
```
|
|
@ -0,0 +1,118 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "npm Packages Repository"
|
||||
slug: "packages/npm"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "npm"
|
||||
weight: 70
|
||||
identifier: "npm"
|
||||
---
|
||||
|
||||
# npm Packages Repository
|
||||
|
||||
Publish [npm](https://www.npmjs.com/) packages for your user or organization.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the npm package registry, you need [Node.js](https://nodejs.org/en/download/) coupled with a package manager such as [Yarn](https://classic.yarnpkg.com/en/docs/install) or [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm/) itself.
|
||||
|
||||
The registry supports [scoped](https://docs.npmjs.com/misc/scope/) and unscoped packages.
|
||||
|
||||
The following examples use the `npm` tool with the scope `@test`.
|
||||
|
||||
## Configuring the package registry
|
||||
|
||||
To register the package registry you need to configure a new package source.
|
||||
|
||||
```shell
|
||||
npm config set {scope}:registry https://gitea.example.com/api/packages/{owner}/npm/
|
||||
npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{token}"
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------ | ----------- |
|
||||
| `scope` | The scope of the packages. |
|
||||
| `owner` | The owner of the package. |
|
||||
| `token` | Your [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}). |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
npm config set @test:registry https://gitea.example.com/api/packages/testuser/npm/
|
||||
npm config set -- '//gitea.example.com/api/packages/testuser/npm/:_authToken' "personal_access_token"
|
||||
```
|
||||
|
||||
or without scope:
|
||||
|
||||
```shell
|
||||
npm config set registry https://gitea.example.com/api/packages/testuser/npm/
|
||||
npm config set -- '//gitea.example.com/api/packages/testuser/npm/:_authToken' "personal_access_token"
|
||||
```
|
||||
|
||||
## Publish a package
|
||||
|
||||
Publish a package by running the following command in your project:
|
||||
|
||||
```shell
|
||||
npm publish
|
||||
```
|
||||
|
||||
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
|
||||
|
||||
## Install a package
|
||||
|
||||
To install a package from the package registry, execute the following command:
|
||||
|
||||
```shell
|
||||
npm install {package_name}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| -------------- | ----------- |
|
||||
| `package_name` | The package name. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
npm install @test/test_package
|
||||
```
|
||||
|
||||
## Tag a package
|
||||
|
||||
The registry supports [version tags](https://docs.npmjs.com/adding-dist-tags-to-packages/) which can be managed by `npm dist-tag`:
|
||||
|
||||
```shell
|
||||
npm dist-tag add {package_name}@{version} {tag}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| -------------- | ----------- |
|
||||
| `package_name` | The package name. |
|
||||
| `version` | The version of the package. |
|
||||
| `tag` | The tag name. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
npm dist-tag add test_package@1.0.2 release
|
||||
```
|
||||
|
||||
The tag name must not be a valid version. All tag names which are parsable as a version are rejected.
|
||||
|
||||
## Supported commands
|
||||
|
||||
```
|
||||
npm install
|
||||
npm ci
|
||||
npm publish
|
||||
npm dist-tag
|
||||
npm view
|
||||
```
|
|
@ -0,0 +1,116 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "NuGet Packages Repository"
|
||||
slug: "packages/nuget"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "NuGet"
|
||||
weight: 80
|
||||
identifier: "nuget"
|
||||
---
|
||||
|
||||
# NuGet Packages Repository
|
||||
|
||||
Publish [NuGet](https://www.nuget.org/) packages for your user or organization. The package registry supports [NuGet Symbol Packages](https://docs.microsoft.com/en-us/nuget/create-packages/symbol-packages-snupkg) too.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the NuGet package registry, you can use command-line interface tools as well as NuGet features in various IDEs like Visual Studio.
|
||||
More informations about NuGet clients can be found in [the official documentation](https://docs.microsoft.com/en-us/nuget/install-nuget-client-tools).
|
||||
The following examples use the `dotnet nuget` tool.
|
||||
|
||||
## Configuring the package registry
|
||||
|
||||
To register the package registry you need to configure a new NuGet feed source:
|
||||
|
||||
```shell
|
||||
dotnet nuget add source --name {source_name} --username {username} --password {password} https://gitea.example.com/api/packages/{owner}/nuget/index.json
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------- | ----------- |
|
||||
| `source_name` | The desired source name. |
|
||||
| `username` | Your Gitea username. |
|
||||
| `password` | Your Gitea password or a personal access token. |
|
||||
| `owner` | The owner of the package. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
dotnet nuget add source --name gitea --username testuser --password password123 https://gitea.example.com/api/packages/testuser/nuget/index.json
|
||||
```
|
||||
|
||||
## Publish a package
|
||||
|
||||
Publish a package by running the following command:
|
||||
|
||||
```shell
|
||||
dotnet nuget push --source {source_name} {package_file}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| -------------- | ----------- |
|
||||
| `source_name` | The desired source name. |
|
||||
| `package_file` | Path to the package `.nupkg` file. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
dotnet nuget push --source gitea test_package.1.0.0.nupkg
|
||||
```
|
||||
|
||||
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
|
||||
|
||||
### Symbol Packages
|
||||
|
||||
The NuGet package registry has build support for a symbol server. The PDB files embedded in a symbol package (`.snupkg`) can get requested by clients.
|
||||
To do so, register the NuGet package registry as symbol source:
|
||||
|
||||
```
|
||||
https://gitea.example.com/api/packages/{owner}/nuget/symbols
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| --------- | ----------- |
|
||||
| `owner` | The owner of the package registry. |
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
https://gitea.example.com/api/packages/testuser/nuget/symbols
|
||||
```
|
||||
|
||||
## Install a package
|
||||
|
||||
To install a NuGet package from the package registry, execute the following command:
|
||||
|
||||
```shell
|
||||
dotnet add package --source {source_name} --version {package_version} {package_name}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------------- | ----------- |
|
||||
| `source_name` | The desired source name. |
|
||||
| `package_name` | The package name. |
|
||||
| `package_version` | The package version. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
dotnet add package --source gitea --version 1.0.0 test_package
|
||||
```
|
||||
|
||||
## Supported commands
|
||||
|
||||
```
|
||||
dotnet add
|
||||
dotnet nuget push
|
||||
dotnet nuget delete
|
||||
```
|
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "Package Registry"
|
||||
slug: "packages/overview"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "Overview"
|
||||
weight: 1
|
||||
identifier: "overview"
|
||||
---
|
||||
|
||||
# Package Registry
|
||||
|
||||
The Package Registry can be used as a public or private registry for common package managers.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Supported package managers
|
||||
|
||||
The following package managers are currently supported:
|
||||
|
||||
| Name | Language | Package client |
|
||||
| ---- | -------- | -------------- |
|
||||
| [Composer]({{< relref "doc/packages/composer.en-us.md" >}}) | PHP | `composer` |
|
||||
| [Conan]({{< relref "doc/packages/conan.en-us.md" >}}) | C++ | `conan` |
|
||||
| [Container]({{< relref "doc/packages/container.en-us.md" >}}) | - | any OCI compliant client |
|
||||
| [Generic]({{< relref "doc/packages/generic.en-us.md" >}}) | - | any HTTP client |
|
||||
| [Helm]({{< relref "doc/packages/helm.en-us.md" >}}) | - | any HTTP client, `cm-push` |
|
||||
| [Maven]({{< relref "doc/packages/maven.en-us.md" >}}) | Java | `mvn`, `gradle` |
|
||||
| [npm]({{< relref "doc/packages/npm.en-us.md" >}}) | JavaScript | `npm`, `yarn` |
|
||||
| [NuGet]({{< relref "doc/packages/nuget.en-us.md" >}}) | .NET | `nuget` |
|
||||
| [PyPI]({{< relref "doc/packages/pypi.en-us.md" >}}) | Python | `pip`, `twine` |
|
||||
| [RubyGems]({{< relref "doc/packages/rubygems.en-us.md" >}}) | Ruby | `gem`, `Bundler` |
|
||||
|
||||
**The following paragraphs only apply if Packages are not globally disabled!**
|
||||
|
||||
## Repository-Packages
|
||||
|
||||
A package always belongs to an owner (a user or organisation), not a repository.
|
||||
To link an (already uploaded) package to a repository, open the settings page
|
||||
on that package and choose a repository to link this package to.
|
||||
The entire package will be linked, not just a single version.
|
||||
|
||||
Linking a package results in showing that package in the repository's package list,
|
||||
and shows a link to the repository on the package site (as well as a link to the repository issues).
|
||||
|
||||
## Access Restrictions
|
||||
|
||||
| Package owner type | User | Organization |
|
||||
|--------------------|------|--------------|
|
||||
| **read** access | public, if user is public too; otherwise for this user only | public, if org is public, otherwise org members only |
|
||||
| **write** access | owner only | org members with admin or write access to the org |
|
||||
|
||||
N.B.: These access restrictions are [subject to change](https://github.com/go-gitea/gitea/issues/19270), where more finegrained control will be added via a dedicated organization team permission.
|
||||
|
||||
## Create or upload a package
|
||||
|
||||
Depending on the type of package, use the respective package-manager for that. Check out the sub-page of a specific package manager for instructions.
|
||||
|
||||
## View packages
|
||||
|
||||
You can view the packages of a repository on the repository page.
|
||||
|
||||
1. Go to the repository.
|
||||
1. Go to **Packages** in the navigation bar.
|
||||
|
||||
To view more details about a package, select the name of the package.
|
||||
|
||||
## Download a package
|
||||
|
||||
To download a package from your repository:
|
||||
|
||||
1. Go to **Packages** in the navigation bar.
|
||||
1. Select the name of the package to view the details.
|
||||
1. In the **Assets** section, select the name of the package file you want to download.
|
||||
|
||||
## Delete a package
|
||||
|
||||
You cannot edit a package after you published it in the Package Registry. Instead, you
|
||||
must delete and recreate it.
|
||||
|
||||
To delete a package from your repository:
|
||||
|
||||
1. Go to **Packages** in the navigation bar.
|
||||
1. Select the name of the package to view the details.
|
||||
1. Click **Delete package** to permanently delete the package.
|
||||
|
||||
## Disable the Package Registry
|
||||
|
||||
The Package Registry is automatically enabled. To disable it for a single repository:
|
||||
|
||||
1. Go to **Settings** in the navigation bar.
|
||||
1. Disable **Enable Repository Packages Registry**.
|
||||
|
||||
Previously published packages are not deleted by disabling the Package Registry.
|
|
@ -0,0 +1,85 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "PyPI Packages Repository"
|
||||
slug: "packages/pypi"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "PyPI"
|
||||
weight: 90
|
||||
identifier: "pypi"
|
||||
---
|
||||
|
||||
# PyPI Packages Repository
|
||||
|
||||
Publish [PyPI](https://pypi.org/) packages for your user or organization.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the PyPI package registry, you need to use the tools [pip](https://pypi.org/project/pip/) to consume and [twine](https://pypi.org/project/twine/) to publish packages.
|
||||
|
||||
## Configuring the package registry
|
||||
|
||||
To register the package registry you need to edit your local `~/.pypirc` file. Add
|
||||
|
||||
```ini
|
||||
[distutils]
|
||||
index-servers = gitea
|
||||
|
||||
[gitea]
|
||||
repository = https://gitea.example.com/api/packages/{owner}/pypi
|
||||
username = {username}
|
||||
password = {password}
|
||||
```
|
||||
|
||||
| Placeholder | Description |
|
||||
| ------------ | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
| `username` | Your Gitea username. |
|
||||
| `password` | Your Gitea password or a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}). |
|
||||
|
||||
## Publish a package
|
||||
|
||||
Publish a package by running the following command:
|
||||
|
||||
```shell
|
||||
python3 -m twine upload --repository gitea /path/to/files/*
|
||||
```
|
||||
|
||||
The package files have the extensions `.tar.gz` and `.whl`.
|
||||
|
||||
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
|
||||
|
||||
## Install a package
|
||||
|
||||
To install a PyPI package from the package registry, execute the following command:
|
||||
|
||||
```shell
|
||||
pip install --index-url https://{username}:{password}@gitea.example.com/api/packages/{owner}/pypi/simple --no-deps {package_name}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------------- | ----------- |
|
||||
| `username` | Your Gitea username. |
|
||||
| `password` | Your Gitea password or a personal access token. |
|
||||
| `owner` | The owner of the package. |
|
||||
| `package_name` | The package name. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
pip install --index-url https://testuser:password123@gitea.example.com/api/packages/testuser/pypi/simple --no-deps test_package
|
||||
```
|
||||
|
||||
## Supported commands
|
||||
|
||||
```
|
||||
pip install
|
||||
twine upload
|
||||
```
|
|
@ -0,0 +1,127 @@
|
|||
---
|
||||
date: "2021-07-20T00:00:00+00:00"
|
||||
title: "RubyGems Packages Repository"
|
||||
slug: "packages/rubygems"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "RubyGems"
|
||||
weight: 100
|
||||
identifier: "rubygems"
|
||||
---
|
||||
|
||||
# RubyGems Packages Repository
|
||||
|
||||
Publish [RubyGems](https://guides.rubygems.org/) packages for your user or organization.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Requirements
|
||||
|
||||
To work with the RubyGems package registry, you need to use the [gem](https://guides.rubygems.org/command-reference/) command line tool to consume and publish packages.
|
||||
|
||||
## Configuring the package registry
|
||||
|
||||
To register the package registry edit the `~/.gem/credentials` file and add:
|
||||
|
||||
```ini
|
||||
---
|
||||
https://gitea.example.com/api/packages/{owner}/rubygems: Bearer {token}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------- | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
| `token` | Your personal access token. |
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
---
|
||||
https://gitea.example.com/api/packages/testuser/rubygems: Bearer 3bd626f84b01cd26b873931eace1e430a5773cc4
|
||||
```
|
||||
|
||||
## Publish a package
|
||||
|
||||
Publish a package by running the following command:
|
||||
|
||||
```shell
|
||||
gem push --host {host} {package_file}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| -------------- | ----------- |
|
||||
| `host` | URL to the package registry. |
|
||||
| `package_file` | Path to the package `.gem` file. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
gem push --host https://gitea.example.com/api/packages/testuser/rubygems test_package-1.0.0.gem
|
||||
```
|
||||
|
||||
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
|
||||
|
||||
## Install a package
|
||||
|
||||
To install a package from the package registry you can use [Bundler](https://bundler.io) or `gem`.
|
||||
|
||||
### Bundler
|
||||
|
||||
Add a new `source` block to your `Gemfile`:
|
||||
|
||||
```
|
||||
source "https://gitea.example.com/api/packages/{owner}/rubygems" do
|
||||
gem "{package_name}"
|
||||
end
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------------- | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
| `package_name` | The package name. |
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
source "https://gitea.example.com/api/packages/testuser/rubygems" do
|
||||
gem "test_package"
|
||||
end
|
||||
```
|
||||
|
||||
Afterwards run the following command:
|
||||
|
||||
```shell
|
||||
bundle install
|
||||
```
|
||||
|
||||
### gem
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```shell
|
||||
gem install --host https://gitea.example.com/api/packages/{owner}/rubygems {package_name}
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------------- | ----------- |
|
||||
| `owner` | The owner of the package. |
|
||||
| `package_name` | The package name. |
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
gem install --host https://gitea.example.com/api/packages/testuser/rubygems test_package
|
||||
```
|
||||
|
||||
## Supported commands
|
||||
|
||||
```
|
||||
gem install
|
||||
bundle install
|
||||
gem push
|
||||
```
|
|
@ -8,6 +8,6 @@ draft: false
|
|||
menu:
|
||||
sidebar:
|
||||
name: "Übersetzung"
|
||||
weight: 45
|
||||
weight: 50
|
||||
identifier: "translation"
|
||||
---
|
||||
|
|
|
@ -8,6 +8,6 @@ draft: false
|
|||
menu:
|
||||
sidebar:
|
||||
name: "Translation"
|
||||
weight: 45
|
||||
weight: 50
|
||||
identifier: "translation"
|
||||
---
|
||||
|
|
|
@ -8,6 +8,6 @@ draft: false
|
|||
menu:
|
||||
sidebar:
|
||||
name: "翻譯"
|
||||
weight: 45
|
||||
weight: 50
|
||||
identifier: "translation"
|
||||
---
|
||||
|
|
|
@ -57,7 +57,7 @@ The command has to be executed with the `RUN_USER = <OS_USERNAME>` specified in
|
|||
Example:
|
||||
|
||||
```none
|
||||
docker exec -u <OS_USERNAME> -it -w <--tempdir> $(docker ps -qf "name=<NAME_OF_DOCKER_CONTAINER>") bash -c '/app/gitea/gitea dump -c </path/to/app.ini>'
|
||||
docker exec -u <OS_USERNAME> -it -w <--tempdir> $(docker ps -qf 'name=^<NAME_OF_DOCKER_CONTAINER>$') bash -c '/app/gitea/gitea dump -c </path/to/app.ini>'
|
||||
```
|
||||
|
||||
\*Note: `--tempdir` refers to the temporary directory of the docker environment used by Gitea; if you have not specified a custom `--tempdir`, then Gitea uses `/tmp` or the `TMPDIR` environment variable of the docker container. For `--tempdir` adjust your `docker exec` command options accordingly.
|
||||
|
|
|
@ -313,8 +313,13 @@ in the current directory.
|
|||
- `--tempdir path`, `-t path`: Path to the temporary directory used. Optional. (default: /tmp).
|
||||
- `--skip-repository`, `-R`: Skip the repository dumping. Optional.
|
||||
- `--skip-custom-dir`: Skip dumping of the custom dir. Optional.
|
||||
- `--skip-lfs-data`: Skip dumping of LFS data. Optional.
|
||||
- `--skip-attachment-data`: Skip dumping of attachment data. Optional.
|
||||
- `--skip-package-data`: Skip dumping of package data. Optional.
|
||||
- `--skip-log`: Skip dumping of log data. Optional.
|
||||
- `--database`, `-d`: Specify the database SQL syntax. Optional.
|
||||
- `--verbose`, `-V`: If provided, shows additional details. Optional.
|
||||
- `--type`: Set the dump output format. Optional. (default: zip)
|
||||
- Examples:
|
||||
- `gitea dump`
|
||||
- `gitea dump --verbose`
|
||||
|
@ -503,6 +508,13 @@ Manage running server operations:
|
|||
- `--host value`, `-H value`: Mail server host (defaults to: 127.0.0.1:25)
|
||||
- `--send-to value`, `-s value`: Email address(es) to send to
|
||||
- `--subject value`, `-S value`: Subject header of sent emails
|
||||
- `processes`: Display Gitea processes and goroutine information
|
||||
- Options:
|
||||
- `--flat`: Show processes as flat table rather than as tree
|
||||
- `--no-system`: Do not show system processes
|
||||
- `--stacktraces`: Show stacktraces for goroutines associated with processes
|
||||
- `--json`: Output as json
|
||||
- `--cancel PID`: Send cancel to process with PID. (Only for non-system processes.)
|
||||
|
||||
### dump-repo
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ ENABLED = true
|
|||
FROM = gitea@mydomain.com
|
||||
MAILER_TYPE = sendmail
|
||||
SENDMAIL_PATH = /usr/sbin/sendmail
|
||||
SENDMAIL_ARGS = "--" ; most "sendmail" programs take options, "--" will prevent an email address being interpreted as an option.
|
||||
```
|
||||
|
||||
## Using SMTP
|
||||
|
|
|
@ -89,7 +89,7 @@ chain in **iptables**. Configure it in `/etc/fail2ban/jail.d/gitea-docker.conf`:
|
|||
[gitea-docker]
|
||||
enabled = true
|
||||
filter = gitea
|
||||
logpath = /home/git/gitea/log/gitea.log
|
||||
logpath = /var/lib/gitea/log/gitea.log
|
||||
maxretry = 10
|
||||
findtime = 3600
|
||||
bantime = 900
|
||||
|
|
|
@ -43,6 +43,39 @@ Possible file names for PR templates:
|
|||
- `.github/PULL_REQUEST_TEMPLATE.md`
|
||||
- `.github/pull_request_template.md`
|
||||
|
||||
Possible file names for PR default merge message templates:
|
||||
|
||||
- `.gitea/default_merge_message/MERGE_TEMPLATE.md`
|
||||
- `.gitea/default_merge_message/REBASE_TEMPLATE.md`
|
||||
- `.gitea/default_merge_message/REBASE-MERGE_TEMPLATE.md`
|
||||
- `.gitea/default_merge_message/SQUASH_TEMPLATE.md`
|
||||
- `.gitea/default_merge_message/MANUALLY-MERGED_TEMPLATE.md`
|
||||
- `.gitea/default_merge_message/REBASE-UPDATE-ONLY_TEMPLATE.md`
|
||||
|
||||
Possible file names for PR default merge message templates:
|
||||
|
||||
- `.gitea/default_merge_message/MERGE_TEMPLATE.md`
|
||||
- `.gitea/default_merge_message/REBASE_TEMPLATE.md`
|
||||
- `.gitea/default_merge_message/REBASE-MERGE_TEMPLATE.md`
|
||||
- `.gitea/default_merge_message/SQUASH_TEMPLATE.md`
|
||||
- `.gitea/default_merge_message/MANUALLY-MERGED_TEMPLATE.md`
|
||||
- `.gitea/default_merge_message/REBASE-UPDATE-ONLY_TEMPLATE.md`
|
||||
|
||||
You can use the following variables enclosed in `${}` inside these templates which follow [os.Expand](https://pkg.go.dev/os#Expand) syntax:
|
||||
|
||||
- BaseRepoOwnerName: Base repository owner name of this pull request
|
||||
- BaseRepoName: Base repository name of this pull request
|
||||
- BaseBranch: Base repository target branch name of this pull request
|
||||
- HeadRepoOwnerName: Head repository owner name of this pull request
|
||||
- HeadRepoName: Head repository name of this pull request
|
||||
- HeadBranch: Head repository branch name of this pull request
|
||||
- PullRequestTitle: Pull request's title
|
||||
- PullRequestDescription: Pull request's description
|
||||
- PullRequestPosterName: Pull request's poster name
|
||||
- PullRequestIndex: Pull request's index number
|
||||
- PullRequestReference: Pull request's reference char with index number. i.e. #1, !2
|
||||
- ClosingIssues: return a string contains all issues which will be closed by this pull request i.e. `close #1, close #2`
|
||||
|
||||
Additionally, the New Issue page URL can be suffixed with `?title=Issue+Title&body=Issue+Text` and the form will be populated with those strings. Those strings will be used instead of the template if there is one.
|
||||
|
||||
## Issue Template Directory
|
||||
|
|
|
@ -348,3 +348,18 @@ The added http-request will automatically add a trailing slash if needed and int
|
|||
|
||||
Then you **MUST** set something like `[server] ROOT_URL = http://example.com/gitea/` correctly in your configuration.
|
||||
|
||||
## Traefik
|
||||
|
||||
If you want traefik to serve your Gitea instance, you can add the following label section to your `docker-compose.yaml` (Assuming the provider is docker).
|
||||
|
||||
```yaml
|
||||
gitea:
|
||||
image: gitea/gitea
|
||||
...
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.gitea.rule=Host(`example.com`)"
|
||||
- "traefik.http.services.gitea-websecure.loadbalancer.server.port=3000"
|
||||
```
|
||||
|
||||
This config assumes that you are handling HTTPS on the traefik side and using HTTP between Gitea and traefik.
|
|
@ -106,3 +106,19 @@ git.example.com {
|
|||
```
|
||||
|
||||
然后您**必须**在 Gitea 的配置文件中正确的添加类似 `[server] ROOT_URL = http://git.example.com/git/` 的配置项。
|
||||
|
||||
## 使用 Traefik 作为反向代理服务
|
||||
|
||||
如果您想使用 traefik 作为 Gitea 的反向代理服务,您可以在 `docker-compose.yaml` 中添加 label 部分(假设使用 docker 作为 traefik 的 provider):
|
||||
|
||||
```yaml
|
||||
gitea:
|
||||
image: gitea/gitea
|
||||
...
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.gitea.rule=Host(`example.com`)"
|
||||
- "traefik.http.services.gitea-websecure.loadbalancer.server.port=3000"
|
||||
```
|
||||
|
||||
这份配置假设您使用 traefik 来处理 HTTPS 服务,并在其和 Gitea 之间使用 HTTP 进行通信。
|
229
go.mod
229
go.mod
|
@ -1,6 +1,6 @@
|
|||
module code.gitea.io/gitea
|
||||
|
||||
go 1.16
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b
|
||||
|
@ -11,22 +11,12 @@ require (
|
|||
gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8
|
||||
gitea.com/lunny/levelqueue v0.4.1
|
||||
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f // indirect
|
||||
github.com/PuerkitoBio/goquery v1.8.0
|
||||
github.com/alecthomas/chroma v0.10.0
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.2.1 // indirect
|
||||
github.com/blevesearch/bleve/v2 v2.3.1
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
|
||||
github.com/caddyserver/certmagic v0.15.4
|
||||
github.com/chi-middleware/proxy v1.1.1
|
||||
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
|
||||
github.com/couchbase/gomemcached v0.1.2 // indirect
|
||||
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
|
||||
github.com/denisenkom/go-mssqldb v0.12.0
|
||||
github.com/djherbis/buffer v1.2.0
|
||||
github.com/djherbis/nio/v3 v3.0.1
|
||||
|
@ -36,7 +26,6 @@ require (
|
|||
github.com/emirpasic/gods v1.12.0
|
||||
github.com/ethantkoenig/rupture v1.0.1
|
||||
github.com/gliderlabs/ssh v0.3.3
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
github.com/go-chi/cors v1.2.0
|
||||
github.com/go-enry/go-enry/v2 v2.8.0
|
||||
|
@ -45,7 +34,7 @@ require (
|
|||
github.com/go-git/go-billy/v5 v5.3.1
|
||||
github.com/go-git/go-git/v5 v5.4.3-0.20210630082519-b4368b2a2ca4
|
||||
github.com/go-ldap/ldap/v3 v3.4.2
|
||||
github.com/go-redis/redis/v8 v8.11.4
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/go-swagger/go-swagger v0.29.0
|
||||
github.com/go-testfixtures/testfixtures/v3 v3.6.1
|
||||
|
@ -54,21 +43,17 @@ require (
|
|||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-github/v39 v39.2.0
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/feeds v1.1.1
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/sessions v1.2.1
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/go-version v1.4.0
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/huandu/xstrings v1.3.2
|
||||
github.com/jaytaylor/html2text v0.0.0-20211105163654-bc68cce691ba
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
|
||||
github.com/klauspost/compress v1.15.0
|
||||
github.com/klauspost/cpuid/v2 v2.0.11
|
||||
|
@ -76,71 +61,229 @@ require (
|
|||
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
|
||||
github.com/markbates/goth v1.69.0
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.12
|
||||
github.com/mholt/acmez v1.0.2 // indirect
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/microcosm-cc/bluemonday v1.0.18
|
||||
github.com/miekg/dns v1.1.46 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/minio-go/v7 v7.0.23
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
||||
github.com/msteinert/pam v1.0.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/niklasfasching/go-org v1.6.2
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/oliamb/cutter v0.2.2
|
||||
github.com/olivere/elastic/v7 v7.0.31
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pquerna/otp v1.3.0
|
||||
github.com/prometheus/client_golang v1.12.1
|
||||
github.com/quasoft/websspi v1.1.2
|
||||
github.com/rs/xid v1.3.0 // indirect
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0
|
||||
github.com/sergi/go-diff v1.2.0
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
|
||||
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
|
||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/tstranex/u2f v1.0.0
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/unknwon/com v1.0.1
|
||||
github.com/unknwon/i18n v0.0.0-20210904045753-ff3a8617e361
|
||||
github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae
|
||||
github.com/unrolled/render v1.4.1
|
||||
github.com/urfave/cli v1.22.5
|
||||
github.com/xanzy/go-gitlab v0.58.0
|
||||
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
||||
github.com/yohcop/openid-go v1.0.0
|
||||
github.com/yuin/goldmark v1.4.8
|
||||
github.com/yuin/goldmark v1.4.11
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.jolheiser.com/hcaptcha v0.0.4
|
||||
go.jolheiser.com/pwn v0.0.3
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
golang.org/x/tools v0.1.9
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/ini.v1 v1.66.4
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
mvdan.cc/xurls/v2 v2.4.0
|
||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
|
||||
xorm.io/builder v0.3.9
|
||||
xorm.io/builder v0.3.10
|
||||
xorm.io/xorm v1.2.5
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.99.0 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/RoaringBitmap/roaring v0.9.4 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.1 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.2.1 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.0.1 // indirect
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||
github.com/blevesearch/mmap-go v1.0.3 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.0 // indirect
|
||||
github.com/blevesearch/segment v0.9.0 // indirect
|
||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.1 // indirect
|
||||
github.com/blevesearch/vellum v1.0.7 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.3.3 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cloudflare/cfssl v1.6.1 // indirect
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
|
||||
github.com/couchbase/gomemcached v0.1.2 // indirect
|
||||
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.2 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/fullstorydev/grpcurl v1.8.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
|
||||
github.com/go-enry/go-oniguruma v1.2.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-openapi/analysis v0.21.2 // indirect
|
||||
github.com/go-openapi/errors v0.20.2 // indirect
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/loads v0.21.0 // indirect
|
||||
github.com/go-openapi/runtime v0.21.1 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.1 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-openapi/validate v0.20.3 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/goccy/go-json v0.9.5 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jessevdk/go-flags v1.5.0 // indirect
|
||||
github.com/jhump/protoreflect v1.8.2 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/libdns/libdns v0.2.1 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/markbates/going v1.0.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mholt/acmez v1.0.2 // indirect
|
||||
github.com/miekg/dns v1.1.46 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.1 // indirect
|
||||
github.com/rs/xid v1.3.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/spf13/afero v1.8.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/cobra v1.3.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.10.1 // indirect
|
||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||
github.com/steveyen/gtreap v0.1.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
|
||||
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/unknwon/com v1.0.1 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.1 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect
|
||||
go.etcd.io/etcd/client/v2 v2.305.1 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/server/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/v3 v3.5.0-alpha.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.8.2 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/mod v0.5.1 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||
google.golang.org/grpc v1.43.0 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
|
||||
|
||||
replace github.com/markbates/goth v1.68.0 => github.com/zeripath/goth v1.68.1-0.20220109111530-754359885dce
|
||||
|
|
35
go.sum
35
go.sum
|
@ -599,8 +599,8 @@ github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8w
|
|||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M=
|
||||
github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
|
||||
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
|
@ -766,8 +766,10 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
|
|||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg=
|
||||
|
@ -1010,8 +1012,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
|
|||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o=
|
||||
github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+4tLukHoB9iqHOu3LmLhRmgUxZo6Vp4=
|
||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
|
@ -1241,15 +1243,18 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
|||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
|
||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
|
@ -1506,10 +1511,6 @@ github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0o
|
|||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
|
||||
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
|
||||
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
|
||||
github.com/unknwon/i18n v0.0.0-20210904045753-ff3a8617e361 h1:4Ij5sX4JEzCCY/CCl8trJHey1tPsIDomYTZf145GKk0=
|
||||
github.com/unknwon/i18n v0.0.0-20210904045753-ff3a8617e361/go.mod h1:+5rDk6sDGpl3azws3O+f+GpFSyN9GVr0K8cvQLQM2ZQ=
|
||||
github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae h1:ihaXiJkaca54IaCSnEXtE/uSZOmPxKZhDfVLrzZLFDs=
|
||||
github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae/go.mod h1:1fdkY6xxl6ExVs2QFv7R0F5IRZHKA8RahhB9fMC9RvM=
|
||||
github.com/unrolled/render v1.4.1 h1:VdpMc2YkAOWzbmC/P2yoHhRDXgsaCQHcTJ1KK6SNCA4=
|
||||
github.com/unrolled/render v1.4.1/go.mod h1:cK4RSTTVdND5j9EYEc0LAMOvdG11JeiKjyjfyZRvV2w=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
|
@ -1553,8 +1554,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
|||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||
github.com/yuin/goldmark v1.4.6/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||
github.com/yuin/goldmark v1.4.8 h1:zHPiabbIRssZOI0MAzJDHsyvG4MXCGqVaMOwR+HeoQQ=
|
||||
github.com/yuin/goldmark v1.4.8/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||
github.com/yuin/goldmark v1.4.11 h1:i45YIzqLnUc2tGaTlJCyUxSG8TvgyGqhqOZOUKIjJ6w=
|
||||
github.com/yuin/goldmark v1.4.11/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg=
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod h1:U9ihbh+1ZN7fR5Se3daSPoz1CGF9IYtSvWwVQtnzGHU=
|
||||
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
|
||||
|
@ -1692,8 +1693,8 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y
|
|||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -2277,7 +2278,6 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AW
|
|||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg=
|
||||
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
@ -2358,7 +2358,8 @@ sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
|||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs=
|
||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
|
||||
xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc=
|
||||
xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
xorm.io/builder v0.3.10 h1:Rvkncad3Lo9YIVqCbgIf6QnpR/HcW3IEr0AANNpuyMQ=
|
||||
xorm.io/builder v0.3.10/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
xorm.io/xorm v1.2.5 h1:tqN7OhN8P9xi52qBb76I8m5maAJMz/SSbgK2RGPCPbo=
|
||||
xorm.io/xorm v1.2.5/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0=
|
||||
|
|
|
@ -36,7 +36,7 @@ TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root T
|
|||
## 如何使用 pgsql 数据库进行集成测试
|
||||
同上,首先在 docker 容器里部署一个 pgsql 数据库
|
||||
```
|
||||
docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:13 #(just ctrl-c to stop db and clean the container)
|
||||
docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:14 #(just ctrl-c to stop db and clean the container)
|
||||
```
|
||||
之后便可以基于这个数据库进行集成测试
|
||||
```
|
||||
|
|
|
@ -46,7 +46,7 @@ func TestAdminEditUser(t *testing.T) {
|
|||
}
|
||||
|
||||
func testSuccessfullEdit(t *testing.T, formData user_model.User) {
|
||||
makeRequest(t, formData, http.StatusFound)
|
||||
makeRequest(t, formData, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func makeRequest(t *testing.T, formData user_model.User, headerCode int) {
|
||||
|
|
|
@ -37,7 +37,7 @@ func testAPIGetBranchProtection(t *testing.T, branchName string, expectedHTTPSta
|
|||
req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branch_protections/%s?token=%s", branchName, token)
|
||||
resp := session.MakeRequest(t, req, expectedHTTPStatus)
|
||||
|
||||
if resp.Code == 200 {
|
||||
if resp.Code == http.StatusOK {
|
||||
var branchProtection api.BranchProtection
|
||||
DecodeJSON(t, resp, &branchProtection)
|
||||
assert.EqualValues(t, branchName, branchProtection.BranchName)
|
||||
|
@ -52,7 +52,7 @@ func testAPICreateBranchProtection(t *testing.T, branchName string, expectedHTTP
|
|||
})
|
||||
resp := session.MakeRequest(t, req, expectedHTTPStatus)
|
||||
|
||||
if resp.Code == 201 {
|
||||
if resp.Code == http.StatusCreated {
|
||||
var branchProtection api.BranchProtection
|
||||
DecodeJSON(t, resp, &branchProtection)
|
||||
assert.EqualValues(t, branchName, branchProtection.BranchName)
|
||||
|
@ -65,7 +65,7 @@ func testAPIEditBranchProtection(t *testing.T, branchName string, body *api.Bran
|
|||
req := NewRequestWithJSON(t, "PATCH", "/api/v1/repos/user2/repo1/branch_protections/"+branchName+"?token="+token, body)
|
||||
resp := session.MakeRequest(t, req, expectedHTTPStatus)
|
||||
|
||||
if resp.Code == 200 {
|
||||
if resp.Code == http.StatusOK {
|
||||
var branchProtection api.BranchProtection
|
||||
DecodeJSON(t, resp, &branchProtection)
|
||||
assert.EqualValues(t, branchName, branchProtection.BranchName)
|
||||
|
|
|
@ -227,7 +227,7 @@ func doAPICreatePullRequest(ctx APITestContext, owner, repo, baseBranch, headBra
|
|||
Title: fmt.Sprintf("create a pr from %s to %s", headBranch, baseBranch),
|
||||
})
|
||||
|
||||
expected := 201
|
||||
expected := http.StatusCreated
|
||||
if ctx.ExpectedCode != 0 {
|
||||
expected = ctx.ExpectedCode
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ func doAPIGetPullRequest(ctx APITestContext, owner, repo string, index int64) fu
|
|||
owner, repo, index, ctx.Token)
|
||||
req := NewRequest(t, http.MethodGet, urlStr)
|
||||
|
||||
expected := 200
|
||||
expected := http.StatusOK
|
||||
if ctx.ExpectedCode != 0 {
|
||||
expected = ctx.ExpectedCode
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64)
|
|||
|
||||
expected := ctx.ExpectedCode
|
||||
if expected == 0 {
|
||||
expected = 200
|
||||
expected = http.StatusOK
|
||||
}
|
||||
|
||||
if !assert.EqualValues(t, expected, resp.Code,
|
||||
|
@ -306,6 +306,24 @@ func doAPIManuallyMergePullRequest(ctx APITestContext, owner, repo, commitID str
|
|||
MergeCommitID: commitID,
|
||||
})
|
||||
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIAutoMergePullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
|
||||
owner, repo, index, ctx.Token)
|
||||
req := NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
|
||||
MergeMessageField: "doAPIMergePullRequest Merge",
|
||||
Do: string(repo_model.MergeStyleMerge),
|
||||
MergeWhenChecksSucceed: true,
|
||||
})
|
||||
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
|
@ -314,6 +332,19 @@ func doAPIManuallyMergePullRequest(ctx APITestContext, owner, repo, commitID str
|
|||
}
|
||||
}
|
||||
|
||||
func doAPICancelAutoMergePullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
|
||||
owner, repo, index, ctx.Token)
|
||||
req := NewRequest(t, http.MethodDelete, urlStr)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, 204)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIGetBranch(ctx APITestContext, branch string, callback ...func(*testing.T, api.Branch)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/branches/%s?token=%s", ctx.Username, ctx.Reponame, branch, ctx.Token)
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -21,7 +21,7 @@ import (
|
|||
func TestAPIIssuesMilestone(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
milestone := unittest.AssertExistsAndLoadBean(t, &models.Milestone{ID: 1}).(*models.Milestone)
|
||||
milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: milestone.RepoID}).(*repo_model.Repository)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||
assert.Equal(t, int64(1), int64(milestone.NumIssues))
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
|
@ -23,7 +24,7 @@ func TestAPIIssuesReactions(t *testing.T) {
|
|||
defer prepareTestEnv(t)()
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 1}).(*models.Issue)
|
||||
_ = issue.LoadRepo()
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
|
@ -82,7 +83,7 @@ func TestAPICommentReactions(t *testing.T) {
|
|||
comment := unittest.AssertExistsAndLoadBean(t, &models.Comment{ID: 2}).(*models.Comment)
|
||||
_ = comment.LoadIssue()
|
||||
issue := comment.Issue
|
||||
_ = issue.LoadRepo()
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -45,7 +46,7 @@ func TestAPIStopStopWatches(t *testing.T) {
|
|||
defer prepareTestEnv(t)()
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
|
||||
_ = issue.LoadRepo()
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
|
@ -61,7 +62,7 @@ func TestAPICancelStopWatches(t *testing.T) {
|
|||
defer prepareTestEnv(t)()
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 1}).(*models.Issue)
|
||||
_ = issue.LoadRepo()
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
||||
|
||||
|
@ -77,7 +78,7 @@ func TestAPIStartStopWatches(t *testing.T) {
|
|||
defer prepareTestEnv(t)()
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 3}).(*models.Issue)
|
||||
_ = issue.LoadRepo()
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
|
|
|
@ -168,12 +168,11 @@ func TestAPIEditIssue(t *testing.T) {
|
|||
func TestAPISearchIssues(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
token := getUserToken(t, "user2")
|
||||
|
||||
link, _ := url.Parse("/api/v1/repos/issues/search")
|
||||
req := NewRequest(t, "GET", link.String())
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
req := NewRequest(t, "GET", link.String()+"?token="+token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var apiIssues []*api.Issue
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 10)
|
||||
|
@ -181,7 +180,7 @@ func TestAPISearchIssues(t *testing.T) {
|
|||
query := url.Values{"token": {token}}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 10)
|
||||
|
||||
|
@ -189,9 +188,10 @@ func TestAPISearchIssues(t *testing.T) {
|
|||
before := time.Unix(999307200, 0).Format(time.RFC3339)
|
||||
query.Add("since", since)
|
||||
query.Add("before", before)
|
||||
query.Add("token", token)
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 8)
|
||||
query.Del("since")
|
||||
|
@ -200,14 +200,14 @@ func TestAPISearchIssues(t *testing.T) {
|
|||
query.Add("state", "closed")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query.Set("state", "all")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.EqualValues(t, "15", resp.Header().Get("X-Total-Count"))
|
||||
assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit
|
||||
|
@ -215,49 +215,49 @@ func TestAPISearchIssues(t *testing.T) {
|
|||
query.Add("limit", "20")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 15)
|
||||
|
||||
query = url.Values{"assigned": {"true"}, "state": {"all"}}
|
||||
query = url.Values{"assigned": {"true"}, "state": {"all"}, "token": {token}}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 1)
|
||||
|
||||
query = url.Values{"milestones": {"milestone1"}, "state": {"all"}}
|
||||
query = url.Values{"milestones": {"milestone1"}, "state": {"all"}, "token": {token}}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 1)
|
||||
|
||||
query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}}
|
||||
query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}, "token": {token}}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query = url.Values{"owner": {"user2"}} // user
|
||||
query = url.Values{"owner": {"user2"}, "token": {token}} // user
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 6)
|
||||
|
||||
query = url.Values{"owner": {"user3"}} // organization
|
||||
query = url.Values{"owner": {"user3"}, "token": {token}} // organization
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 3)
|
||||
|
||||
query = url.Values{"owner": {"user3"}, "team": {"team1"}} // organization + team
|
||||
query = url.Values{"owner": {"user3"}, "team": {"team1"}, "token": {token}} // organization + team
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
}
|
||||
|
@ -265,12 +265,11 @@ func TestAPISearchIssues(t *testing.T) {
|
|||
func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
token := getUserToken(t, "user1")
|
||||
|
||||
link, _ := url.Parse("/api/v1/repos/issues/search")
|
||||
req := NewRequest(t, "GET", link.String())
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
req := NewRequest(t, "GET", link.String()+"?token="+token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var apiIssues []*api.Issue
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
|
||||
|
@ -280,14 +279,14 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
|||
query.Add("token", token)
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 10)
|
||||
|
||||
query.Add("labels", "label1")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
|
@ -295,7 +294,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
|||
query.Set("labels", "label1,label2")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
|
@ -303,7 +302,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
|||
query.Set("labels", "orglabel4")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 1)
|
||||
|
||||
|
@ -312,7 +311,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
|||
query.Add("state", "all")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
|
@ -320,7 +319,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
|||
query.Set("labels", "label1,orglabel4")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
@ -23,7 +24,7 @@ func TestAPIGetTrackedTimes(t *testing.T) {
|
|||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
issue2 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
|
||||
assert.NoError(t, issue2.LoadRepo())
|
||||
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
||||
|
||||
session := loginUser(t, user2.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
@ -65,7 +66,7 @@ func TestAPIDeleteTrackedTime(t *testing.T) {
|
|||
|
||||
time6 := unittest.AssertExistsAndLoadBean(t, &models.TrackedTime{ID: 6}).(*models.TrackedTime)
|
||||
issue2 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
|
||||
assert.NoError(t, issue2.LoadRepo())
|
||||
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
session := loginUser(t, user2.Name)
|
||||
|
@ -99,7 +100,7 @@ func TestAPIAddTrackedTimes(t *testing.T) {
|
|||
defer prepareTestEnv(t)()
|
||||
|
||||
issue2 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
|
||||
assert.NoError(t, issue2.LoadRepo())
|
||||
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@ func TestNodeinfo(t *testing.T) {
|
|||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var nodeinfo api.NodeInfo
|
||||
DecodeJSON(t, resp, &nodeinfo)
|
||||
assert.True(t, nodeinfo.OpenRegistrations)
|
||||
assert.Equal(t, "gitea", nodeinfo.Software.Name)
|
||||
assert.Equal(t, 23, nodeinfo.Usage.Users.Total)
|
||||
assert.Equal(t, 15, nodeinfo.Usage.LocalPosts)
|
||||
assert.Equal(t, 2, nodeinfo.Usage.LocalComments)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -20,9 +20,8 @@ import (
|
|||
|
||||
func TestAPIOrgCreate(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
session := loginUser(t, "user1")
|
||||
token := getUserToken(t, "user1")
|
||||
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
org := api.CreateOrgOption{
|
||||
UserName: "user1_org",
|
||||
FullName: "User1's organization",
|
||||
|
@ -32,7 +31,7 @@ func TestAPIOrgCreate(t *testing.T) {
|
|||
Visibility: "limited",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs?token="+token, &org)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var apiOrg api.Organization
|
||||
DecodeJSON(t, resp, &apiOrg)
|
||||
|
@ -50,13 +49,13 @@ func TestAPIOrgCreate(t *testing.T) {
|
|||
FullName: org.FullName,
|
||||
})
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s", org.UserName)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s?token=%s", org.UserName, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiOrg)
|
||||
assert.EqualValues(t, org.UserName, apiOrg.UserName)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", org.UserName)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token=%s", org.UserName, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repos []*api.Repository
|
||||
DecodeJSON(t, resp, &repos)
|
||||
|
@ -64,8 +63,8 @@ func TestAPIOrgCreate(t *testing.T) {
|
|||
assert.False(t, repo.Private)
|
||||
}
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", org.UserName)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members?token=%s", org.UserName, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// user1 on this org is public
|
||||
var users []*api.User
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
neturl "net/url"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
composer_module "code.gitea.io/gitea/modules/packages/composer"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers/api/packages/composer"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageComposer(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
vendorName := "gitea"
|
||||
projectName := "composer-package"
|
||||
packageName := vendorName + "/" + projectName
|
||||
packageVersion := "1.0.3"
|
||||
packageDescription := "Package Description"
|
||||
packageType := "composer-plugin"
|
||||
packageAuthor := "Gitea Authors"
|
||||
packageLicense := "MIT"
|
||||
|
||||
var buf bytes.Buffer
|
||||
archive := zip.NewWriter(&buf)
|
||||
w, _ := archive.Create("composer.json")
|
||||
w.Write([]byte(`{
|
||||
"name": "` + packageName + `",
|
||||
"description": "` + packageDescription + `",
|
||||
"type": "` + packageType + `",
|
||||
"license": "` + packageLicense + `",
|
||||
"authors": [
|
||||
{
|
||||
"name": "` + packageAuthor + `"
|
||||
}
|
||||
]
|
||||
}`))
|
||||
archive.Close()
|
||||
content := buf.Bytes()
|
||||
|
||||
url := fmt.Sprintf("%sapi/packages/%s/composer", setting.AppURL, user.Name)
|
||||
|
||||
t.Run("ServiceIndex", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/packages.json", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result composer.ServiceIndexResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, url+"/search.json?q=%query%&type=%type%", result.SearchTemplate)
|
||||
assert.Equal(t, url+"/p2/%package%.json", result.MetadataTemplate)
|
||||
assert.Equal(t, url+"/list.json", result.PackageList)
|
||||
})
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
t.Run("MissingVersion", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
uploadURL := url + "?version=" + packageVersion
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeComposer)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &composer_module.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, fmt.Sprintf("%s-%s.%s.zip", vendorName, projectName, packageVersion), pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(content)), pb.Size)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeComposer)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(0), pvs[0].DownloadCount)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/files/%s/%s/%s", url, neturl.PathEscape(packageName), neturl.PathEscape(pvs[0].LowerVersion), neturl.PathEscape(pfs[0].LowerName)))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, content, resp.Body.Bytes())
|
||||
|
||||
pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeComposer)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("SearchService", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Query string
|
||||
Type string
|
||||
Page int
|
||||
PerPage int
|
||||
ExpectedTotal int64
|
||||
ExpectedResults int
|
||||
}{
|
||||
{"", "", 0, 0, 1, 1},
|
||||
{"", "", 1, 1, 1, 1},
|
||||
{"test", "", 1, 0, 0, 0},
|
||||
{"gitea", "", 1, 1, 1, 1},
|
||||
{"gitea", "", 2, 1, 1, 0},
|
||||
{"", packageType, 1, 1, 1, 1},
|
||||
{"gitea", packageType, 1, 1, 1, 1},
|
||||
{"gitea", "dummy", 1, 1, 0, 0},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/search.json?q=%s&type=%s&page=%d&per_page=%d", url, c.Query, c.Type, c.Page, c.PerPage))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result composer.SearchResultResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, c.ExpectedTotal, result.Total, "case %d: unexpected total hits", i)
|
||||
assert.Len(t, result.Results, c.ExpectedResults, "case %d: unexpected result count", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("EnumeratePackages", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", url+"/list.json")
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result map[string][]string
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result, "packageNames")
|
||||
names := result["packageNames"]
|
||||
assert.Len(t, names, 1)
|
||||
assert.Equal(t, packageName, names[0])
|
||||
})
|
||||
|
||||
t.Run("PackageMetadata", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/p2/%s/%s.json", url, vendorName, projectName))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result composer.PackageMetadataResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result.Packages, packageName)
|
||||
pkgs := result.Packages[packageName]
|
||||
assert.Len(t, pkgs, 1)
|
||||
assert.Equal(t, packageName, pkgs[0].Name)
|
||||
assert.Equal(t, packageVersion, pkgs[0].Version)
|
||||
assert.Equal(t, packageType, pkgs[0].Type)
|
||||
assert.Equal(t, packageDescription, pkgs[0].Description)
|
||||
assert.Len(t, pkgs[0].Authors, 1)
|
||||
assert.Equal(t, packageAuthor, pkgs[0].Authors[0].Name)
|
||||
assert.Equal(t, "zip", pkgs[0].Dist.Type)
|
||||
assert.Equal(t, "7b40bfd6da811b2b78deec1e944f156dbb2c747b", pkgs[0].Dist.Checksum)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,724 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
stdurl "net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
conan_model "code.gitea.io/gitea/models/packages/conan"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
conan_module "code.gitea.io/gitea/modules/packages/conan"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
conan_router "code.gitea.io/gitea/routers/api/packages/conan"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
conanfileName = "conanfile.py"
|
||||
conaninfoName = "conaninfo.txt"
|
||||
|
||||
conanLicense = "MIT"
|
||||
conanAuthor = "Gitea <info@gitea.io>"
|
||||
conanHomepage = "https://gitea.io/"
|
||||
conanURL = "https://gitea.com/"
|
||||
conanDescription = "Description of ConanPackage"
|
||||
conanTopic = "gitea"
|
||||
|
||||
conanPackageReference = "dummyreference"
|
||||
|
||||
contentConaninfo = `[settings]
|
||||
arch=x84_64
|
||||
|
||||
[requires]
|
||||
fmt/7.1.3
|
||||
|
||||
[options]
|
||||
shared=False
|
||||
|
||||
[full_settings]
|
||||
arch=x84_64
|
||||
|
||||
[full_requires]
|
||||
fmt/7.1.3
|
||||
|
||||
[full_options]
|
||||
shared=False
|
||||
|
||||
[recipe_hash]
|
||||
74714915a51073acb548ca1ce29afbac
|
||||
|
||||
[env]
|
||||
CC=gcc-10`
|
||||
)
|
||||
|
||||
func addTokenAuthHeader(request *http.Request, token string) *http.Request {
|
||||
request.Header.Set("Authorization", token)
|
||||
return request
|
||||
}
|
||||
|
||||
func buildConanfileContent(name, version string) string {
|
||||
return `from conans import ConanFile, CMake, tools
|
||||
|
||||
class ConanPackageConan(ConanFile):
|
||||
name = "` + name + `"
|
||||
version = "` + version + `"
|
||||
license = "` + conanLicense + `"
|
||||
author = "` + conanAuthor + `"
|
||||
homepage = "` + conanHomepage + `"
|
||||
url = "` + conanURL + `"
|
||||
description = "` + conanDescription + `"
|
||||
topics = ("` + conanTopic + `")
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
options = {"shared": [True, False], "fPIC": [True, False]}
|
||||
default_options = {"shared": False, "fPIC": True}
|
||||
generators = "cmake"`
|
||||
}
|
||||
|
||||
func uploadConanPackageV1(t *testing.T, baseURL, token, name, version, user, channel string) {
|
||||
contentConanfile := buildConanfileContent(name, version)
|
||||
|
||||
recipeURL := fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s", baseURL, name, version, user, channel)
|
||||
|
||||
req := NewRequest(t, "GET", recipeURL)
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", recipeURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", recipeURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("%s/upload_urls", recipeURL))
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/upload_urls", recipeURL), map[string]int64{
|
||||
conanfileName: int64(len(contentConanfile)),
|
||||
"removed.txt": 0,
|
||||
})
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
uploadURLs := make(map[string]string)
|
||||
DecodeJSON(t, resp, &uploadURLs)
|
||||
|
||||
assert.Contains(t, uploadURLs, conanfileName)
|
||||
assert.NotContains(t, uploadURLs, "removed.txt")
|
||||
|
||||
uploadURL := uploadURLs[conanfileName]
|
||||
assert.NotEmpty(t, uploadURL)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", uploadURL, strings.NewReader(contentConanfile))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
packageURL := fmt.Sprintf("%s/packages/%s", recipeURL, conanPackageReference)
|
||||
|
||||
req = NewRequest(t, "GET", packageURL)
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", packageURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", packageURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("%s/upload_urls", packageURL))
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/upload_urls", packageURL), map[string]int64{
|
||||
conaninfoName: int64(len(contentConaninfo)),
|
||||
"removed.txt": 0,
|
||||
})
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
uploadURLs = make(map[string]string)
|
||||
DecodeJSON(t, resp, &uploadURLs)
|
||||
|
||||
assert.Contains(t, uploadURLs, conaninfoName)
|
||||
assert.NotContains(t, uploadURLs, "removed.txt")
|
||||
|
||||
uploadURL = uploadURLs[conaninfoName]
|
||||
assert.NotEmpty(t, uploadURL)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", uploadURL, strings.NewReader(contentConaninfo))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
}
|
||||
|
||||
func uploadConanPackageV2(t *testing.T, baseURL, token, name, version, user, channel, recipeRevision, packageRevision string) {
|
||||
contentConanfile := buildConanfileContent(name, version)
|
||||
|
||||
recipeURL := fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s", baseURL, name, version, user, channel, recipeRevision)
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/files/%s", recipeURL, conanfileName), strings.NewReader(contentConanfile))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/files", recipeURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var list *struct {
|
||||
Files map[string]interface{} `json:"files"`
|
||||
}
|
||||
DecodeJSON(t, resp, &list)
|
||||
assert.Len(t, list.Files, 1)
|
||||
assert.Contains(t, list.Files, conanfileName)
|
||||
|
||||
packageURL := fmt.Sprintf("%s/packages/%s/revisions/%s", recipeURL, conanPackageReference, packageRevision)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/files", packageURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/files/%s", packageURL, conaninfoName), strings.NewReader(contentConaninfo))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/files", packageURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
list = nil
|
||||
DecodeJSON(t, resp, &list)
|
||||
assert.Len(t, list.Files, 1)
|
||||
assert.Contains(t, list.Files, conaninfoName)
|
||||
}
|
||||
|
||||
func TestPackageConan(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
name := "ConanPackage"
|
||||
version1 := "1.2"
|
||||
version2 := "1.3"
|
||||
user1 := "dummy"
|
||||
user2 := "gitea"
|
||||
channel1 := "test"
|
||||
channel2 := "final"
|
||||
revision1 := "rev1"
|
||||
revision2 := "rev2"
|
||||
|
||||
url := fmt.Sprintf("%sapi/packages/%s/conan", setting.AppURL, user.Name)
|
||||
|
||||
t.Run("v1", func(t *testing.T) {
|
||||
t.Run("Ping", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/ping", url))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, "revisions", resp.Header().Get("X-Conan-Server-Capabilities"))
|
||||
})
|
||||
|
||||
token := ""
|
||||
|
||||
t.Run("Authenticate", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/users/authenticate", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
body := resp.Body.String()
|
||||
assert.NotEmpty(t, body)
|
||||
|
||||
token = fmt.Sprintf("Bearer %s", body)
|
||||
})
|
||||
|
||||
t.Run("CheckCredentials", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/users/check_credentials", url))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
uploadConanPackageV1(t, url, token, name, version1, user1, channel1)
|
||||
|
||||
t.Run("Validate", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeConan)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.Equal(t, name, pd.Package.Name)
|
||||
assert.Equal(t, version1, pd.Version.Version)
|
||||
assert.IsType(t, &conan_module.Metadata{}, pd.Metadata)
|
||||
metadata := pd.Metadata.(*conan_module.Metadata)
|
||||
assert.Equal(t, conanLicense, metadata.License)
|
||||
assert.Equal(t, conanAuthor, metadata.Author)
|
||||
assert.Equal(t, conanHomepage, metadata.ProjectURL)
|
||||
assert.Equal(t, conanURL, metadata.RepositoryURL)
|
||||
assert.Equal(t, conanDescription, metadata.Description)
|
||||
assert.Equal(t, []string{conanTopic}, metadata.Keywords)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 2)
|
||||
|
||||
for _, pf := range pfs {
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if pf.Name == conanfileName {
|
||||
assert.True(t, pf.IsLead)
|
||||
|
||||
assert.Equal(t, int64(len(buildConanfileContent(name, version1))), pb.Size)
|
||||
} else if pf.Name == conaninfoName {
|
||||
assert.False(t, pf.IsLead)
|
||||
|
||||
assert.Equal(t, int64(len(contentConaninfo)), pb.Size)
|
||||
} else {
|
||||
assert.Fail(t, "unknown file: %s", pf.Name)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
recipeURL := fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s", url, name, version1, user1, channel1)
|
||||
|
||||
req := NewRequest(t, "GET", recipeURL)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
fileHashes := make(map[string]string)
|
||||
DecodeJSON(t, resp, &fileHashes)
|
||||
assert.Len(t, fileHashes, 1)
|
||||
assert.Contains(t, fileHashes, conanfileName)
|
||||
assert.Equal(t, "7abc52241c22090782c54731371847a8", fileHashes[conanfileName])
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", recipeURL))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
downloadURLs := make(map[string]string)
|
||||
DecodeJSON(t, resp, &downloadURLs)
|
||||
assert.Contains(t, downloadURLs, conanfileName)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", recipeURL))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &downloadURLs)
|
||||
assert.Contains(t, downloadURLs, conanfileName)
|
||||
|
||||
req = NewRequest(t, "GET", downloadURLs[conanfileName])
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, buildConanfileContent(name, version1), resp.Body.String())
|
||||
|
||||
packageURL := fmt.Sprintf("%s/packages/%s", recipeURL, conanPackageReference)
|
||||
|
||||
req = NewRequest(t, "GET", packageURL)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
fileHashes = make(map[string]string)
|
||||
DecodeJSON(t, resp, &fileHashes)
|
||||
assert.Len(t, fileHashes, 1)
|
||||
assert.Contains(t, fileHashes, conaninfoName)
|
||||
assert.Equal(t, "7628bfcc5b17f1470c468621a78df394", fileHashes[conaninfoName])
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", packageURL))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
downloadURLs = make(map[string]string)
|
||||
DecodeJSON(t, resp, &downloadURLs)
|
||||
assert.Contains(t, downloadURLs, conaninfoName)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", packageURL))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &downloadURLs)
|
||||
assert.Contains(t, downloadURLs, conaninfoName)
|
||||
|
||||
req = NewRequest(t, "GET", downloadURLs[conaninfoName])
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, contentConaninfo, resp.Body.String())
|
||||
})
|
||||
|
||||
t.Run("Search", func(t *testing.T) {
|
||||
uploadConanPackageV1(t, url, token, name, version2, user1, channel1)
|
||||
uploadConanPackageV1(t, url, token, name, version1, user1, channel2)
|
||||
uploadConanPackageV1(t, url, token, name, version1, user2, channel1)
|
||||
uploadConanPackageV1(t, url, token, name, version1, user2, channel2)
|
||||
|
||||
t.Run("Recipe", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Query string
|
||||
Expected []string
|
||||
}{
|
||||
{"ConanPackage", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.1", []string{}},
|
||||
{"Conan*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2@", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2@du*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final"}},
|
||||
{"ConanPackage/1.2@du*/", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final"}},
|
||||
{"ConanPackage/1.2@du*/*test", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@du*/*st", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@gitea/*", []string{"ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"*/*@dummy", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final"}},
|
||||
{"*/*@*/final", []string{"ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/final"}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/conans/search?q=%s", url, stdurl.QueryEscape(c.Query)))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result *conan_router.SearchResult
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.ElementsMatch(t, c.Expected, result.Results, "case %d: unexpected result", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s/search", url, name, version1, user1, channel2))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result map[string]*conan_module.Conaninfo
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result, conanPackageReference)
|
||||
info := result[conanPackageReference]
|
||||
assert.NotEmpty(t, info.Settings)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Channel string
|
||||
References []string
|
||||
}{
|
||||
{channel1, []string{conanPackageReference}},
|
||||
{channel2, []string{}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
rref, _ := conan_module.NewRecipeReference(name, version1, user1, c.Channel, conan_module.DefaultRevision)
|
||||
references, err := conan_model.GetPackageReferences(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, references)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s/packages/delete", url, name, version1, user1, c.Channel), map[string][]string{
|
||||
"package_ids": c.References,
|
||||
})
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
references, err = conan_model.GetPackageReferences(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, references, "case %d: should be empty", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Recipe", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Channel string
|
||||
}{
|
||||
{channel1},
|
||||
{channel2},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
rref, _ := conan_module.NewRecipeReference(name, version1, user1, c.Channel, conan_module.DefaultRevision)
|
||||
revisions, err := conan_model.GetRecipeRevisions(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, revisions)
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s", url, name, version1, user1, c.Channel))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
revisions, err = conan_model.GetRecipeRevisions(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, revisions, "case %d: should be empty", i)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("v2", func(t *testing.T) {
|
||||
t.Run("Ping", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/ping", url))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, "revisions", resp.Header().Get("X-Conan-Server-Capabilities"))
|
||||
})
|
||||
|
||||
token := ""
|
||||
|
||||
t.Run("Authenticate", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/users/authenticate", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
body := resp.Body.String()
|
||||
assert.NotEmpty(t, body)
|
||||
|
||||
token = fmt.Sprintf("Bearer %s", body)
|
||||
})
|
||||
|
||||
t.Run("CheckCredentials", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/users/check_credentials", url))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision1, revision1)
|
||||
|
||||
t.Run("Validate", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeConan)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 2)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Latest", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
recipeURL := fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s", url, name, version1, user1, channel1)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/latest", recipeURL))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
obj := make(map[string]string)
|
||||
DecodeJSON(t, resp, &obj)
|
||||
assert.Contains(t, obj, "revision")
|
||||
assert.Equal(t, revision1, obj["revision"])
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/revisions/%s/packages/%s/latest", recipeURL, revision1, conanPackageReference))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
obj = make(map[string]string)
|
||||
DecodeJSON(t, resp, &obj)
|
||||
assert.Contains(t, obj, "revision")
|
||||
assert.Equal(t, revision1, obj["revision"])
|
||||
})
|
||||
|
||||
t.Run("ListRevisions", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision1, revision2)
|
||||
uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision2, revision1)
|
||||
uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision2, revision2)
|
||||
|
||||
recipeURL := fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions", url, name, version1, user1, channel1)
|
||||
|
||||
req := NewRequest(t, "GET", recipeURL)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type RevisionInfo struct {
|
||||
Revision string `json:"revision"`
|
||||
Time time.Time `json:"time"`
|
||||
}
|
||||
|
||||
type RevisionList struct {
|
||||
Revisions []*RevisionInfo `json:"revisions"`
|
||||
}
|
||||
|
||||
var list *RevisionList
|
||||
DecodeJSON(t, resp, &list)
|
||||
assert.Len(t, list.Revisions, 2)
|
||||
revs := make([]string, 0, len(list.Revisions))
|
||||
for _, rev := range list.Revisions {
|
||||
revs = append(revs, rev.Revision)
|
||||
}
|
||||
assert.ElementsMatch(t, []string{revision1, revision2}, revs)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/packages/%s/revisions", recipeURL, revision1, conanPackageReference))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &list)
|
||||
assert.Len(t, list.Revisions, 2)
|
||||
revs = make([]string, 0, len(list.Revisions))
|
||||
for _, rev := range list.Revisions {
|
||||
revs = append(revs, rev.Revision)
|
||||
}
|
||||
assert.ElementsMatch(t, []string{revision1, revision2}, revs)
|
||||
})
|
||||
|
||||
t.Run("Search", func(t *testing.T) {
|
||||
t.Run("Recipe", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Query string
|
||||
Expected []string
|
||||
}{
|
||||
{"ConanPackage", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.1", []string{}},
|
||||
{"Conan*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2@", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2@du*", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@du*/", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@du*/*test", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@du*/*st", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@gitea/*", []string{"ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"*/*@dummy", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test"}},
|
||||
{"*/*@*/final", []string{"ConanPackage/1.2@gitea/final"}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/conans/search?q=%s", url, stdurl.QueryEscape(c.Query)))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result *conan_router.SearchResult
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.ElementsMatch(t, c.Expected, result.Results, "case %d: unexpected result", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/search", url, name, version1, user1, channel1))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result map[string]*conan_module.Conaninfo
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result, conanPackageReference)
|
||||
info := result[conanPackageReference]
|
||||
assert.NotEmpty(t, info.Settings)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/search", url, name, version1, user1, channel1, revision1))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
result = make(map[string]*conan_module.Conaninfo)
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result, conanPackageReference)
|
||||
info = result[conanPackageReference]
|
||||
assert.NotEmpty(t, info.Settings)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
rref, _ := conan_module.NewRecipeReference(name, version1, user1, channel1, revision1)
|
||||
pref, _ := conan_module.NewPackageReference(rref, conanPackageReference, conan_module.DefaultRevision)
|
||||
|
||||
checkPackageRevisionCount := func(count int) {
|
||||
revisions, err := conan_model.GetPackageRevisions(db.DefaultContext, user.ID, pref)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, revisions, count)
|
||||
}
|
||||
checkPackageReferenceCount := func(count int) {
|
||||
references, err := conan_model.GetPackageReferences(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, references, count)
|
||||
}
|
||||
|
||||
checkPackageRevisionCount(2)
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/packages/%s/revisions/%s", url, name, version1, user1, channel1, revision1, conanPackageReference, revision1))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkPackageRevisionCount(1)
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/packages/%s", url, name, version1, user1, channel1, revision1, conanPackageReference))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkPackageRevisionCount(0)
|
||||
|
||||
rref = rref.WithRevision(revision2)
|
||||
|
||||
checkPackageReferenceCount(1)
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/packages", url, name, version1, user1, channel1, revision2))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkPackageReferenceCount(0)
|
||||
})
|
||||
|
||||
t.Run("Recipe", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
rref, _ := conan_module.NewRecipeReference(name, version1, user1, channel1, conan_module.DefaultRevision)
|
||||
|
||||
checkRecipeRevisionCount := func(count int) {
|
||||
revisions, err := conan_model.GetRecipeRevisions(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, revisions, count)
|
||||
}
|
||||
|
||||
checkRecipeRevisionCount(2)
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s", url, name, version1, user1, channel1, revision1))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkRecipeRevisionCount(1)
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s", url, name, version1, user1, channel1))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkRecipeRevisionCount(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
|
@ -0,0 +1,534 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
container_model "code.gitea.io/gitea/models/packages/container"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
container_module "code.gitea.io/gitea/modules/packages/container"
|
||||
"code.gitea.io/gitea/modules/packages/container/oci"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageContainer(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
has := func(l packages_model.PackagePropertyList, name string) bool {
|
||||
for _, pp := range l {
|
||||
if pp.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
images := []string{"test", "te/st"}
|
||||
tags := []string{"latest", "main"}
|
||||
multiTag := "multi"
|
||||
|
||||
unknownDigest := "sha256:0000000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
blobDigest := "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||
blobContent, _ := base64.StdEncoding.DecodeString(`H4sIAAAJbogA/2IYBaNgFIxYAAgAAP//Lq+17wAEAAA=`)
|
||||
|
||||
configDigest := "sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d"
|
||||
configContent := `{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/true"],"ArgsEscaped":true,"Image":"sha256:9bd8b88dc68b80cffe126cc820e4b52c6e558eb3b37680bfee8e5f3ed7b8c257"},"container":"b89fe92a887d55c0961f02bdfbfd8ac3ddf66167db374770d2d9e9fab3311510","container_config":{"Hostname":"b89fe92a887d","Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/true\"]"],"ArgsEscaped":true,"Image":"sha256:9bd8b88dc68b80cffe126cc820e4b52c6e558eb3b37680bfee8e5f3ed7b8c257"},"created":"2022-01-01T00:00:00.000000000Z","docker_version":"20.10.12","history":[{"created":"2022-01-01T00:00:00.000000000Z","created_by":"/bin/sh -c #(nop) COPY file:0e7589b0c800daaf6fa460d2677101e4676dd9491980210cb345480e513f3602 in /true "},{"created":"2022-01-01T00:00:00.000000001Z","created_by":"/bin/sh -c #(nop) CMD [\"/true\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:0ff3b91bdf21ecdf2f2f3d4372c2098a14dbe06cd678e8f0a85fd4902d00e2e2"]}}`
|
||||
|
||||
manifestDigest := "sha256:4f10484d1c1bb13e3956b4de1cd42db8e0f14a75be1617b60f2de3cd59c803c6"
|
||||
manifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeDockerManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
|
||||
|
||||
untaggedManifestDigest := "sha256:4305f5f5572b9a426b88909b036e52ee3cf3d7b9c1b01fac840e90747f56623d"
|
||||
untaggedManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
|
||||
|
||||
indexManifestDigest := "sha256:bab112d6efb9e7f221995caaaa880352feb5bd8b1faf52fae8d12c113aa123ec"
|
||||
indexManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageIndex + `","manifests":[{"mediaType":"` + oci.MediaTypeDockerManifest + `","digest":"` + manifestDigest + `","platform":{"os":"linux","architecture":"arm","variant":"v7"}},{"mediaType":"` + oci.MediaTypeImageManifest + `","digest":"` + untaggedManifestDigest + `","platform":{"os":"linux","architecture":"arm64","variant":"v8"}}]}`
|
||||
|
||||
anonymousToken := ""
|
||||
userToken := ""
|
||||
|
||||
t.Run("Authenticate", func(t *testing.T) {
|
||||
type TokenResponse struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
authenticate := []string{
|
||||
`Bearer realm="` + setting.AppURL + `v2/token"`,
|
||||
`Basic`,
|
||||
}
|
||||
|
||||
t.Run("Anonymous", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||
resp := MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
assert.ElementsMatch(t, authenticate, resp.Header().Values("WWW-Authenticate"))
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%sv2/token", setting.AppURL))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
tokenResponse := &TokenResponse{}
|
||||
DecodeJSON(t, resp, &tokenResponse)
|
||||
|
||||
assert.NotEmpty(t, tokenResponse.Token)
|
||||
|
||||
anonymousToken = fmt.Sprintf("Bearer %s", tokenResponse.Token)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||
addTokenAuthHeader(req, anonymousToken)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("User", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||
resp := MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
assert.ElementsMatch(t, authenticate, resp.Header().Values("WWW-Authenticate"))
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%sv2/token", setting.AppURL))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
tokenResponse := &TokenResponse{}
|
||||
DecodeJSON(t, resp, &tokenResponse)
|
||||
|
||||
assert.NotEmpty(t, tokenResponse.Token)
|
||||
|
||||
userToken = fmt.Sprintf("Bearer %s", tokenResponse.Token)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("DetermineSupport", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, "registry/2.0", resp.Header().Get("Docker-Distribution-Api-Version"))
|
||||
})
|
||||
|
||||
for _, image := range images {
|
||||
t.Run(fmt.Sprintf("[Image:%s]", image), func(t *testing.T) {
|
||||
url := fmt.Sprintf("%sv2/%s/%s", setting.AppURL, user.Name, image)
|
||||
|
||||
t.Run("UploadBlob/Monolithic", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url))
|
||||
addTokenAuthHeader(req, anonymousToken)
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequestWithBody(t, "POST", fmt.Sprintf("%s/blobs/uploads?digest=%s", url, unknownDigest), bytes.NewReader(blobContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
req = NewRequestWithBody(t, "POST", fmt.Sprintf("%s/blobs/uploads?digest=%s", url, blobDigest), bytes.NewReader(blobContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("/v2/%s/%s/blobs/%s", user.Name, image, blobDigest), resp.Header().Get("Location"))
|
||||
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
|
||||
pv, err := packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, container_model.UploadVersion)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pfs, err := packages_model.GetFilesByVersionID(db.DefaultContext, pv.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
|
||||
pb, err := packages_model.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, len(blobContent), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadBlob/Chunked", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
uuid := resp.Header().Get("Docker-Upload-Uuid")
|
||||
assert.NotEmpty(t, uuid)
|
||||
|
||||
pbu, err := packages_model.GetBlobUploadByID(db.DefaultContext, uuid)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 0, pbu.BytesReceived)
|
||||
|
||||
uploadURL := resp.Header().Get("Location")
|
||||
assert.NotEmpty(t, uploadURL)
|
||||
|
||||
req = NewRequestWithBody(t, "PATCH", setting.AppURL+uploadURL[1:]+"000", bytes.NewReader(blobContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestWithBody(t, "PATCH", setting.AppURL+uploadURL[1:], bytes.NewReader(blobContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
|
||||
req.Header.Set("Content-Range", "1-10")
|
||||
MakeRequest(t, req, http.StatusRequestedRangeNotSatisfiable)
|
||||
|
||||
contentRange := fmt.Sprintf("0-%d", len(blobContent)-1)
|
||||
req.Header.Set("Content-Range", contentRange)
|
||||
resp = MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
assert.Equal(t, uuid, resp.Header().Get("Docker-Upload-Uuid"))
|
||||
assert.Equal(t, contentRange, resp.Header().Get("Range"))
|
||||
|
||||
pbu, err = packages_model.GetBlobUploadByID(db.DefaultContext, uuid)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, len(blobContent), pbu.BytesReceived)
|
||||
|
||||
uploadURL = resp.Header().Get("Location")
|
||||
|
||||
req = NewRequest(t, "PUT", fmt.Sprintf("%s?digest=%s", setting.AppURL+uploadURL[1:], blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp = MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("/v2/%s/%s/blobs/%s", user.Name, image, blobDigest), resp.Header().Get("Location"))
|
||||
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
})
|
||||
|
||||
for _, tag := range tags {
|
||||
t.Run(fmt.Sprintf("[Tag:%s]", tag), func(t *testing.T) {
|
||||
t.Run("UploadManifest", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "POST", fmt.Sprintf("%s/blobs/uploads?digest=%s", url, configDigest), strings.NewReader(configContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent))
|
||||
addTokenAuthHeader(req, anonymousToken)
|
||||
req.Header.Set("Content-Type", oci.MediaTypeDockerManifest)
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
req.Header.Set("Content-Type", oci.MediaTypeDockerManifest)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
|
||||
pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, tag)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.SemVer)
|
||||
assert.Equal(t, image, pd.Package.Name)
|
||||
assert.Equal(t, tag, pd.Version.Version)
|
||||
assert.True(t, has(pd.Properties, container_module.PropertyManifestTagged))
|
||||
|
||||
assert.IsType(t, &container_module.Metadata{}, pd.Metadata)
|
||||
metadata := pd.Metadata.(*container_module.Metadata)
|
||||
assert.Equal(t, container_module.TypeOCI, metadata.Type)
|
||||
assert.Len(t, metadata.ImageLayers, 2)
|
||||
assert.Empty(t, metadata.MultiArch)
|
||||
|
||||
assert.Len(t, pd.Files, 3)
|
||||
for _, pfd := range pd.Files {
|
||||
switch pfd.File.Name {
|
||||
case container_model.ManifestFilename:
|
||||
assert.True(t, pfd.File.IsLead)
|
||||
assert.Equal(t, oci.MediaTypeDockerManifest, pfd.Properties.GetByName(container_module.PropertyMediaType))
|
||||
assert.Equal(t, manifestDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
|
||||
case strings.Replace(configDigest, ":", "_", 1):
|
||||
assert.False(t, pfd.File.IsLead)
|
||||
assert.Equal(t, "application/vnd.docker.container.image.v1+json", pfd.Properties.GetByName(container_module.PropertyMediaType))
|
||||
assert.Equal(t, configDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
|
||||
case strings.Replace(blobDigest, ":", "_", 1):
|
||||
assert.False(t, pfd.File.IsLead)
|
||||
assert.Equal(t, "application/vnd.docker.image.rootfs.diff.tar.gzip", pfd.Properties.GetByName(container_module.PropertyMediaType))
|
||||
assert.Equal(t, blobDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
|
||||
default:
|
||||
assert.Fail(t, "unknown file: %s", pfd.File.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Overwrite existing tag
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
req.Header.Set("Content-Type", oci.MediaTypeDockerManifest)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
})
|
||||
|
||||
t.Run("HeadManifest", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/unknown-tag", url))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/%s", url, tag))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%d", len(manifestContent)), resp.Header().Get("Content-Length"))
|
||||
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
})
|
||||
|
||||
t.Run("GetManifest", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/manifests/unknown-tag", url))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/manifests/%s", url, tag))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%d", len(manifestContent)), resp.Header().Get("Content-Length"))
|
||||
assert.Equal(t, oci.MediaTypeDockerManifest, resp.Header().Get("Content-Type"))
|
||||
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
assert.Equal(t, manifestContent, resp.Body.String())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("UploadUntaggedManifest", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, untaggedManifestDigest), strings.NewReader(untaggedManifestContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
req.Header.Set("Content-Type", oci.MediaTypeImageManifest)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, untaggedManifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/%s", url, untaggedManifestDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%d", len(untaggedManifestContent)), resp.Header().Get("Content-Length"))
|
||||
assert.Equal(t, untaggedManifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
|
||||
pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, untaggedManifestDigest)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.SemVer)
|
||||
assert.Equal(t, image, pd.Package.Name)
|
||||
assert.Equal(t, untaggedManifestDigest, pd.Version.Version)
|
||||
assert.False(t, has(pd.Properties, container_module.PropertyManifestTagged))
|
||||
|
||||
assert.IsType(t, &container_module.Metadata{}, pd.Metadata)
|
||||
|
||||
assert.Len(t, pd.Files, 3)
|
||||
for _, pfd := range pd.Files {
|
||||
if pfd.File.Name == container_model.ManifestFilename {
|
||||
assert.True(t, pfd.File.IsLead)
|
||||
assert.Equal(t, oci.MediaTypeImageManifest, pfd.Properties.GetByName(container_module.PropertyMediaType))
|
||||
assert.Equal(t, untaggedManifestDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("UploadIndexManifest", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, multiTag), strings.NewReader(indexManifestContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
req.Header.Set("Content-Type", oci.MediaTypeImageIndex)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, indexManifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
|
||||
pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, multiTag)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.SemVer)
|
||||
assert.Equal(t, image, pd.Package.Name)
|
||||
assert.Equal(t, multiTag, pd.Version.Version)
|
||||
assert.True(t, has(pd.Properties, container_module.PropertyManifestTagged))
|
||||
|
||||
getAllByName := func(l packages_model.PackagePropertyList, name string) []string {
|
||||
values := make([]string, 0, len(l))
|
||||
for _, pp := range l {
|
||||
if pp.Name == name {
|
||||
values = append(values, pp.Value)
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
assert.ElementsMatch(t, []string{manifestDigest, untaggedManifestDigest}, getAllByName(pd.Properties, container_module.PropertyManifestReference))
|
||||
|
||||
assert.IsType(t, &container_module.Metadata{}, pd.Metadata)
|
||||
metadata := pd.Metadata.(*container_module.Metadata)
|
||||
assert.Equal(t, container_module.TypeOCI, metadata.Type)
|
||||
assert.Contains(t, metadata.MultiArch, "linux/arm/v7")
|
||||
assert.Equal(t, manifestDigest, metadata.MultiArch["linux/arm/v7"])
|
||||
assert.Contains(t, metadata.MultiArch, "linux/arm64/v8")
|
||||
assert.Equal(t, untaggedManifestDigest, metadata.MultiArch["linux/arm64/v8"])
|
||||
|
||||
assert.Len(t, pd.Files, 1)
|
||||
assert.True(t, pd.Files[0].File.IsLead)
|
||||
assert.Equal(t, oci.MediaTypeImageIndex, pd.Files[0].Properties.GetByName(container_module.PropertyMediaType))
|
||||
assert.Equal(t, indexManifestDigest, pd.Files[0].Properties.GetByName(container_module.PropertyDigest))
|
||||
})
|
||||
|
||||
t.Run("UploadBlob/Mount", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads?mount=%s", url, unknownDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads?mount=%s", url, blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("/v2/%s/%s/blobs/%s", user.Name, image, blobDigest), resp.Header().Get("Location"))
|
||||
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
})
|
||||
|
||||
t.Run("HeadBlob", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "HEAD", fmt.Sprintf("%s/blobs/%s", url, unknownDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/blobs/%s", url, blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%d", len(blobContent)), resp.Header().Get("Content-Length"))
|
||||
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
})
|
||||
|
||||
t.Run("GetBlob", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/blobs/%s", url, unknownDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/blobs/%s", url, blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%d", len(blobContent)), resp.Header().Get("Content-Length"))
|
||||
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
assert.Equal(t, blobContent, resp.Body.Bytes())
|
||||
})
|
||||
|
||||
t.Run("GetTagList", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
URL string
|
||||
ExpectedTags []string
|
||||
ExpectedLink string
|
||||
}{
|
||||
{
|
||||
URL: fmt.Sprintf("%s/tags/list", url),
|
||||
ExpectedTags: []string{"latest", "main", "multi"},
|
||||
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=multi>; rel="next"`, user.Name, image),
|
||||
},
|
||||
{
|
||||
URL: fmt.Sprintf("%s/tags/list?n=0", url),
|
||||
ExpectedTags: []string{},
|
||||
ExpectedLink: "",
|
||||
},
|
||||
{
|
||||
URL: fmt.Sprintf("%s/tags/list?n=2", url),
|
||||
ExpectedTags: []string{"latest", "main"},
|
||||
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=main&n=2>; rel="next"`, user.Name, image),
|
||||
},
|
||||
{
|
||||
URL: fmt.Sprintf("%s/tags/list?last=main", url),
|
||||
ExpectedTags: []string{"multi"},
|
||||
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=multi>; rel="next"`, user.Name, image),
|
||||
},
|
||||
{
|
||||
URL: fmt.Sprintf("%s/tags/list?n=1&last=latest", url),
|
||||
ExpectedTags: []string{"main"},
|
||||
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=main&n=1>; rel="next"`, user.Name, image),
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
req := NewRequest(t, "GET", c.URL)
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type TagList struct {
|
||||
Name string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
tagList := &TagList{}
|
||||
DecodeJSON(t, resp, &tagList)
|
||||
|
||||
assert.Equal(t, user.Name+"/"+image, tagList.Name)
|
||||
assert.Equal(t, c.ExpectedTags, tagList.Tags)
|
||||
assert.Equal(t, c.ExpectedLink, resp.Header().Get("Link"))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
t.Run("Blob", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/blobs/%s", url, blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/blobs/%s", url, blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("ManifestByDigest", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/manifests/%s", url, untaggedManifestDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/%s", url, untaggedManifestDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("ManifestByTag", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/manifests/%s", url, multiTag))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/%s", url, multiTag))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageGeneric(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
packageName := "te-st_pac.kage"
|
||||
packageVersion := "1.0.3"
|
||||
filename := "fi-le_na.me"
|
||||
content := []byte{1, 2, 3}
|
||||
|
||||
url := fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, filename)
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.Nil(t, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(content)), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadExists", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", url)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, content, resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", url)
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, pvs)
|
||||
})
|
||||
|
||||
t.Run("DownloadNotExists", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", url)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("DeleteNotExists", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", url)
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
helm_module "code.gitea.io/gitea/modules/packages/helm"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func TestPackageHelm(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
packageName := "test-chart"
|
||||
packageVersion := "1.0.3"
|
||||
packageAuthor := "KN4CK3R"
|
||||
packageDescription := "Gitea Test Package"
|
||||
|
||||
filename := fmt.Sprintf("%s-%s.tgz", packageName, packageVersion)
|
||||
|
||||
chartContent := `apiVersion: v2
|
||||
description: ` + packageDescription + `
|
||||
name: ` + packageName + `
|
||||
type: application
|
||||
version: ` + packageVersion + `
|
||||
maintainers:
|
||||
- name: ` + packageAuthor + `
|
||||
dependencies:
|
||||
- name: dep1
|
||||
repository: https://example.com/
|
||||
version: 1.0.0`
|
||||
|
||||
var buf bytes.Buffer
|
||||
zw := gzip.NewWriter(&buf)
|
||||
archive := tar.NewWriter(zw)
|
||||
archive.WriteHeader(&tar.Header{
|
||||
Name: fmt.Sprintf("%s/Chart.yaml", packageName),
|
||||
Mode: 0o600,
|
||||
Size: int64(len(chartContent)),
|
||||
})
|
||||
archive.Write([]byte(chartContent))
|
||||
archive.Close()
|
||||
zw.Close()
|
||||
content := buf.Bytes()
|
||||
|
||||
url := fmt.Sprintf("/api/packages/%s/helm", user.Name)
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
uploadURL := url + "/api/charts"
|
||||
|
||||
req := NewRequestWithBody(t, "POST", uploadURL, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeHelm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &helm_module.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(content)), pb.Size)
|
||||
|
||||
req = NewRequestWithBody(t, "POST", uploadURL, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
checkDownloadCount := func(count int64) {
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeHelm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, count, pvs[0].DownloadCount)
|
||||
}
|
||||
|
||||
checkDownloadCount(0)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s", url, filename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, content, resp.Body.Bytes())
|
||||
|
||||
checkDownloadCount(1)
|
||||
})
|
||||
|
||||
t.Run("Index", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.yaml", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type ChartVersion struct {
|
||||
helm_module.Metadata `yaml:",inline"`
|
||||
URLs []string `yaml:"urls"`
|
||||
Created time.Time `yaml:"created,omitempty"`
|
||||
Removed bool `yaml:"removed,omitempty"`
|
||||
Digest string `yaml:"digest,omitempty"`
|
||||
}
|
||||
|
||||
type ServerInfo struct {
|
||||
ContextPath string `yaml:"contextPath,omitempty"`
|
||||
}
|
||||
|
||||
type Index struct {
|
||||
APIVersion string `yaml:"apiVersion"`
|
||||
Entries map[string][]*ChartVersion `yaml:"entries"`
|
||||
Generated time.Time `yaml:"generated,omitempty"`
|
||||
ServerInfo *ServerInfo `yaml:"serverInfo,omitempty"`
|
||||
}
|
||||
|
||||
var result Index
|
||||
assert.NoError(t, yaml.NewDecoder(resp.Body).Decode(&result))
|
||||
assert.NotEmpty(t, result.Entries)
|
||||
assert.Contains(t, result.Entries, packageName)
|
||||
|
||||
cvs := result.Entries[packageName]
|
||||
assert.Len(t, cvs, 1)
|
||||
|
||||
cv := cvs[0]
|
||||
assert.Equal(t, packageName, cv.Name)
|
||||
assert.Equal(t, packageVersion, cv.Version)
|
||||
assert.Equal(t, packageDescription, cv.Description)
|
||||
assert.Len(t, cv.Maintainers, 1)
|
||||
assert.Equal(t, packageAuthor, cv.Maintainers[0].Name)
|
||||
assert.Len(t, cv.Dependencies, 1)
|
||||
assert.ElementsMatch(t, []string{fmt.Sprintf("%s%s/%s", setting.AppURL, url[1:], filename)}, cv.URLs)
|
||||
|
||||
assert.Equal(t, url, result.ServerInfo.ContextPath)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/packages/maven"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageMaven(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
groupID := "com.gitea"
|
||||
artifactID := "test-project"
|
||||
packageName := groupID + "-" + artifactID
|
||||
packageVersion := "1.0.1"
|
||||
packageDescription := "Test Description"
|
||||
|
||||
root := fmt.Sprintf("/api/packages/%s/maven/%s/%s", user.Name, strings.ReplaceAll(groupID, ".", "/"), artifactID)
|
||||
filename := fmt.Sprintf("%s-%s.jar", packageName, packageVersion)
|
||||
|
||||
putFile := func(t *testing.T, path, content string, expectedStatus int) {
|
||||
req := NewRequestWithBody(t, "PUT", root+path, strings.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusCreated)
|
||||
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.SemVer)
|
||||
assert.Nil(t, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.False(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(4), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadExists", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, []byte("test"), resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(0), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("UploadVerifySHA1", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
t.Run("Missmatch", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s.sha1", packageVersion, filename), "test", http.StatusBadRequest)
|
||||
})
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s.sha1", packageVersion, filename), "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", http.StatusOK)
|
||||
})
|
||||
})
|
||||
|
||||
pomContent := `<?xml version="1.0"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<groupId>` + groupID + `</groupId>
|
||||
<artifactId>` + artifactID + `</artifactId>
|
||||
<version>` + packageVersion + `</version>
|
||||
<description>` + packageDescription + `</description>
|
||||
</project>`
|
||||
|
||||
t.Run("UploadPOM", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.Metadata)
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s.pom", packageVersion, filename), pomContent, http.StatusCreated)
|
||||
|
||||
pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err = packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.IsType(t, &maven.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageDescription, pd.Metadata.(*maven.Metadata).Description)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 2)
|
||||
i := 0
|
||||
if strings.HasSuffix(pfs[1].Name, ".pom") {
|
||||
i = 1
|
||||
}
|
||||
assert.Equal(t, filename+".pom", pfs[i].Name)
|
||||
assert.True(t, pfs[i].IsLead)
|
||||
})
|
||||
|
||||
t.Run("DownloadPOM", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, []byte(pomContent), resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("DownloadChecksums", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/1.2.3/%s", root, filename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
for key, checksum := range map[string]string{
|
||||
"md5": "098f6bcd4621d373cade4e832627b4f6",
|
||||
"sha1": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
|
||||
"sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
|
||||
"sha512": "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff",
|
||||
} {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.%s", root, packageVersion, filename, key))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, checksum, resp.Body.String())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DownloadMetadata", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", root+"/maven-metadata.xml")
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
expectedMetadata := `<?xml version="1.0" encoding="UTF-8"?>` + "\n<metadata><groupId>com.gitea</groupId><artifactId>test-project</artifactId><versioning><release>1.0.1</release><latest>1.0.1</latest><versions><version>1.0.1</version></versions></versioning></metadata>"
|
||||
assert.Equal(t, expectedMetadata, resp.Body.String())
|
||||
|
||||
for key, checksum := range map[string]string{
|
||||
"md5": "6bee0cebaaa686d658adf3e7e16371a0",
|
||||
"sha1": "8696abce499fe84d9ea93e5492abe7147e195b6c",
|
||||
"sha256": "3f48322f81c4b2c3bb8649ae1e5c9801476162b520e1c2734ac06b2c06143208",
|
||||
"sha512": "cb075aa2e2ef1a83cdc14dd1e08c505b72d633399b39e73a21f00f0deecb39a3e2c79f157c1163f8a3854828750706e0dec3a0f5e4778e91f8ec2cf351a855f2",
|
||||
} {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/maven-metadata.xml.%s", root, key))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, checksum, resp.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/packages/npm"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageNpm(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
token := fmt.Sprintf("Bearer %s", getTokenForLoggedInUser(t, loginUser(t, user.Name)))
|
||||
|
||||
packageName := "@scope/test-package"
|
||||
packageVersion := "1.0.1-pre"
|
||||
packageTag := "latest"
|
||||
packageTag2 := "release"
|
||||
packageAuthor := "KN4CK3R"
|
||||
packageDescription := "Test Description"
|
||||
|
||||
data := "H4sIAAAAAAAA/ytITM5OTE/VL4DQelnF+XkMVAYGBgZmJiYK2MRBwNDcSIHB2NTMwNDQzMwAqA7IMDUxA9LUdgg2UFpcklgEdAql5kD8ogCnhwio5lJQUMpLzE1VslJQcihOzi9I1S9JLS7RhSYIJR2QgrLUouLM/DyQGkM9Az1D3YIiqExKanFyUWZBCVQ2BKhVwQVJDKwosbQkI78IJO/tZ+LsbRykxFXLNdA+HwWjYBSMgpENACgAbtAACAAA"
|
||||
upload := `{
|
||||
"_id": "` + packageName + `",
|
||||
"name": "` + packageName + `",
|
||||
"description": "` + packageDescription + `",
|
||||
"dist-tags": {
|
||||
"` + packageTag + `": "` + packageVersion + `"
|
||||
},
|
||||
"versions": {
|
||||
"` + packageVersion + `": {
|
||||
"name": "` + packageName + `",
|
||||
"version": "` + packageVersion + `",
|
||||
"description": "` + packageDescription + `",
|
||||
"author": {
|
||||
"name": "` + packageAuthor + `"
|
||||
},
|
||||
"dist": {
|
||||
"integrity": "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==",
|
||||
"shasum": "aaa7eaf852a948b0aa05afeda35b1badca155d90"
|
||||
}
|
||||
}
|
||||
},
|
||||
"_attachments": {
|
||||
"` + packageName + `-` + packageVersion + `.tgz": {
|
||||
"data": "` + data + `"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
root := fmt.Sprintf("/api/packages/%s/npm/%s", user.Name, url.QueryEscape(packageName))
|
||||
tagsRoot := fmt.Sprintf("/api/packages/%s/npm/-/package/%s/dist-tags", user.Name, url.QueryEscape(packageName))
|
||||
filename := fmt.Sprintf("%s-%s.tgz", strings.Split(packageName, "/")[1], packageVersion)
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", root, strings.NewReader(upload))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &npm.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
assert.Len(t, pd.Properties, 1)
|
||||
assert.Equal(t, npm.TagProperty, pd.Properties[0].Name)
|
||||
assert.Equal(t, packageTag, pd.Properties[0].Value)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(192), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadExists", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", root, strings.NewReader(upload))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/-/%s/%s", root, packageVersion, filename))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
b, _ := base64.StdEncoding.DecodeString(data)
|
||||
assert.Equal(t, b, resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("PackageMetadata", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/packages/%s/npm/%s", user.Name, "does-not-exist"))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", root)
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result npm.PackageMetadata
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, packageName, result.ID)
|
||||
assert.Equal(t, packageName, result.Name)
|
||||
assert.Equal(t, packageDescription, result.Description)
|
||||
assert.Contains(t, result.DistTags, packageTag)
|
||||
assert.Equal(t, packageVersion, result.DistTags[packageTag])
|
||||
assert.Equal(t, packageAuthor, result.Author.Name)
|
||||
assert.Contains(t, result.Versions, packageVersion)
|
||||
pmv := result.Versions[packageVersion]
|
||||
assert.Equal(t, fmt.Sprintf("%s@%s", packageName, packageVersion), pmv.ID)
|
||||
assert.Equal(t, packageName, pmv.Name)
|
||||
assert.Equal(t, packageDescription, pmv.Description)
|
||||
assert.Equal(t, packageAuthor, pmv.Author.Name)
|
||||
assert.Equal(t, "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==", pmv.Dist.Integrity)
|
||||
assert.Equal(t, "aaa7eaf852a948b0aa05afeda35b1badca155d90", pmv.Dist.Shasum)
|
||||
assert.Equal(t, fmt.Sprintf("%s%s/-/%s/%s", setting.AppURL, root[1:], packageVersion, filename), pmv.Dist.Tarball)
|
||||
})
|
||||
|
||||
t.Run("AddTag", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
test := func(t *testing.T, status int, tag, version string) {
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/%s", tagsRoot, tag), strings.NewReader(`"`+version+`"`))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, status)
|
||||
}
|
||||
|
||||
test(t, http.StatusBadRequest, "1.0", packageVersion)
|
||||
test(t, http.StatusBadRequest, "v1.0", packageVersion)
|
||||
test(t, http.StatusNotFound, packageTag2, "1.2")
|
||||
test(t, http.StatusOK, packageTag, packageVersion)
|
||||
test(t, http.StatusOK, packageTag2, packageVersion)
|
||||
})
|
||||
|
||||
t.Run("ListTags", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", tagsRoot)
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result map[string]string
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Len(t, result, 2)
|
||||
assert.Contains(t, result, packageTag)
|
||||
assert.Equal(t, packageVersion, result[packageTag])
|
||||
assert.Contains(t, result, packageTag2)
|
||||
assert.Equal(t, packageVersion, result[packageTag2])
|
||||
})
|
||||
|
||||
t.Run("PackageMetadataDistTags", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", root)
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result npm.PackageMetadata
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Len(t, result.DistTags, 2)
|
||||
assert.Contains(t, result.DistTags, packageTag)
|
||||
assert.Equal(t, packageVersion, result.DistTags[packageTag])
|
||||
assert.Contains(t, result.DistTags, packageTag2)
|
||||
assert.Equal(t, packageVersion, result.DistTags[packageTag2])
|
||||
})
|
||||
|
||||
t.Run("DeleteTag", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
test := func(t *testing.T, status int, tag string) {
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s", tagsRoot, tag))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, status)
|
||||
}
|
||||
|
||||
test(t, http.StatusBadRequest, "v1.0")
|
||||
test(t, http.StatusBadRequest, "1.0")
|
||||
test(t, http.StatusOK, "dummy")
|
||||
test(t, http.StatusOK, packageTag2)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,381 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers/api/packages/nuget"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageNuGet(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
packageName := "test.package"
|
||||
packageVersion := "1.0.3"
|
||||
packageAuthors := "KN4CK3R"
|
||||
packageDescription := "Gitea Test Package"
|
||||
symbolFilename := "test.pdb"
|
||||
symbolID := "d910bb6948bd4c6cb40155bcf52c3c94"
|
||||
|
||||
var buf bytes.Buffer
|
||||
archive := zip.NewWriter(&buf)
|
||||
w, _ := archive.Create("package.nuspec")
|
||||
w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>` + packageName + `</id>
|
||||
<version>` + packageVersion + `</version>
|
||||
<authors>` + packageAuthors + `</authors>
|
||||
<description>` + packageDescription + `</description>
|
||||
<group targetFramework=".NETStandard2.0">
|
||||
<dependency id="Microsoft.CSharp" version="4.5.0" />
|
||||
</group>
|
||||
</metadata>
|
||||
</package>`))
|
||||
archive.Close()
|
||||
content := buf.Bytes()
|
||||
|
||||
url := fmt.Sprintf("/api/packages/%s/nuget", user.Name)
|
||||
|
||||
t.Run("ServiceIndex", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result nuget.ServiceIndexResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, "3.0.0", result.Version)
|
||||
assert.NotEmpty(t, result.Resources)
|
||||
|
||||
root := setting.AppURL + url[1:]
|
||||
for _, r := range result.Resources {
|
||||
switch r.Type {
|
||||
case "SearchQueryService":
|
||||
fallthrough
|
||||
case "SearchQueryService/3.0.0-beta":
|
||||
fallthrough
|
||||
case "SearchQueryService/3.0.0-rc":
|
||||
assert.Equal(t, root+"/query", r.ID)
|
||||
case "RegistrationsBaseUrl":
|
||||
fallthrough
|
||||
case "RegistrationsBaseUrl/3.0.0-beta":
|
||||
fallthrough
|
||||
case "RegistrationsBaseUrl/3.0.0-rc":
|
||||
assert.Equal(t, root+"/registration", r.ID)
|
||||
case "PackageBaseAddress/3.0.0":
|
||||
assert.Equal(t, root+"/package", r.ID)
|
||||
case "PackagePublish/2.0.0":
|
||||
assert.Equal(t, root, r.ID)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
t.Run("DependencyPackage", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &nuget_module.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion), pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(content)), pb.Size)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("SymbolPackage", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
createPackage := func(id, packageType string) io.Reader {
|
||||
var buf bytes.Buffer
|
||||
archive := zip.NewWriter(&buf)
|
||||
|
||||
w, _ := archive.Create("package.nuspec")
|
||||
w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>` + id + `</id>
|
||||
<version>` + packageVersion + `</version>
|
||||
<authors>` + packageAuthors + `</authors>
|
||||
<description>` + packageDescription + `</description>
|
||||
<packageTypes><packageType name="` + packageType + `" /></packageTypes>
|
||||
</metadata>
|
||||
</package>`))
|
||||
|
||||
w, _ = archive.Create(symbolFilename)
|
||||
b, _ := base64.StdEncoding.DecodeString(`QlNKQgEAAQAAAAAADAAAAFBEQiB2MS4wAAAAAAAABgB8AAAAWAAAACNQZGIAAAAA1AAAAAgBAAAj
|
||||
fgAA3AEAAAQAAAAjU3RyaW5ncwAAAADgAQAABAAAACNVUwDkAQAAMAAAACNHVUlEAAAAFAIAACgB
|
||||
AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
|
||||
w.Write(b)
|
||||
|
||||
archive.Close()
|
||||
return &buf
|
||||
}
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage("unknown-package", "SymbolsPackage"))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage(packageName, "DummyPackage"))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage(packageName, "SymbolsPackage"))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &nuget_module.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 3)
|
||||
for _, pf := range pfs {
|
||||
switch pf.Name {
|
||||
case fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion):
|
||||
case fmt.Sprintf("%s.%s.snupkg", packageName, packageVersion):
|
||||
assert.False(t, pf.IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(616), pb.Size)
|
||||
case symbolFilename:
|
||||
assert.False(t, pf.IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(160), pb.Size)
|
||||
|
||||
pps, err := packages.GetProperties(db.DefaultContext, packages.PropertyTypeFile, pf.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pps, 1)
|
||||
assert.Equal(t, nuget_module.PropertySymbolID, pps[0].Name)
|
||||
assert.Equal(t, symbolID, pps[0].Value)
|
||||
default:
|
||||
assert.Fail(t, "unexpected file: %v", pf.Name)
|
||||
}
|
||||
}
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage(packageName, "SymbolsPackage"))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
checkDownloadCount := func(count int64) {
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, count, pvs[0].DownloadCount)
|
||||
}
|
||||
|
||||
checkDownloadCount(0)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.nupkg", url, packageName, packageVersion, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, content, resp.Body.Bytes())
|
||||
|
||||
checkDownloadCount(1)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.snupkg", url, packageName, packageVersion, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkDownloadCount(1)
|
||||
|
||||
t.Run("Symbol", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFFFFF/gitea.pdb", url, symbolFilename, symbolID))
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFFFFF/%s", url, symbolFilename, "00000000000000000000000000000000", symbolFilename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFFFFF/%s", url, symbolFilename, symbolID, symbolFilename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkDownloadCount(1)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("SearchService", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Query string
|
||||
Skip int
|
||||
Take int
|
||||
ExpectedTotal int64
|
||||
ExpectedResults int
|
||||
}{
|
||||
{"", 0, 0, 1, 1},
|
||||
{"", 0, 10, 1, 1},
|
||||
{"gitea", 0, 10, 0, 0},
|
||||
{"test", 0, 10, 1, 1},
|
||||
{"test", 1, 10, 1, 0},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/query?q=%s&skip=%d&take=%d", url, c.Query, c.Skip, c.Take))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result nuget.SearchResultResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, c.ExpectedTotal, result.TotalHits, "case %d: unexpected total hits", i)
|
||||
assert.Len(t, result.Data, c.ExpectedResults, "case %d: unexpected result count", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RegistrationService", func(t *testing.T) {
|
||||
indexURL := fmt.Sprintf("%s%s/registration/%s/index.json", setting.AppURL, url[1:], packageName)
|
||||
leafURL := fmt.Sprintf("%s%s/registration/%s/%s.json", setting.AppURL, url[1:], packageName, packageVersion)
|
||||
contentURL := fmt.Sprintf("%s%s/package/%s/%s/%s.%s.nupkg", setting.AppURL, url[1:], packageName, packageVersion, packageName, packageVersion)
|
||||
|
||||
t.Run("RegistrationIndex", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/registration/%s/index.json", url, packageName))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result nuget.RegistrationIndexResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, indexURL, result.RegistrationIndexURL)
|
||||
assert.Equal(t, 1, result.Count)
|
||||
assert.Len(t, result.Pages, 1)
|
||||
assert.Equal(t, indexURL, result.Pages[0].RegistrationPageURL)
|
||||
assert.Equal(t, packageVersion, result.Pages[0].Lower)
|
||||
assert.Equal(t, packageVersion, result.Pages[0].Upper)
|
||||
assert.Equal(t, 1, result.Pages[0].Count)
|
||||
assert.Len(t, result.Pages[0].Items, 1)
|
||||
assert.Equal(t, packageName, result.Pages[0].Items[0].CatalogEntry.ID)
|
||||
assert.Equal(t, packageVersion, result.Pages[0].Items[0].CatalogEntry.Version)
|
||||
assert.Equal(t, packageAuthors, result.Pages[0].Items[0].CatalogEntry.Authors)
|
||||
assert.Equal(t, packageDescription, result.Pages[0].Items[0].CatalogEntry.Description)
|
||||
assert.Equal(t, leafURL, result.Pages[0].Items[0].CatalogEntry.CatalogLeafURL)
|
||||
assert.Equal(t, contentURL, result.Pages[0].Items[0].CatalogEntry.PackageContentURL)
|
||||
})
|
||||
|
||||
t.Run("RegistrationLeaf", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/registration/%s/%s.json", url, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result nuget.RegistrationLeafResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, leafURL, result.RegistrationLeafURL)
|
||||
assert.Equal(t, contentURL, result.PackageContentURL)
|
||||
assert.Equal(t, indexURL, result.RegistrationIndexURL)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("PackageService", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/index.json", url, packageName))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result nuget.PackageVersionsResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Len(t, result.Versions, 1)
|
||||
assert.Equal(t, packageVersion, result.Versions[0])
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, pvs)
|
||||
})
|
||||
|
||||
t.Run("DownloadNotExists", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.nupkg", url, packageName, packageVersion, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.snupkg", url, packageName, packageVersion, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("DeleteNotExists", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/package/%s/%s", url, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/packages/pypi"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackagePyPI(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
packageName := "test-package"
|
||||
packageVersion := "1.0.1"
|
||||
packageAuthor := "KN4CK3R"
|
||||
packageDescription := "Test Description"
|
||||
|
||||
content := "test"
|
||||
hashSHA256 := "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
|
||||
|
||||
root := fmt.Sprintf("/api/packages/%s/pypi", user.Name)
|
||||
|
||||
uploadFile := func(t *testing.T, filename, content string, expectedStatus int) {
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
part, _ := writer.CreateFormFile("content", filename)
|
||||
_, _ = io.Copy(part, strings.NewReader(content))
|
||||
|
||||
writer.WriteField("name", packageName)
|
||||
writer.WriteField("version", packageVersion)
|
||||
writer.WriteField("author", packageAuthor)
|
||||
writer.WriteField("summary", packageDescription)
|
||||
writer.WriteField("description", packageDescription)
|
||||
writer.WriteField("sha256_digest", hashSHA256)
|
||||
writer.WriteField("requires_python", "3.6")
|
||||
|
||||
_ = writer.Close()
|
||||
|
||||
req := NewRequestWithBody(t, "POST", root, body)
|
||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
filename := "test.whl"
|
||||
uploadFile(t, filename, content, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePyPI)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(4), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadAddFile", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
filename := "test.tar.gz"
|
||||
uploadFile(t, filename, content, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePyPI)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 2)
|
||||
|
||||
pf, err := packages.GetFileForVersionByName(db.DefaultContext, pvs[0].ID, filename, packages.EmptyFileKey)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, filename, pf.Name)
|
||||
assert.True(t, pf.IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(4), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadHashMismatch", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
filename := "test2.whl"
|
||||
uploadFile(t, filename, "dummy", http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("UploadExists", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
uploadFile(t, "test.whl", content, http.StatusBadRequest)
|
||||
uploadFile(t, "test.tar.gz", content, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
downloadFile := func(filename string) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/files/%s/%s/%s", root, packageName, packageVersion, filename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, []byte(content), resp.Body.Bytes())
|
||||
}
|
||||
|
||||
downloadFile("test.whl")
|
||||
downloadFile("test.tar.gz")
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePyPI)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(2), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("PackageMetadata", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/simple/%s", root, packageName))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
nodes := htmlDoc.doc.Find("a").Nodes
|
||||
assert.Len(t, nodes, 2)
|
||||
|
||||
hrefMatcher := regexp.MustCompile(fmt.Sprintf(`%s/files/%s/%s/test\..+#sha256-%s`, root, packageName, packageVersion, hashSHA256))
|
||||
|
||||
for _, a := range nodes {
|
||||
for _, att := range a.Attr {
|
||||
switch att.Key {
|
||||
case "href":
|
||||
assert.Regexp(t, hrefMatcher, att.Val)
|
||||
case "data-requires-python":
|
||||
assert.Equal(t, "3.6", att.Val)
|
||||
default:
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/packages/rubygems"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageRubyGems(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
packageName := "gitea"
|
||||
packageVersion := "1.0.5"
|
||||
packageFilename := "gitea-1.0.5.gem"
|
||||
|
||||
gemContent, _ := base64.StdEncoding.DecodeString(`bWV0YWRhdGEuZ3oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA0NDQAMDAwMDAw
|
||||
MAAwMDAwMDAwADAwMDAwMDAxMDQxADE0MTEwNzcyMzY2ADAxMzQ0MQAgMAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMHdoZWVsAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAd2hlZWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAw
|
||||
MDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf
|
||||
iwgA9vQjYQID1VVNb9QwEL37V5he9pRsmlJAFlQckCoOXAriQIUix5nNmsYf2JOqKwS/nYmz2d3Q
|
||||
qqCCKpFdadfjmfdm5nmcLMv4k9DXm6Wrv4BCcQ5GiPcelF5pJVE7y6w0IHirESS7hhDJJu4I+jhu
|
||||
Mc53Tsd5kZ8y30lcuWAEH2KY7HHtQhQs4+cJkwwuwNdeB6JhtbaNDoLTL1MQsFJrqQnr8jNrJJJH
|
||||
WZTHWfEiK094UYj0zYvp4Z9YAx5sA1ZpSCS3M30zeWwo2bG60FvUBjIKJts2GwMW76r0Yr9NzjN3
|
||||
YhwsGX2Ozl4dpcWwvK9d43PQtDIv9igvHwSyIIwFmXHjqTqxLY8MPkCADmQk80p2EfZ6VbM6/ue6
|
||||
/1D0Bq7/qeA/zh6W82leHmhFWUHn/JbsEfT6q7QbiCpoj8l0QcEUFLmX6kq2wBEiMjBSd+Pwt7T5
|
||||
Ot0kuXYMbkD1KOuOBnWYb7hBsAP4bhlkFRqnqpWefMZ/pHCn6+WIFGq2dgY8EQq+RvRRLJcTyZJ1
|
||||
WhHqGPTu7QdmACXdJFLwb9+ZdxErbSPKrqsMxJhAWCJ1qaqRdtu6yktcT/STsamG0qp7rsa5EL/K
|
||||
MBua30uw4ynzExqYWRJDfx8/kQWN3PwsDh2jYLr1W+pZcAmCs9splvnz/Flesqhbq21bXcGG/OLh
|
||||
+2fv/JTF3hgZyCW9OaZjxoZjdnBGfgKpxZyJ1QYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGF0
|
||||
YS50YXIuZ3oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA0NDQAMDAwMDAwMAAw
|
||||
MDAwMDAwADAwMDAwMDAwMjQyADE0MTEwNzcyMzY2ADAxMzM2MQAgMAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMHdoZWVsAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAd2hlZWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAwMDAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfiwgA
|
||||
9vQjYQID7M/NCsMgDABgz32KrA/QxersK/Q17ExXIcyhlr7+HLv1sJ02KPhBCPk5JOyn881nsl2c
|
||||
xI+gRDRaC3zbZ8RBCamlxGHolTFlX11kLwDFH6wp21hO2RYi/rD3bb5/7iCubFOCMbBtABzNkIjn
|
||||
bvGlAnisOUE7EnOALUR2p7b06e6aV4iqqqrquJ4AAAD//wMA+sA/NQAIAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGNoZWNr
|
||||
c3Vtcy55YW1sLmd6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwNDQ0ADAwMDAwMDAAMDAw
|
||||
MDAwMAAwMDAwMDAwMDQ1MAAxNDExMDc3MjM2NgAwMTQ2MTIAIDAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDB3aGVlbAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAHdoZWVsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDAwMAAwMDAwMDAwAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH4sIAPb0
|
||||
I2ECA2WQOa4UQAxE8znFXGCQ21vbPyMj5wRuL0Qk6EecnmZCyKyy9FSvXq/X4/u3ryj68Xg+f/Zn
|
||||
VHzGlx+/P57qvU4XxWalBKftSXOgCjNYkdRycrC5Axem+W4HqS12PNEv7836jF9vnlHxwSyxKY+y
|
||||
go0cPblyHzkrZ4HF1GSVhe7mOOoasXNk2fnbUxb+19Pp9tobD/QlJKMX7y204PREh6nQ5hG9Alw6
|
||||
x4TnmtA+aekGfm6wAseog2LSgpR4Q7cYnAH3K4qAQa6A6JCC1gpuY7P+9YxE5SZ+j0eVGbaBTwBQ
|
||||
iIqRUyyzLCoFCBdYNWxniapTavD97blXTzFvgoVoAsKBAtlU48cdaOmeZDpwV01OtcGwjscfeUrY
|
||||
B9QBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`)
|
||||
|
||||
root := fmt.Sprintf("/api/packages/%s/rubygems", user.Name)
|
||||
|
||||
uploadFile := func(t *testing.T, expectedStatus int) {
|
||||
req := NewRequestWithBody(t, "POST", fmt.Sprintf("%s/api/v1/gems", root), bytes.NewReader(gemContent))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
uploadFile(t, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeRubyGems)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &rubygems.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, packageFilename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(4608), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadExists", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
uploadFile(t, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/gems/%s", root, packageFilename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, gemContent, resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeRubyGems)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("DownloadGemspec", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/quick/Marshal.4.8/%sspec.rz", root, packageFilename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
b, _ := base64.StdEncoding.DecodeString(`eJxi4Si1EndPzbWyCi5ITc5My0xOLMnMz2M8zMIRLeGpxGWsZ6RnzGbF5hqSyempxJWeWZKayGbN
|
||||
EBJqJQjWFZZaVJyZnxfN5qnEZahnoGcKkjTwVBJyB6lUKEhMzk5MTwULGngqcRaVJlWCONEMBp5K
|
||||
DGAWSKc7zFhPJamg0qRK99TcYphehZLU4hKInFhGSUlBsZW+PtgZepn5+iDxECRzDUDGcfh6hoA4
|
||||
gAAAAP//MS06Gw==`)
|
||||
assert.Equal(t, b, resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeRubyGems)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("EnumeratePackages", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
enumeratePackages := func(t *testing.T, endpoint string, expectedContent []byte) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s", root, endpoint))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, expectedContent, resp.Body.Bytes())
|
||||
}
|
||||
|
||||
b, _ := base64.StdEncoding.DecodeString(`H4sICAAAAAAA/3NwZWNzLjQuOABi4Yhmi+bwVOJKzyxJTWSzYnMNCbUSdE/NtbIKSy0qzszPi2bzVOIy1DPQM2WzZgjxVOIsKk2qBDEBAQAA///xOEYKOwAAAA==`)
|
||||
enumeratePackages(t, "specs.4.8.gz", b)
|
||||
b, _ = base64.StdEncoding.DecodeString(`H4sICAAAAAAA/2xhdGVzdF9zcGVjcy40LjgAYuGIZovm8FTiSs8sSU1ks2JzDQm1EnRPzbWyCkstKs7Mz4tm81TiMtQz0DNls2YI8VTiLCpNqgQxAQEAAP//8ThGCjsAAAA=`)
|
||||
enumeratePackages(t, "latest_specs.4.8.gz", b)
|
||||
b, _ = base64.StdEncoding.DecodeString(`H4sICAAAAAAA/3ByZXJlbGVhc2Vfc3BlY3MuNC44AGLhiGYABAAA//9snXr5BAAAAA==`)
|
||||
enumeratePackages(t, "prerelease_specs.4.8.gz", b)
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
body := bytes.Buffer{}
|
||||
writer := multipart.NewWriter(&body)
|
||||
writer.WriteField("gem_name", packageName)
|
||||
writer.WriteField("version", packageVersion)
|
||||
writer.Close()
|
||||
|
||||
req := NewRequestWithBody(t, "DELETE", fmt.Sprintf("%s/api/v1/gems/yank", root), &body)
|
||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeRubyGems)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, pvs)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
container_model "code.gitea.io/gitea/models/packages/container"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
packages_service "code.gitea.io/gitea/services/packages"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageAPI(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
packageName := "test-package"
|
||||
packageVersion := "1.0.3"
|
||||
filename := "file.bin"
|
||||
|
||||
url := fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, filename)
|
||||
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader([]byte{}))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
t.Run("ListPackages", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s?token=%s", user.Name, token))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiPackages []*api.Package
|
||||
DecodeJSON(t, resp, &apiPackages)
|
||||
|
||||
assert.Len(t, apiPackages, 1)
|
||||
assert.Equal(t, string(packages_model.TypeGeneric), apiPackages[0].Type)
|
||||
assert.Equal(t, packageName, apiPackages[0].Name)
|
||||
assert.Equal(t, packageVersion, apiPackages[0].Version)
|
||||
assert.NotNil(t, apiPackages[0].Creator)
|
||||
assert.Equal(t, user.Name, apiPackages[0].Creator.UserName)
|
||||
})
|
||||
|
||||
t.Run("GetPackage", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/dummy/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var p *api.Package
|
||||
DecodeJSON(t, resp, &p)
|
||||
|
||||
assert.Equal(t, string(packages_model.TypeGeneric), p.Type)
|
||||
assert.Equal(t, packageName, p.Name)
|
||||
assert.Equal(t, packageVersion, p.Version)
|
||||
assert.NotNil(t, p.Creator)
|
||||
assert.Equal(t, user.Name, p.Creator.UserName)
|
||||
|
||||
t.Run("RepositoryLink", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
p, err := packages_model.GetPackageByName(db.DefaultContext, user.ID, packages_model.TypeGeneric, packageName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// no repository link
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var ap1 *api.Package
|
||||
DecodeJSON(t, resp, &ap1)
|
||||
assert.Nil(t, ap1.Repository)
|
||||
|
||||
// link to public repository
|
||||
assert.NoError(t, packages_model.SetRepositoryLink(db.DefaultContext, p.ID, 1))
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var ap2 *api.Package
|
||||
DecodeJSON(t, resp, &ap2)
|
||||
assert.NotNil(t, ap2.Repository)
|
||||
assert.EqualValues(t, 1, ap2.Repository.ID)
|
||||
|
||||
// link to private repository
|
||||
assert.NoError(t, packages_model.SetRepositoryLink(db.DefaultContext, p.ID, 2))
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var ap3 *api.Package
|
||||
DecodeJSON(t, resp, &ap3)
|
||||
assert.Nil(t, ap3.Repository)
|
||||
|
||||
assert.NoError(t, packages_model.UnlinkRepositoryFromAllPackages(db.DefaultContext, 2))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("ListPackageFiles", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/dummy/%s/%s/files?token=%s", user.Name, packageName, packageVersion, token))
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s/files?token=%s", user.Name, packageName, packageVersion, token))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var files []*api.PackageFile
|
||||
DecodeJSON(t, resp, &files)
|
||||
|
||||
assert.Len(t, files, 1)
|
||||
assert.Equal(t, int64(0), files[0].Size)
|
||||
assert.Equal(t, filename, files[0].Name)
|
||||
assert.Equal(t, "d41d8cd98f00b204e9800998ecf8427e", files[0].HashMD5)
|
||||
assert.Equal(t, "da39a3ee5e6b4b0d3255bfef95601890afd80709", files[0].HashSHA1)
|
||||
assert.Equal(t, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", files[0].HashSHA256)
|
||||
assert.Equal(t, "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", files[0].HashSHA512)
|
||||
})
|
||||
|
||||
t.Run("DeletePackage", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/packages/%s/dummy/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPackageCleanup(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
pbs, err := packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, time.Duration(0))
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, pbs)
|
||||
|
||||
_, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, 2, packages_model.TypeContainer, "test", container_model.UploadVersion)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = packages_service.Cleanup(nil, time.Duration(0))
|
||||
assert.NoError(t, err)
|
||||
|
||||
pbs, err = packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, time.Duration(0))
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, pbs)
|
||||
|
||||
_, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, 2, packages_model.TypeContainer, "test", container_model.UploadVersion)
|
||||
assert.ErrorIs(t, err, packages_model.ErrPackageNotExist)
|
||||
}
|
|
@ -47,7 +47,7 @@ func TestAPIPrivateServ(t *testing.T) {
|
|||
results, err := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.False(t, results.IsDeployKey)
|
||||
assert.Zero(t, results.DeployKeyID)
|
||||
assert.Equal(t, int64(1), results.KeyID)
|
||||
assert.Equal(t, "user2@localhost", results.KeyName)
|
||||
assert.Equal(t, "user2", results.UserName)
|
||||
|
@ -70,7 +70,7 @@ func TestAPIPrivateServ(t *testing.T) {
|
|||
results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.False(t, results.IsDeployKey)
|
||||
assert.Zero(t, results.DeployKeyID)
|
||||
assert.Equal(t, int64(1), results.KeyID)
|
||||
assert.Equal(t, "user2@localhost", results.KeyName)
|
||||
assert.Equal(t, "user2", results.UserName)
|
||||
|
@ -92,7 +92,7 @@ func TestAPIPrivateServ(t *testing.T) {
|
|||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.True(t, results.IsDeployKey)
|
||||
assert.NotZero(t, results.DeployKeyID)
|
||||
assert.Equal(t, deployKey.KeyID, results.KeyID)
|
||||
assert.Equal(t, "test-deploy", results.KeyName)
|
||||
assert.Equal(t, "user15", results.UserName)
|
||||
|
@ -129,7 +129,7 @@ func TestAPIPrivateServ(t *testing.T) {
|
|||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.True(t, results.IsDeployKey)
|
||||
assert.NotZero(t, results.DeployKeyID)
|
||||
assert.Equal(t, deployKey.KeyID, results.KeyID)
|
||||
assert.Equal(t, "test-deploy", results.KeyName)
|
||||
assert.Equal(t, "user15", results.UserName)
|
||||
|
@ -142,7 +142,7 @@ func TestAPIPrivateServ(t *testing.T) {
|
|||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.True(t, results.IsDeployKey)
|
||||
assert.NotZero(t, results.DeployKeyID)
|
||||
assert.Equal(t, deployKey.KeyID, results.KeyID)
|
||||
assert.Equal(t, "test-deploy", results.KeyName)
|
||||
assert.Equal(t, "user15", results.UserName)
|
||||
|
|
|
@ -77,7 +77,7 @@ func TestAPICreatePullSuccess(t *testing.T) {
|
|||
Base: "master",
|
||||
Title: "create a failure pr",
|
||||
})
|
||||
session.MakeRequest(t, req, 201)
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity) // second request should fail
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ func TestAPICreatePullWithFieldsSuccess(t *testing.T) {
|
|||
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s", owner10.Name, repo10.Name, token), opts)
|
||||
|
||||
res := session.MakeRequest(t, req, 201)
|
||||
res := session.MakeRequest(t, req, http.StatusCreated)
|
||||
pull := new(api.PullRequest)
|
||||
DecodeJSON(t, res, pull)
|
||||
|
||||
|
@ -165,7 +165,7 @@ func TestAPIEditPull(t *testing.T) {
|
|||
Title: "create a success pr",
|
||||
})
|
||||
pull := new(api.PullRequest)
|
||||
resp := session.MakeRequest(t, req, 201)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, pull)
|
||||
assert.EqualValues(t, "master", pull.Base.Name)
|
||||
|
||||
|
@ -173,12 +173,12 @@ func TestAPIEditPull(t *testing.T) {
|
|||
Base: "feature/1",
|
||||
Title: "edit a this pr",
|
||||
})
|
||||
resp = session.MakeRequest(t, req, 201)
|
||||
resp = session.MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, pull)
|
||||
assert.EqualValues(t, "feature/1", pull.Base.Name)
|
||||
|
||||
req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d?token=%s", owner10.Name, repo10.Name, pull.Index, token), &api.EditPullRequestOption{
|
||||
Base: "not-exist",
|
||||
})
|
||||
session.MakeRequest(t, req, 404)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
|
|
@ -25,12 +25,11 @@ func TestAPIListReleases(t *testing.T) {
|
|||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
session := loginUser(t, user2.LowerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
token := getUserToken(t, user2.LowerName)
|
||||
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/releases", user2.Name, repo.Name))
|
||||
link.RawQuery = url.Values{"token": {token}}.Encode()
|
||||
resp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
var apiReleases []*api.Release
|
||||
DecodeJSON(t, resp, &apiReleases)
|
||||
if assert.Len(t, apiReleases, 3) {
|
||||
|
@ -53,13 +52,11 @@ func TestAPIListReleases(t *testing.T) {
|
|||
|
||||
// test filter
|
||||
testFilterByLen := func(auth bool, query url.Values, expectedLength int, msgAndArgs ...string) {
|
||||
link.RawQuery = query.Encode()
|
||||
if auth {
|
||||
query.Set("token", token)
|
||||
resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
} else {
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
}
|
||||
link.RawQuery = query.Encode()
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiReleases)
|
||||
assert.Len(t, apiReleases, expectedLength, msgAndArgs)
|
||||
}
|
||||
|
@ -105,7 +102,7 @@ func TestAPICreateAndUpdateRelease(t *testing.T) {
|
|||
session := loginUser(t, owner.LowerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
gitRepo, err := git.OpenRepository(git.DefaultContext, repo.RepoPath())
|
||||
assert.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
|
||||
|
@ -167,7 +164,7 @@ func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) {
|
|||
session := loginUser(t, owner.LowerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
gitRepo, err := git.OpenRepository(git.DefaultContext, repo.RepoPath())
|
||||
assert.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue