mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-10 00:05:01 +02:00
Merge remote-tracking branch 'upstream/main' into limit-repo-size
Resolved Conflicts: models/migrations/migrations.go services/forms/repo_form.go templates/admin/repo/list.tmpl templates/repo/settings/options.tmpl
This commit is contained in:
commit
f810b42a2e
@ -44,7 +44,10 @@ steps:
|
||||
image: techknowlogick/xgo:go-1.21.x
|
||||
pull: always
|
||||
commands:
|
||||
- curl -sL https://deb.nodesource.com/setup_20.x | bash - && apt-get -qqy install nodejs
|
||||
- apt-get update && apt-get -qqy install ca-certificates curl gnupg
|
||||
- mkdir -p /etc/apt/keyrings && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||
- echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list
|
||||
- apt-get update && apt-get -qqy install nodejs
|
||||
- export PATH=$PATH:$GOPATH/bin
|
||||
- make release
|
||||
environment:
|
||||
|
||||
@ -11,7 +11,6 @@ parserOptions:
|
||||
plugins:
|
||||
- "@eslint-community/eslint-plugin-eslint-comments"
|
||||
- eslint-plugin-array-func
|
||||
- eslint-plugin-custom-elements
|
||||
- eslint-plugin-import
|
||||
- eslint-plugin-jquery
|
||||
- eslint-plugin-no-jquery
|
||||
@ -19,6 +18,7 @@ plugins:
|
||||
- eslint-plugin-regexp
|
||||
- eslint-plugin-sonarjs
|
||||
- eslint-plugin-unicorn
|
||||
- eslint-plugin-vitest-globals
|
||||
- eslint-plugin-wc
|
||||
|
||||
env:
|
||||
@ -46,6 +46,12 @@ overrides:
|
||||
- files: ["*.config.*"]
|
||||
rules:
|
||||
import/no-unused-modules: [0]
|
||||
- files: ["**/*.test.*", "web_src/js/test/setup.js"]
|
||||
env:
|
||||
vitest-globals/env: true
|
||||
- files: ["web_src/js/modules/fetch.js", "web_src/js/standalone/**/*"]
|
||||
rules:
|
||||
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
|
||||
|
||||
rules:
|
||||
"@eslint-community/eslint-comments/disable-enable-pair": [2]
|
||||
@ -85,19 +91,6 @@ rules:
|
||||
consistent-this: [0]
|
||||
constructor-super: [2]
|
||||
curly: [0]
|
||||
custom-elements/expose-class-on-global: [0]
|
||||
custom-elements/extends-correct-class: [2]
|
||||
custom-elements/file-name-matches-element: [2]
|
||||
custom-elements/no-constructor: [2]
|
||||
custom-elements/no-customized-built-in-elements: [2]
|
||||
custom-elements/no-dom-traversal-in-attributechangedcallback: [2]
|
||||
custom-elements/no-dom-traversal-in-connectedcallback: [2]
|
||||
custom-elements/no-exports-with-element: [2]
|
||||
custom-elements/no-method-prefixed-with-on: [2]
|
||||
custom-elements/no-unchecked-define: [0]
|
||||
custom-elements/one-element-per-file: [0]
|
||||
custom-elements/tag-name-matches-class: [2]
|
||||
custom-elements/valid-tag-name: [2]
|
||||
default-case-last: [2]
|
||||
default-case: [0]
|
||||
default-param-last: [0]
|
||||
@ -420,7 +413,7 @@ rules:
|
||||
no-restricted-exports: [0]
|
||||
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename]
|
||||
no-restricted-imports: [0]
|
||||
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
|
||||
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression, {selector: "CallExpression[callee.name='fetch']", message: "use modules/fetch.js instead"}]
|
||||
no-return-assign: [0]
|
||||
no-script-url: [2]
|
||||
no-self-assign: [2, {props: true}]
|
||||
@ -737,14 +730,27 @@ rules:
|
||||
valid-typeof: [2, {requireStringLiterals: true}]
|
||||
vars-on-top: [0]
|
||||
wc/attach-shadow-constructor: [2]
|
||||
wc/define-tag-after-class-definition: [0]
|
||||
wc/expose-class-on-global: [0]
|
||||
wc/file-name-matches-element: [2]
|
||||
wc/guard-define-call: [0]
|
||||
wc/guard-super-call: [2]
|
||||
wc/max-elements-per-file: [0]
|
||||
wc/no-child-traversal-in-attributechangedcallback: [2]
|
||||
wc/no-child-traversal-in-connectedcallback: [2]
|
||||
wc/no-closed-shadow-root: [2]
|
||||
wc/no-constructor-attributes: [2]
|
||||
wc/no-constructor-params: [2]
|
||||
wc/no-invalid-element-name: [0] # covered by custom-elements/valid-tag-name
|
||||
wc/no-constructor: [2]
|
||||
wc/no-customized-built-in-elements: [2]
|
||||
wc/no-exports-with-element: [2]
|
||||
wc/no-invalid-element-name: [2]
|
||||
wc/no-invalid-extends: [2]
|
||||
wc/no-method-prefixed-with-on: [2]
|
||||
wc/no-self-class: [2]
|
||||
wc/no-typos: [2]
|
||||
wc/require-listener-teardown: [2]
|
||||
wc/tag-name-matches-class: [2]
|
||||
wrap-iife: [2, inside]
|
||||
wrap-regex: [0]
|
||||
yield-star-spacing: [2, after]
|
||||
|
||||
2
.github/workflows/cron-licenses.yml
vendored
2
.github/workflows/cron-licenses.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'go-gitea/gitea'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
|
||||
4
.github/workflows/cron-translations.yml
vendored
4
.github/workflows/cron-translations.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'go-gitea/gitea'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: download from crowdin
|
||||
uses: docker://jonasfranz/crowdin
|
||||
env:
|
||||
@ -35,7 +35,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'go-gitea/gitea'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: push translations to crowdin
|
||||
uses: docker://jonasfranz/crowdin
|
||||
env:
|
||||
|
||||
7
.github/workflows/files-changed.yml
vendored
7
.github/workflows/files-changed.yml
vendored
@ -34,7 +34,7 @@ jobs:
|
||||
swagger: ${{ steps.changes.outputs.swagger }}
|
||||
yaml: ${{ steps.changes.outputs.yaml }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: changes
|
||||
with:
|
||||
@ -64,9 +64,12 @@ jobs:
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
- ".markdownlint.yaml"
|
||||
- "package.json"
|
||||
- "package-lock.json"
|
||||
|
||||
actions:
|
||||
- ".github/workflows/*"
|
||||
- "Makefile"
|
||||
|
||||
templates:
|
||||
- "templates/**/*.tmpl"
|
||||
@ -90,3 +93,5 @@ jobs:
|
||||
- "**/*.yml"
|
||||
- "**/*.yaml"
|
||||
- ".yamllint.yaml"
|
||||
- "pyproject.toml"
|
||||
- "poetry.lock"
|
||||
|
||||
22
.github/workflows/pull-compliance.yml
vendored
22
.github/workflows/pull-compliance.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
@ -31,7 +31,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
@ -44,7 +44,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
@ -57,7 +57,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
@ -69,7 +69,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
@ -86,7 +86,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
@ -101,7 +101,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
@ -114,7 +114,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
@ -129,7 +129,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
@ -161,7 +161,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
@ -174,6 +174,6 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
- run: make lint-actions
|
||||
|
||||
70
.github/workflows/pull-db-tests.yml
vendored
70
.github/workflows/pull-db-tests.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
pgsql:
|
||||
image: postgres:15
|
||||
image: postgres:12
|
||||
env:
|
||||
POSTGRES_DB: test
|
||||
POSTGRES_PASSWORD: postgres
|
||||
@ -31,14 +31,14 @@ jobs:
|
||||
minio:
|
||||
# as github actions doesn't support "entrypoint", we need to use a non-official image
|
||||
# that has a custom entrypoint set to "minio server /data"
|
||||
image: bitnami/minio:2021.3.17
|
||||
image: bitnami/minio:2023.8.31
|
||||
env:
|
||||
MINIO_ACCESS_KEY: 123456
|
||||
MINIO_SECRET_KEY: 12345678
|
||||
MINIO_ROOT_USER: 123456
|
||||
MINIO_ROOT_PASSWORD: 12345678
|
||||
ports:
|
||||
- "9000:9000"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
@ -63,7 +63,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
@ -85,13 +85,6 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: true
|
||||
MYSQL_DATABASE: test
|
||||
ports:
|
||||
- "3306:3306"
|
||||
elasticsearch:
|
||||
image: elasticsearch:7.5.0
|
||||
env:
|
||||
@ -104,13 +97,6 @@ jobs:
|
||||
MEILI_ENV: development # disable auth
|
||||
ports:
|
||||
- "7700:7700"
|
||||
smtpimap:
|
||||
image: tabascoterrier/docker-imap-devel:latest
|
||||
ports:
|
||||
- "25:25"
|
||||
- "143:143"
|
||||
- "587:587"
|
||||
- "993:993"
|
||||
redis:
|
||||
image: redis
|
||||
options: >- # wait until redis has started
|
||||
@ -128,7 +114,7 @@ jobs:
|
||||
ports:
|
||||
- "9000:9000"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
@ -152,16 +138,16 @@ jobs:
|
||||
RACE_ENABLED: true
|
||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
||||
|
||||
test-mysql5:
|
||||
test-mysql:
|
||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
image: mysql:8.0
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: true
|
||||
MYSQL_DATABASE: test
|
||||
MYSQL_DATABASE: testgitea
|
||||
ports:
|
||||
- "3306:3306"
|
||||
elasticsearch:
|
||||
@ -178,7 +164,7 @@ jobs:
|
||||
- "587:587"
|
||||
- "993:993"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
@ -197,43 +183,13 @@ jobs:
|
||||
USE_REPO_TEST_DIR: 1
|
||||
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
|
||||
|
||||
test-mysql8:
|
||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mysql8:
|
||||
image: mysql:8
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: true
|
||||
MYSQL_DATABASE: testgitea
|
||||
ports:
|
||||
- "3306:3306"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
check-latest: true
|
||||
- name: Add hosts to /etc/hosts
|
||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql8" | sudo tee -a /etc/hosts'
|
||||
- run: make deps-backend
|
||||
- run: make backend
|
||||
env:
|
||||
TAGS: bindata
|
||||
- run: make test-mysql8-migration test-mysql8
|
||||
timeout-minutes: 50
|
||||
env:
|
||||
TAGS: bindata
|
||||
USE_REPO_TEST_DIR: 1
|
||||
|
||||
test-mssql:
|
||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mssql:
|
||||
image: mcr.microsoft.com/mssql/server:latest
|
||||
image: mcr.microsoft.com/mssql/server:2017-latest
|
||||
env:
|
||||
ACCEPT_EULA: Y
|
||||
MSSQL_PID: Standard
|
||||
@ -241,7 +197,7 @@ jobs:
|
||||
ports:
|
||||
- "1433:1433"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
|
||||
2
.github/workflows/pull-e2e-tests.yml
vendored
2
.github/workflows/pull-e2e-tests.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "~1.21"
|
||||
|
||||
6
.github/workflows/release-nightly.yml
vendored
6
.github/workflows/release-nightly.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
nightly-binary:
|
||||
runs-on: actuated-4cpu-16gb
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
@ -58,7 +58,7 @@ jobs:
|
||||
nightly-docker-rootful:
|
||||
runs-on: actuated-4cpu-16gb
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
@ -95,7 +95,7 @@ jobs:
|
||||
nightly-docker-rootless:
|
||||
runs-on: actuated-4cpu-16gb
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
|
||||
@ -44,5 +44,3 @@ rules:
|
||||
ignore: |
|
||||
.venv
|
||||
node_modules
|
||||
/models/fixtures
|
||||
/models/migrations/fixtures
|
||||
|
||||
27
CHANGELOG.md
27
CHANGELOG.md
@ -4,6 +4,33 @@ 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.com).
|
||||
|
||||
## [1.20.5](https://github.com/go-gitea/gitea/releases/tag/v1.20.5) - 2023-10-03
|
||||
|
||||
* ENHANCEMENTS
|
||||
* Fix z-index on markdown completion (#27237) (#27242 & #27238)
|
||||
* Use secure cookie for HTTPS sites (#26999) (#27013)
|
||||
* BUGFIXES
|
||||
* Fix git 2.11 error when checking IsEmpty (#27393) (#27396)
|
||||
* Allow get release download files and lfs files with oauth2 token format (#26430) (#27378)
|
||||
* Fix orphan check for deleted branch (#27310) (#27320)
|
||||
* Quote table `release` in sql queries (#27205) (#27219)
|
||||
* Fix release URL in webhooks (#27182) (#27184)
|
||||
* Fix successful return value for `SyncAndGetUserSpecificDiff` (#27152) (#27156)
|
||||
* fix pagination for followers and following (#27127) (#27138)
|
||||
* Fix issue templates when blank isses are disabled (#27061) (#27082)
|
||||
* Fix context cache bug & enable context cache for dashabord commits' authors(#26991) (#27017)
|
||||
* Fix INI parsing for value with trailing slash (#26995) (#27001)
|
||||
* Fix PushEvent NullPointerException jenkinsci/github-plugin (#27203) (#27249)
|
||||
* Fix organization field being null in POST /orgs/{orgid}/teams (#27150) (#27167 & #27162)
|
||||
* Fix bug of review request number (#27406) (#27104)
|
||||
* TESTING
|
||||
* services/wiki: Close() after error handling (#27129) (#27137)
|
||||
* DOCS
|
||||
* Improve actions docs related to `pull_request` event (#27126) (#27145)
|
||||
* MISC
|
||||
* Add logs for data broken of comment review (#27326) (#27344)
|
||||
* Load reviewer before sending notification (#27063) (#27064)
|
||||
|
||||
## [1.20.4](https://github.com/go-gitea/gitea/releases/tag/v1.20.4) - 2023-09-08
|
||||
|
||||
* SECURITY
|
||||
|
||||
68
Makefile
68
Makefile
@ -167,10 +167,6 @@ TEST_MYSQL_HOST ?= mysql:3306
|
||||
TEST_MYSQL_DBNAME ?= testgitea
|
||||
TEST_MYSQL_USERNAME ?= root
|
||||
TEST_MYSQL_PASSWORD ?=
|
||||
TEST_MYSQL8_HOST ?= mysql8:3306
|
||||
TEST_MYSQL8_DBNAME ?= testgitea
|
||||
TEST_MYSQL8_USERNAME ?= root
|
||||
TEST_MYSQL8_PASSWORD ?=
|
||||
TEST_PGSQL_HOST ?= pgsql:5432
|
||||
TEST_PGSQL_DBNAME ?= testgitea
|
||||
TEST_PGSQL_USERNAME ?= postgres
|
||||
@ -226,6 +222,7 @@ help:
|
||||
@echo " - test-frontend test frontend files"
|
||||
@echo " - test-backend test backend files"
|
||||
@echo " - test-e2e[\#TestSpecificName] test end to end using playwright"
|
||||
@echo " - update update js and py dependencies"
|
||||
@echo " - update-js update js dependencies"
|
||||
@echo " - update-py update py dependencies"
|
||||
@echo " - webpack build webpack files"
|
||||
@ -281,12 +278,12 @@ clean:
|
||||
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \
|
||||
integrations*.test \
|
||||
e2e*.test \
|
||||
tests/integration/gitea-integration-pgsql/ tests/integration/gitea-integration-mysql/ tests/integration/gitea-integration-mysql8/ tests/integration/gitea-integration-sqlite/ \
|
||||
tests/integration/gitea-integration-mssql/ tests/integration/indexers-mysql/ tests/integration/indexers-mysql8/ tests/integration/indexers-pgsql tests/integration/indexers-sqlite \
|
||||
tests/integration/indexers-mssql tests/mysql.ini tests/mysql8.ini tests/pgsql.ini tests/mssql.ini man/ \
|
||||
tests/e2e/gitea-e2e-pgsql/ tests/e2e/gitea-e2e-mysql/ tests/e2e/gitea-e2e-mysql8/ tests/e2e/gitea-e2e-sqlite/ \
|
||||
tests/e2e/gitea-e2e-mssql/ tests/e2e/indexers-mysql/ tests/e2e/indexers-mysql8/ tests/e2e/indexers-pgsql/ tests/e2e/indexers-sqlite/ \
|
||||
tests/e2e/indexers-mssql/ tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/
|
||||
tests/integration/gitea-integration-* \
|
||||
tests/integration/indexers-* \
|
||||
tests/mysql.ini tests/pgsql.ini tests/mssql.ini man/ \
|
||||
tests/e2e/gitea-e2e-*/ \
|
||||
tests/e2e/indexers-*/ \
|
||||
tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
@ -550,27 +547,6 @@ test-mysql\#%: integrations.mysql.test generate-ini-mysql
|
||||
.PHONY: test-mysql-migration
|
||||
test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test
|
||||
|
||||
generate-ini-mysql8:
|
||||
sed -e 's|{{TEST_MYSQL8_HOST}}|${TEST_MYSQL8_HOST}|g' \
|
||||
-e 's|{{TEST_MYSQL8_DBNAME}}|${TEST_MYSQL8_DBNAME}|g' \
|
||||
-e 's|{{TEST_MYSQL8_USERNAME}}|${TEST_MYSQL8_USERNAME}|g' \
|
||||
-e 's|{{TEST_MYSQL8_PASSWORD}}|${TEST_MYSQL8_PASSWORD}|g' \
|
||||
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
|
||||
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
|
||||
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
|
||||
tests/mysql8.ini.tmpl > tests/mysql8.ini
|
||||
|
||||
.PHONY: test-mysql8
|
||||
test-mysql8: integrations.mysql8.test generate-ini-mysql8
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./integrations.mysql8.test
|
||||
|
||||
.PHONY: test-mysql8\#%
|
||||
test-mysql8\#%: integrations.mysql8.test generate-ini-mysql8
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./integrations.mysql8.test -test.run $(subst .,/,$*)
|
||||
|
||||
.PHONY: test-mysql8-migration
|
||||
test-mysql8-migration: migrations.mysql8.test migrations.individual.mysql8.test
|
||||
|
||||
generate-ini-pgsql:
|
||||
sed -e 's|{{TEST_PGSQL_HOST}}|${TEST_PGSQL_HOST}|g' \
|
||||
-e 's|{{TEST_PGSQL_DBNAME}}|${TEST_PGSQL_DBNAME}|g' \
|
||||
@ -643,14 +619,6 @@ test-e2e-mysql: playwright e2e.mysql.test generate-ini-mysql
|
||||
test-e2e-mysql\#%: playwright e2e.mysql.test generate-ini-mysql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test -test.run TestE2e/$*
|
||||
|
||||
.PHONY: test-e2e-mysql8
|
||||
test-e2e-mysql8: playwright e2e.mysql8.test generate-ini-mysql8
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./e2e.mysql8.test
|
||||
|
||||
.PHONY: test-e2e-mysql8\#%
|
||||
test-e2e-mysql8\#%: playwright e2e.mysql8.test generate-ini-mysql8
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./e2e.mysql8.test -test.run TestE2e/$*
|
||||
|
||||
.PHONY: test-e2e-pgsql
|
||||
test-e2e-pgsql: playwright e2e.pgsql.test generate-ini-pgsql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test
|
||||
@ -694,9 +662,6 @@ integration-test-coverage-sqlite: integrations.cover.sqlite.test generate-ini-sq
|
||||
integrations.mysql.test: git-check $(GO_SOURCES)
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql.test
|
||||
|
||||
integrations.mysql8.test: git-check $(GO_SOURCES)
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql8.test
|
||||
|
||||
integrations.pgsql.test: git-check $(GO_SOURCES)
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.pgsql.test
|
||||
|
||||
@ -717,11 +682,6 @@ migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql.test
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./migrations.mysql.test
|
||||
|
||||
.PHONY: migrations.mysql8.test
|
||||
migrations.mysql8.test: $(GO_SOURCES) generate-ini-mysql8
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql8.test
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./migrations.mysql8.test
|
||||
|
||||
.PHONY: migrations.pgsql.test
|
||||
migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test
|
||||
@ -743,13 +703,7 @@ migrations.individual.mysql.test: $(GO_SOURCES)
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \
|
||||
done
|
||||
|
||||
.PHONY: migrations.individual.mysql8.test
|
||||
migrations.individual.mysql8.test: $(GO_SOURCES)
|
||||
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \
|
||||
done
|
||||
|
||||
.PHONY: migrations.individual.mysql8.test\#%
|
||||
.PHONY: migrations.individual.sqlite.test\#%
|
||||
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||
|
||||
@ -787,9 +741,6 @@ migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
|
||||
e2e.mysql.test: $(GO_SOURCES)
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mysql.test
|
||||
|
||||
e2e.mysql8.test: $(GO_SOURCES)
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mysql8.test
|
||||
|
||||
e2e.pgsql.test: $(GO_SOURCES)
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.pgsql.test
|
||||
|
||||
@ -924,6 +875,9 @@ node_modules: package-lock.json
|
||||
poetry install
|
||||
@touch .venv
|
||||
|
||||
.PHONY: update
|
||||
update: update-js update-py
|
||||
|
||||
.PHONY: update-js
|
||||
update-js: node-check | node_modules
|
||||
npx updates -u -f package.json
|
||||
|
||||
619
cmd/admin.go
619
cmd/admin.go
@ -6,26 +6,13 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"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"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@ -59,28 +46,16 @@ var (
|
||||
},
|
||||
}
|
||||
|
||||
microcmdRegenHooks = &cli.Command{
|
||||
Name: "hooks",
|
||||
Usage: "Regenerate git-hooks",
|
||||
Action: runRegenerateHooks,
|
||||
}
|
||||
|
||||
microcmdRegenKeys = &cli.Command{
|
||||
Name: "keys",
|
||||
Usage: "Regenerate authorized_keys file",
|
||||
Action: runRegenerateKeys,
|
||||
}
|
||||
|
||||
subcmdAuth = &cli.Command{
|
||||
Name: "auth",
|
||||
Usage: "Modify external auth providers",
|
||||
Subcommands: []*cli.Command{
|
||||
microcmdAuthAddOauth,
|
||||
microcmdAuthUpdateOauth,
|
||||
cmdAuthAddLdapBindDn,
|
||||
cmdAuthUpdateLdapBindDn,
|
||||
cmdAuthAddLdapSimpleAuth,
|
||||
cmdAuthUpdateLdapSimpleAuth,
|
||||
microcmdAuthAddLdapBindDn,
|
||||
microcmdAuthUpdateLdapBindDn,
|
||||
microcmdAuthAddLdapSimpleAuth,
|
||||
microcmdAuthUpdateLdapSimpleAuth,
|
||||
microcmdAuthAddSMTP,
|
||||
microcmdAuthUpdateSMTP,
|
||||
microcmdAuthList,
|
||||
@ -88,170 +63,6 @@ var (
|
||||
},
|
||||
}
|
||||
|
||||
microcmdAuthList = &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List auth sources",
|
||||
Action: runListAuth,
|
||||
Flags: []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "min-width",
|
||||
Usage: "Minimal cell width including any padding for the formatted table",
|
||||
Value: 0,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "tab-width",
|
||||
Usage: "width of tab characters in formatted table (equivalent number of spaces)",
|
||||
Value: 8,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "padding",
|
||||
Usage: "padding added to a cell before computing its width",
|
||||
Value: 1,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "pad-char",
|
||||
Usage: `ASCII char used for padding if padchar == '\\t', the Writer will assume that the width of a '\\t' in the formatted output is tabwidth, and cells are left-aligned independent of align_left (for correct-looking results, tabwidth must correspond to the tab width in the viewer displaying the result)`,
|
||||
Value: "\t",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "vertical-bars",
|
||||
Usage: "Set to true to print vertical bars between columns",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
idFlag = &cli.Int64Flag{
|
||||
Name: "id",
|
||||
Usage: "ID of authentication source",
|
||||
}
|
||||
|
||||
microcmdAuthDelete = &cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "Delete specific auth source",
|
||||
Flags: []cli.Flag{idFlag},
|
||||
Action: runDeleteAuth,
|
||||
}
|
||||
|
||||
oauthCLIFlags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Usage: "Application Name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "provider",
|
||||
Value: "",
|
||||
Usage: "OAuth2 Provider",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "key",
|
||||
Value: "",
|
||||
Usage: "Client ID (Key)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "secret",
|
||||
Value: "",
|
||||
Usage: "Client Secret",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auto-discover-url",
|
||||
Value: "",
|
||||
Usage: "OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "use-custom-urls",
|
||||
Value: "false",
|
||||
Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-tenant-id",
|
||||
Value: "",
|
||||
Usage: "Use custom Tenant ID for OAuth endpoints",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-auth-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Authorization URL (option for GitLab/GitHub)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-token-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Token URL (option for GitLab/GitHub)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-profile-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Profile URL (option for GitLab/GitHub)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-email-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Email URL (option for GitHub)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "icon-url",
|
||||
Value: "",
|
||||
Usage: "Custom icon URL for OAuth2 login source",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skip-local-2fa",
|
||||
Usage: "Set to true to skip local 2fa for users authenticated by this source",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "scopes",
|
||||
Value: nil,
|
||||
Usage: "Scopes to request when to authenticate against this OAuth2 source",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "required-claim-name",
|
||||
Value: "",
|
||||
Usage: "Claim name that has to be set to allow users to login with this source",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "required-claim-value",
|
||||
Value: "",
|
||||
Usage: "Claim value that has to be set to allow users to login with this source",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "group-claim-name",
|
||||
Value: "",
|
||||
Usage: "Claim name providing group names for this source",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "admin-group",
|
||||
Value: "",
|
||||
Usage: "Group Claim value for administrator users",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "restricted-group",
|
||||
Value: "",
|
||||
Usage: "Group Claim value for restricted users",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "group-team-map",
|
||||
Value: "",
|
||||
Usage: "JSON mapping between groups and org teams",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "group-team-map-removal",
|
||||
Usage: "Activate automatic team membership removal depending on groups",
|
||||
},
|
||||
}
|
||||
|
||||
microcmdAuthUpdateOauth = &cli.Command{
|
||||
Name: "update-oauth",
|
||||
Usage: "Update existing Oauth authentication source",
|
||||
Action: runUpdateOauth,
|
||||
Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...),
|
||||
}
|
||||
|
||||
microcmdAuthAddOauth = &cli.Command{
|
||||
Name: "add-oauth",
|
||||
Usage: "Add new Oauth authentication source",
|
||||
Action: runAddOauth,
|
||||
Flags: oauthCLIFlags,
|
||||
}
|
||||
|
||||
subcmdSendMail = &cli.Command{
|
||||
Name: "sendmail",
|
||||
Usage: "Send a message to all users",
|
||||
@ -275,75 +86,9 @@ var (
|
||||
},
|
||||
}
|
||||
|
||||
smtpCLIFlags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Usage: "Application Name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth-type",
|
||||
Value: "PLAIN",
|
||||
Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "host",
|
||||
Value: "",
|
||||
Usage: "SMTP Host",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "port",
|
||||
Usage: "SMTP Port",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "force-smtps",
|
||||
Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.",
|
||||
Value: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skip-verify",
|
||||
Usage: "Skip TLS verify.",
|
||||
Value: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "helo-hostname",
|
||||
Value: "",
|
||||
Usage: "Hostname sent with HELO. Leave blank to send current hostname",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "disable-helo",
|
||||
Usage: "Disable SMTP helo.",
|
||||
Value: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "allowed-domains",
|
||||
Value: "",
|
||||
Usage: "Leave empty to allow all domains. Separate multiple domains with a comma (',')",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skip-local-2fa",
|
||||
Usage: "Skip 2FA to log on.",
|
||||
Value: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "active",
|
||||
Usage: "This Authentication Source is Activated.",
|
||||
Value: true,
|
||||
},
|
||||
}
|
||||
|
||||
microcmdAuthAddSMTP = &cli.Command{
|
||||
Name: "add-smtp",
|
||||
Usage: "Add new SMTP authentication source",
|
||||
Action: runAddSMTP,
|
||||
Flags: smtpCLIFlags,
|
||||
}
|
||||
|
||||
microcmdAuthUpdateSMTP = &cli.Command{
|
||||
Name: "update-smtp",
|
||||
Usage: "Update existing SMTP authentication source",
|
||||
Action: runUpdateSMTP,
|
||||
Flags: append(smtpCLIFlags[:1], append([]cli.Flag{idFlag}, smtpCLIFlags[1:]...)...),
|
||||
idFlag = &cli.Int64Flag{
|
||||
Name: "id",
|
||||
Usage: "ID of authentication source",
|
||||
}
|
||||
)
|
||||
|
||||
@ -389,7 +134,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
|
||||
}
|
||||
log.Trace(" currentNumReleases is %d, running SyncReleasesWithTags", oldnum)
|
||||
|
||||
if err = repo_module.SyncReleasesWithTags(repo, gitRepo); err != nil {
|
||||
if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil {
|
||||
log.Warn(" SyncReleasesWithTags: %v", err)
|
||||
gitRepo.Close()
|
||||
continue
|
||||
@ -420,351 +165,3 @@ func getReleaseCount(ctx context.Context, id int64) (int64, error) {
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func runRegenerateHooks(_ *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
|
||||
}
|
||||
|
||||
func runRegenerateKeys(_ *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return asymkey_model.RewriteAllPublicKeys()
|
||||
}
|
||||
|
||||
func parseOAuth2Config(c *cli.Context) *oauth2.Source {
|
||||
var customURLMapping *oauth2.CustomURLMapping
|
||||
if c.IsSet("use-custom-urls") {
|
||||
customURLMapping = &oauth2.CustomURLMapping{
|
||||
TokenURL: c.String("custom-token-url"),
|
||||
AuthURL: c.String("custom-auth-url"),
|
||||
ProfileURL: c.String("custom-profile-url"),
|
||||
EmailURL: c.String("custom-email-url"),
|
||||
Tenant: c.String("custom-tenant-id"),
|
||||
}
|
||||
} else {
|
||||
customURLMapping = nil
|
||||
}
|
||||
return &oauth2.Source{
|
||||
Provider: c.String("provider"),
|
||||
ClientID: c.String("key"),
|
||||
ClientSecret: c.String("secret"),
|
||||
OpenIDConnectAutoDiscoveryURL: c.String("auto-discover-url"),
|
||||
CustomURLMapping: customURLMapping,
|
||||
IconURL: c.String("icon-url"),
|
||||
SkipLocalTwoFA: c.Bool("skip-local-2fa"),
|
||||
Scopes: c.StringSlice("scopes"),
|
||||
RequiredClaimName: c.String("required-claim-name"),
|
||||
RequiredClaimValue: c.String("required-claim-value"),
|
||||
GroupClaimName: c.String("group-claim-name"),
|
||||
AdminGroup: c.String("admin-group"),
|
||||
RestrictedGroup: c.String("restricted-group"),
|
||||
GroupTeamMap: c.String("group-team-map"),
|
||||
GroupTeamMapRemoval: c.Bool("group-team-map-removal"),
|
||||
}
|
||||
}
|
||||
|
||||
func runAddOauth(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config := parseOAuth2Config(c)
|
||||
if config.Provider == "openidConnect" {
|
||||
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
|
||||
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
|
||||
return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL)
|
||||
}
|
||||
}
|
||||
|
||||
return auth_model.CreateSource(&auth_model.Source{
|
||||
Type: auth_model.OAuth2,
|
||||
Name: c.String("name"),
|
||||
IsActive: true,
|
||||
Cfg: config,
|
||||
})
|
||||
}
|
||||
|
||||
func runUpdateOauth(c *cli.Context) error {
|
||||
if !c.IsSet("id") {
|
||||
return fmt.Errorf("--id flag is missing")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := auth_model.GetSourceByID(c.Int64("id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oAuth2Config := source.Cfg.(*oauth2.Source)
|
||||
|
||||
if c.IsSet("name") {
|
||||
source.Name = c.String("name")
|
||||
}
|
||||
|
||||
if c.IsSet("provider") {
|
||||
oAuth2Config.Provider = c.String("provider")
|
||||
}
|
||||
|
||||
if c.IsSet("key") {
|
||||
oAuth2Config.ClientID = c.String("key")
|
||||
}
|
||||
|
||||
if c.IsSet("secret") {
|
||||
oAuth2Config.ClientSecret = c.String("secret")
|
||||
}
|
||||
|
||||
if c.IsSet("auto-discover-url") {
|
||||
oAuth2Config.OpenIDConnectAutoDiscoveryURL = c.String("auto-discover-url")
|
||||
}
|
||||
|
||||
if c.IsSet("icon-url") {
|
||||
oAuth2Config.IconURL = c.String("icon-url")
|
||||
}
|
||||
|
||||
if c.IsSet("scopes") {
|
||||
oAuth2Config.Scopes = c.StringSlice("scopes")
|
||||
}
|
||||
|
||||
if c.IsSet("required-claim-name") {
|
||||
oAuth2Config.RequiredClaimName = c.String("required-claim-name")
|
||||
}
|
||||
if c.IsSet("required-claim-value") {
|
||||
oAuth2Config.RequiredClaimValue = c.String("required-claim-value")
|
||||
}
|
||||
|
||||
if c.IsSet("group-claim-name") {
|
||||
oAuth2Config.GroupClaimName = c.String("group-claim-name")
|
||||
}
|
||||
if c.IsSet("admin-group") {
|
||||
oAuth2Config.AdminGroup = c.String("admin-group")
|
||||
}
|
||||
if c.IsSet("restricted-group") {
|
||||
oAuth2Config.RestrictedGroup = c.String("restricted-group")
|
||||
}
|
||||
if c.IsSet("group-team-map") {
|
||||
oAuth2Config.GroupTeamMap = c.String("group-team-map")
|
||||
}
|
||||
if c.IsSet("group-team-map-removal") {
|
||||
oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal")
|
||||
}
|
||||
|
||||
// update custom URL mapping
|
||||
customURLMapping := &oauth2.CustomURLMapping{}
|
||||
|
||||
if oAuth2Config.CustomURLMapping != nil {
|
||||
customURLMapping.TokenURL = oAuth2Config.CustomURLMapping.TokenURL
|
||||
customURLMapping.AuthURL = oAuth2Config.CustomURLMapping.AuthURL
|
||||
customURLMapping.ProfileURL = oAuth2Config.CustomURLMapping.ProfileURL
|
||||
customURLMapping.EmailURL = oAuth2Config.CustomURLMapping.EmailURL
|
||||
customURLMapping.Tenant = oAuth2Config.CustomURLMapping.Tenant
|
||||
}
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-token-url") {
|
||||
customURLMapping.TokenURL = c.String("custom-token-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-auth-url") {
|
||||
customURLMapping.AuthURL = c.String("custom-auth-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-profile-url") {
|
||||
customURLMapping.ProfileURL = c.String("custom-profile-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-email-url") {
|
||||
customURLMapping.EmailURL = c.String("custom-email-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-tenant-id") {
|
||||
customURLMapping.Tenant = c.String("custom-tenant-id")
|
||||
}
|
||||
|
||||
oAuth2Config.CustomURLMapping = customURLMapping
|
||||
source.Cfg = oAuth2Config
|
||||
|
||||
return auth_model.UpdateSource(source)
|
||||
}
|
||||
|
||||
func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
|
||||
if c.IsSet("auth-type") {
|
||||
conf.Auth = c.String("auth-type")
|
||||
validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"}
|
||||
if !util.SliceContainsString(validAuthTypes, strings.ToUpper(c.String("auth-type"))) {
|
||||
return errors.New("Auth must be one of PLAIN/LOGIN/CRAM-MD5")
|
||||
}
|
||||
conf.Auth = c.String("auth-type")
|
||||
}
|
||||
if c.IsSet("host") {
|
||||
conf.Host = c.String("host")
|
||||
}
|
||||
if c.IsSet("port") {
|
||||
conf.Port = c.Int("port")
|
||||
}
|
||||
if c.IsSet("allowed-domains") {
|
||||
conf.AllowedDomains = c.String("allowed-domains")
|
||||
}
|
||||
if c.IsSet("force-smtps") {
|
||||
conf.ForceSMTPS = c.Bool("force-smtps")
|
||||
}
|
||||
if c.IsSet("skip-verify") {
|
||||
conf.SkipVerify = c.Bool("skip-verify")
|
||||
}
|
||||
if c.IsSet("helo-hostname") {
|
||||
conf.HeloHostname = c.String("helo-hostname")
|
||||
}
|
||||
if c.IsSet("disable-helo") {
|
||||
conf.DisableHelo = c.Bool("disable-helo")
|
||||
}
|
||||
if c.IsSet("skip-local-2fa") {
|
||||
conf.SkipLocalTwoFA = c.Bool("skip-local-2fa")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runAddSMTP(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !c.IsSet("name") || len(c.String("name")) == 0 {
|
||||
return errors.New("name must be set")
|
||||
}
|
||||
if !c.IsSet("host") || len(c.String("host")) == 0 {
|
||||
return errors.New("host must be set")
|
||||
}
|
||||
if !c.IsSet("port") {
|
||||
return errors.New("port must be set")
|
||||
}
|
||||
active := true
|
||||
if c.IsSet("active") {
|
||||
active = c.Bool("active")
|
||||
}
|
||||
|
||||
var smtpConfig smtp.Source
|
||||
if err := parseSMTPConfig(c, &smtpConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If not set default to PLAIN
|
||||
if len(smtpConfig.Auth) == 0 {
|
||||
smtpConfig.Auth = "PLAIN"
|
||||
}
|
||||
|
||||
return auth_model.CreateSource(&auth_model.Source{
|
||||
Type: auth_model.SMTP,
|
||||
Name: c.String("name"),
|
||||
IsActive: active,
|
||||
Cfg: &smtpConfig,
|
||||
})
|
||||
}
|
||||
|
||||
func runUpdateSMTP(c *cli.Context) error {
|
||||
if !c.IsSet("id") {
|
||||
return fmt.Errorf("--id flag is missing")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := auth_model.GetSourceByID(c.Int64("id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
smtpConfig := source.Cfg.(*smtp.Source)
|
||||
|
||||
if err := parseSMTPConfig(c, smtpConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.IsSet("name") {
|
||||
source.Name = c.String("name")
|
||||
}
|
||||
|
||||
if c.IsSet("active") {
|
||||
source.IsActive = c.Bool("active")
|
||||
}
|
||||
|
||||
source.Cfg = smtpConfig
|
||||
|
||||
return auth_model.UpdateSource(source)
|
||||
}
|
||||
|
||||
func runListAuth(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authSources, err := auth_model.Sources()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
flags := tabwriter.AlignRight
|
||||
if c.Bool("vertical-bars") {
|
||||
flags |= tabwriter.Debug
|
||||
}
|
||||
|
||||
padChar := byte('\t')
|
||||
if len(c.String("pad-char")) > 0 {
|
||||
padChar = c.String("pad-char")[0]
|
||||
}
|
||||
|
||||
// loop through each source and print
|
||||
w := tabwriter.NewWriter(os.Stdout, c.Int("min-width"), c.Int("tab-width"), c.Int("padding"), padChar, flags)
|
||||
fmt.Fprintf(w, "ID\tName\tType\tEnabled\n")
|
||||
for _, source := range authSources {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", source.ID, source.Name, source.Type.String(), source.IsActive)
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runDeleteAuth(c *cli.Context) error {
|
||||
if !c.IsSet("id") {
|
||||
return fmt.Errorf("--id flag is missing")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := auth_model.GetSourceByID(c.Int64("id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return auth_service.DeleteSource(source)
|
||||
}
|
||||
|
||||
109
cmd/admin_auth.go
Normal file
109
cmd/admin_auth.go
Normal file
@ -0,0 +1,109 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
auth_service "code.gitea.io/gitea/services/auth"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
microcmdAuthDelete = &cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "Delete specific auth source",
|
||||
Flags: []cli.Flag{idFlag},
|
||||
Action: runDeleteAuth,
|
||||
}
|
||||
microcmdAuthList = &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List auth sources",
|
||||
Action: runListAuth,
|
||||
Flags: []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "min-width",
|
||||
Usage: "Minimal cell width including any padding for the formatted table",
|
||||
Value: 0,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "tab-width",
|
||||
Usage: "width of tab characters in formatted table (equivalent number of spaces)",
|
||||
Value: 8,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "padding",
|
||||
Usage: "padding added to a cell before computing its width",
|
||||
Value: 1,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "pad-char",
|
||||
Usage: `ASCII char used for padding if padchar == '\\t', the Writer will assume that the width of a '\\t' in the formatted output is tabwidth, and cells are left-aligned independent of align_left (for correct-looking results, tabwidth must correspond to the tab width in the viewer displaying the result)`,
|
||||
Value: "\t",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "vertical-bars",
|
||||
Usage: "Set to true to print vertical bars between columns",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func runListAuth(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authSources, err := auth_model.Sources()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
flags := tabwriter.AlignRight
|
||||
if c.Bool("vertical-bars") {
|
||||
flags |= tabwriter.Debug
|
||||
}
|
||||
|
||||
padChar := byte('\t')
|
||||
if len(c.String("pad-char")) > 0 {
|
||||
padChar = c.String("pad-char")[0]
|
||||
}
|
||||
|
||||
// loop through each source and print
|
||||
w := tabwriter.NewWriter(os.Stdout, c.Int("min-width"), c.Int("tab-width"), c.Int("padding"), padChar, flags)
|
||||
fmt.Fprintf(w, "ID\tName\tType\tEnabled\n")
|
||||
for _, source := range authSources {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", source.ID, source.Name, source.Type.String(), source.IsActive)
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runDeleteAuth(c *cli.Context) error {
|
||||
if !c.IsSet("id") {
|
||||
return fmt.Errorf("--id flag is missing")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := auth_model.GetSourceByID(c.Int64("id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return auth_service.DeleteSource(source)
|
||||
}
|
||||
@ -132,10 +132,10 @@ var (
|
||||
ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags,
|
||||
&cli.StringFlag{
|
||||
Name: "user-dn",
|
||||
Usage: "The user’s DN.",
|
||||
Usage: "The user's DN.",
|
||||
})
|
||||
|
||||
cmdAuthAddLdapBindDn = &cli.Command{
|
||||
microcmdAuthAddLdapBindDn = &cli.Command{
|
||||
Name: "add-ldap",
|
||||
Usage: "Add new LDAP (via Bind DN) authentication source",
|
||||
Action: func(c *cli.Context) error {
|
||||
@ -144,7 +144,7 @@ var (
|
||||
Flags: ldapBindDnCLIFlags,
|
||||
}
|
||||
|
||||
cmdAuthUpdateLdapBindDn = &cli.Command{
|
||||
microcmdAuthUpdateLdapBindDn = &cli.Command{
|
||||
Name: "update-ldap",
|
||||
Usage: "Update existing LDAP (via Bind DN) authentication source",
|
||||
Action: func(c *cli.Context) error {
|
||||
@ -153,7 +153,7 @@ var (
|
||||
Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...),
|
||||
}
|
||||
|
||||
cmdAuthAddLdapSimpleAuth = &cli.Command{
|
||||
microcmdAuthAddLdapSimpleAuth = &cli.Command{
|
||||
Name: "add-ldap-simple",
|
||||
Usage: "Add new LDAP (simple auth) authentication source",
|
||||
Action: func(c *cli.Context) error {
|
||||
@ -162,7 +162,7 @@ var (
|
||||
Flags: ldapSimpleAuthCLIFlags,
|
||||
}
|
||||
|
||||
cmdAuthUpdateLdapSimpleAuth = &cli.Command{
|
||||
microcmdAuthUpdateLdapSimpleAuth = &cli.Command{
|
||||
Name: "update-ldap-simple",
|
||||
Usage: "Update existing LDAP (simple auth) authentication source",
|
||||
Action: func(c *cli.Context) error {
|
||||
|
||||
@ -226,7 +226,7 @@ func TestAddLdapBindDn(t *testing.T) {
|
||||
|
||||
// Create a copy of command to test
|
||||
app := cli.NewApp()
|
||||
app.Flags = cmdAuthAddLdapBindDn.Flags
|
||||
app.Flags = microcmdAuthAddLdapBindDn.Flags
|
||||
app.Action = service.addLdapBindDn
|
||||
|
||||
// Run it
|
||||
@ -457,7 +457,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
||||
|
||||
// Create a copy of command to test
|
||||
app := cli.NewApp()
|
||||
app.Flags = cmdAuthAddLdapSimpleAuth.Flags
|
||||
app.Flags = microcmdAuthAddLdapSimpleAuth.Flags
|
||||
app.Action = service.addLdapSimpleAuth
|
||||
|
||||
// Run it
|
||||
@ -920,7 +920,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
||||
|
||||
// Create a copy of command to test
|
||||
app := cli.NewApp()
|
||||
app.Flags = cmdAuthUpdateLdapBindDn.Flags
|
||||
app.Flags = microcmdAuthUpdateLdapBindDn.Flags
|
||||
app.Action = service.updateLdapBindDn
|
||||
|
||||
// Run it
|
||||
@ -1310,7 +1310,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
||||
|
||||
// Create a copy of command to test
|
||||
app := cli.NewApp()
|
||||
app.Flags = cmdAuthUpdateLdapSimpleAuth.Flags
|
||||
app.Flags = microcmdAuthUpdateLdapSimpleAuth.Flags
|
||||
app.Action = service.updateLdapSimpleAuth
|
||||
|
||||
// Run it
|
||||
|
||||
298
cmd/admin_auth_oauth.go
Normal file
298
cmd/admin_auth_oauth.go
Normal file
@ -0,0 +1,298 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/services/auth/source/oauth2"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
oauthCLIFlags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Usage: "Application Name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "provider",
|
||||
Value: "",
|
||||
Usage: "OAuth2 Provider",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "key",
|
||||
Value: "",
|
||||
Usage: "Client ID (Key)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "secret",
|
||||
Value: "",
|
||||
Usage: "Client Secret",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auto-discover-url",
|
||||
Value: "",
|
||||
Usage: "OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "use-custom-urls",
|
||||
Value: "false",
|
||||
Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-tenant-id",
|
||||
Value: "",
|
||||
Usage: "Use custom Tenant ID for OAuth endpoints",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-auth-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Authorization URL (option for GitLab/GitHub)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-token-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Token URL (option for GitLab/GitHub)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-profile-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Profile URL (option for GitLab/GitHub)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-email-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Email URL (option for GitHub)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "icon-url",
|
||||
Value: "",
|
||||
Usage: "Custom icon URL for OAuth2 login source",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skip-local-2fa",
|
||||
Usage: "Set to true to skip local 2fa for users authenticated by this source",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "scopes",
|
||||
Value: nil,
|
||||
Usage: "Scopes to request when to authenticate against this OAuth2 source",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "required-claim-name",
|
||||
Value: "",
|
||||
Usage: "Claim name that has to be set to allow users to login with this source",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "required-claim-value",
|
||||
Value: "",
|
||||
Usage: "Claim value that has to be set to allow users to login with this source",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "group-claim-name",
|
||||
Value: "",
|
||||
Usage: "Claim name providing group names for this source",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "admin-group",
|
||||
Value: "",
|
||||
Usage: "Group Claim value for administrator users",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "restricted-group",
|
||||
Value: "",
|
||||
Usage: "Group Claim value for restricted users",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "group-team-map",
|
||||
Value: "",
|
||||
Usage: "JSON mapping between groups and org teams",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "group-team-map-removal",
|
||||
Usage: "Activate automatic team membership removal depending on groups",
|
||||
},
|
||||
}
|
||||
|
||||
microcmdAuthAddOauth = &cli.Command{
|
||||
Name: "add-oauth",
|
||||
Usage: "Add new Oauth authentication source",
|
||||
Action: runAddOauth,
|
||||
Flags: oauthCLIFlags,
|
||||
}
|
||||
|
||||
microcmdAuthUpdateOauth = &cli.Command{
|
||||
Name: "update-oauth",
|
||||
Usage: "Update existing Oauth authentication source",
|
||||
Action: runUpdateOauth,
|
||||
Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...),
|
||||
}
|
||||
)
|
||||
|
||||
func parseOAuth2Config(c *cli.Context) *oauth2.Source {
|
||||
var customURLMapping *oauth2.CustomURLMapping
|
||||
if c.IsSet("use-custom-urls") {
|
||||
customURLMapping = &oauth2.CustomURLMapping{
|
||||
TokenURL: c.String("custom-token-url"),
|
||||
AuthURL: c.String("custom-auth-url"),
|
||||
ProfileURL: c.String("custom-profile-url"),
|
||||
EmailURL: c.String("custom-email-url"),
|
||||
Tenant: c.String("custom-tenant-id"),
|
||||
}
|
||||
} else {
|
||||
customURLMapping = nil
|
||||
}
|
||||
return &oauth2.Source{
|
||||
Provider: c.String("provider"),
|
||||
ClientID: c.String("key"),
|
||||
ClientSecret: c.String("secret"),
|
||||
OpenIDConnectAutoDiscoveryURL: c.String("auto-discover-url"),
|
||||
CustomURLMapping: customURLMapping,
|
||||
IconURL: c.String("icon-url"),
|
||||
SkipLocalTwoFA: c.Bool("skip-local-2fa"),
|
||||
Scopes: c.StringSlice("scopes"),
|
||||
RequiredClaimName: c.String("required-claim-name"),
|
||||
RequiredClaimValue: c.String("required-claim-value"),
|
||||
GroupClaimName: c.String("group-claim-name"),
|
||||
AdminGroup: c.String("admin-group"),
|
||||
RestrictedGroup: c.String("restricted-group"),
|
||||
GroupTeamMap: c.String("group-team-map"),
|
||||
GroupTeamMapRemoval: c.Bool("group-team-map-removal"),
|
||||
}
|
||||
}
|
||||
|
||||
func runAddOauth(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config := parseOAuth2Config(c)
|
||||
if config.Provider == "openidConnect" {
|
||||
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
|
||||
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
|
||||
return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL)
|
||||
}
|
||||
}
|
||||
|
||||
return auth_model.CreateSource(&auth_model.Source{
|
||||
Type: auth_model.OAuth2,
|
||||
Name: c.String("name"),
|
||||
IsActive: true,
|
||||
Cfg: config,
|
||||
})
|
||||
}
|
||||
|
||||
func runUpdateOauth(c *cli.Context) error {
|
||||
if !c.IsSet("id") {
|
||||
return fmt.Errorf("--id flag is missing")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := auth_model.GetSourceByID(c.Int64("id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oAuth2Config := source.Cfg.(*oauth2.Source)
|
||||
|
||||
if c.IsSet("name") {
|
||||
source.Name = c.String("name")
|
||||
}
|
||||
|
||||
if c.IsSet("provider") {
|
||||
oAuth2Config.Provider = c.String("provider")
|
||||
}
|
||||
|
||||
if c.IsSet("key") {
|
||||
oAuth2Config.ClientID = c.String("key")
|
||||
}
|
||||
|
||||
if c.IsSet("secret") {
|
||||
oAuth2Config.ClientSecret = c.String("secret")
|
||||
}
|
||||
|
||||
if c.IsSet("auto-discover-url") {
|
||||
oAuth2Config.OpenIDConnectAutoDiscoveryURL = c.String("auto-discover-url")
|
||||
}
|
||||
|
||||
if c.IsSet("icon-url") {
|
||||
oAuth2Config.IconURL = c.String("icon-url")
|
||||
}
|
||||
|
||||
if c.IsSet("scopes") {
|
||||
oAuth2Config.Scopes = c.StringSlice("scopes")
|
||||
}
|
||||
|
||||
if c.IsSet("required-claim-name") {
|
||||
oAuth2Config.RequiredClaimName = c.String("required-claim-name")
|
||||
}
|
||||
if c.IsSet("required-claim-value") {
|
||||
oAuth2Config.RequiredClaimValue = c.String("required-claim-value")
|
||||
}
|
||||
|
||||
if c.IsSet("group-claim-name") {
|
||||
oAuth2Config.GroupClaimName = c.String("group-claim-name")
|
||||
}
|
||||
if c.IsSet("admin-group") {
|
||||
oAuth2Config.AdminGroup = c.String("admin-group")
|
||||
}
|
||||
if c.IsSet("restricted-group") {
|
||||
oAuth2Config.RestrictedGroup = c.String("restricted-group")
|
||||
}
|
||||
if c.IsSet("group-team-map") {
|
||||
oAuth2Config.GroupTeamMap = c.String("group-team-map")
|
||||
}
|
||||
if c.IsSet("group-team-map-removal") {
|
||||
oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal")
|
||||
}
|
||||
|
||||
// update custom URL mapping
|
||||
customURLMapping := &oauth2.CustomURLMapping{}
|
||||
|
||||
if oAuth2Config.CustomURLMapping != nil {
|
||||
customURLMapping.TokenURL = oAuth2Config.CustomURLMapping.TokenURL
|
||||
customURLMapping.AuthURL = oAuth2Config.CustomURLMapping.AuthURL
|
||||
customURLMapping.ProfileURL = oAuth2Config.CustomURLMapping.ProfileURL
|
||||
customURLMapping.EmailURL = oAuth2Config.CustomURLMapping.EmailURL
|
||||
customURLMapping.Tenant = oAuth2Config.CustomURLMapping.Tenant
|
||||
}
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-token-url") {
|
||||
customURLMapping.TokenURL = c.String("custom-token-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-auth-url") {
|
||||
customURLMapping.AuthURL = c.String("custom-auth-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-profile-url") {
|
||||
customURLMapping.ProfileURL = c.String("custom-profile-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-email-url") {
|
||||
customURLMapping.EmailURL = c.String("custom-email-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-tenant-id") {
|
||||
customURLMapping.Tenant = c.String("custom-tenant-id")
|
||||
}
|
||||
|
||||
oAuth2Config.CustomURLMapping = customURLMapping
|
||||
source.Cfg = oAuth2Config
|
||||
|
||||
return auth_model.UpdateSource(source)
|
||||
}
|
||||
201
cmd/admin_auth_stmp.go
Normal file
201
cmd/admin_auth_stmp.go
Normal file
@ -0,0 +1,201 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/auth/source/smtp"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
smtpCLIFlags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Usage: "Application Name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth-type",
|
||||
Value: "PLAIN",
|
||||
Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "host",
|
||||
Value: "",
|
||||
Usage: "SMTP Host",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "port",
|
||||
Usage: "SMTP Port",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "force-smtps",
|
||||
Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.",
|
||||
Value: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skip-verify",
|
||||
Usage: "Skip TLS verify.",
|
||||
Value: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "helo-hostname",
|
||||
Value: "",
|
||||
Usage: "Hostname sent with HELO. Leave blank to send current hostname",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "disable-helo",
|
||||
Usage: "Disable SMTP helo.",
|
||||
Value: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "allowed-domains",
|
||||
Value: "",
|
||||
Usage: "Leave empty to allow all domains. Separate multiple domains with a comma (',')",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skip-local-2fa",
|
||||
Usage: "Skip 2FA to log on.",
|
||||
Value: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "active",
|
||||
Usage: "This Authentication Source is Activated.",
|
||||
Value: true,
|
||||
},
|
||||
}
|
||||
|
||||
microcmdAuthAddSMTP = &cli.Command{
|
||||
Name: "add-smtp",
|
||||
Usage: "Add new SMTP authentication source",
|
||||
Action: runAddSMTP,
|
||||
Flags: smtpCLIFlags,
|
||||
}
|
||||
|
||||
microcmdAuthUpdateSMTP = &cli.Command{
|
||||
Name: "update-smtp",
|
||||
Usage: "Update existing SMTP authentication source",
|
||||
Action: runUpdateSMTP,
|
||||
Flags: append(smtpCLIFlags[:1], append([]cli.Flag{idFlag}, smtpCLIFlags[1:]...)...),
|
||||
}
|
||||
)
|
||||
|
||||
func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
|
||||
if c.IsSet("auth-type") {
|
||||
conf.Auth = c.String("auth-type")
|
||||
validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"}
|
||||
if !util.SliceContainsString(validAuthTypes, strings.ToUpper(c.String("auth-type"))) {
|
||||
return errors.New("Auth must be one of PLAIN/LOGIN/CRAM-MD5")
|
||||
}
|
||||
conf.Auth = c.String("auth-type")
|
||||
}
|
||||
if c.IsSet("host") {
|
||||
conf.Host = c.String("host")
|
||||
}
|
||||
if c.IsSet("port") {
|
||||
conf.Port = c.Int("port")
|
||||
}
|
||||
if c.IsSet("allowed-domains") {
|
||||
conf.AllowedDomains = c.String("allowed-domains")
|
||||
}
|
||||
if c.IsSet("force-smtps") {
|
||||
conf.ForceSMTPS = c.Bool("force-smtps")
|
||||
}
|
||||
if c.IsSet("skip-verify") {
|
||||
conf.SkipVerify = c.Bool("skip-verify")
|
||||
}
|
||||
if c.IsSet("helo-hostname") {
|
||||
conf.HeloHostname = c.String("helo-hostname")
|
||||
}
|
||||
if c.IsSet("disable-helo") {
|
||||
conf.DisableHelo = c.Bool("disable-helo")
|
||||
}
|
||||
if c.IsSet("skip-local-2fa") {
|
||||
conf.SkipLocalTwoFA = c.Bool("skip-local-2fa")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runAddSMTP(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !c.IsSet("name") || len(c.String("name")) == 0 {
|
||||
return errors.New("name must be set")
|
||||
}
|
||||
if !c.IsSet("host") || len(c.String("host")) == 0 {
|
||||
return errors.New("host must be set")
|
||||
}
|
||||
if !c.IsSet("port") {
|
||||
return errors.New("port must be set")
|
||||
}
|
||||
active := true
|
||||
if c.IsSet("active") {
|
||||
active = c.Bool("active")
|
||||
}
|
||||
|
||||
var smtpConfig smtp.Source
|
||||
if err := parseSMTPConfig(c, &smtpConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If not set default to PLAIN
|
||||
if len(smtpConfig.Auth) == 0 {
|
||||
smtpConfig.Auth = "PLAIN"
|
||||
}
|
||||
|
||||
return auth_model.CreateSource(&auth_model.Source{
|
||||
Type: auth_model.SMTP,
|
||||
Name: c.String("name"),
|
||||
IsActive: active,
|
||||
Cfg: &smtpConfig,
|
||||
})
|
||||
}
|
||||
|
||||
func runUpdateSMTP(c *cli.Context) error {
|
||||
if !c.IsSet("id") {
|
||||
return fmt.Errorf("--id flag is missing")
|
||||
}
|
||||
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := auth_model.GetSourceByID(c.Int64("id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
smtpConfig := source.Cfg.(*smtp.Source)
|
||||
|
||||
if err := parseSMTPConfig(c, smtpConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.IsSet("name") {
|
||||
source.Name = c.String("name")
|
||||
}
|
||||
|
||||
if c.IsSet("active") {
|
||||
source.IsActive = c.Bool("active")
|
||||
}
|
||||
|
||||
source.Cfg = smtpConfig
|
||||
|
||||
return auth_model.UpdateSource(source)
|
||||
}
|
||||
46
cmd/admin_regenerate.go
Normal file
46
cmd/admin_regenerate.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
microcmdRegenHooks = &cli.Command{
|
||||
Name: "hooks",
|
||||
Usage: "Regenerate git-hooks",
|
||||
Action: runRegenerateHooks,
|
||||
}
|
||||
|
||||
microcmdRegenKeys = &cli.Command{
|
||||
Name: "keys",
|
||||
Usage: "Regenerate authorized_keys file",
|
||||
Action: runRegenerateKeys,
|
||||
}
|
||||
)
|
||||
|
||||
func runRegenerateHooks(_ *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
|
||||
}
|
||||
|
||||
func runRegenerateKeys(_ *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return asymkey_model.RewriteAllPublicKeys(ctx)
|
||||
}
|
||||
@ -115,7 +115,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(nil); n == 0 {
|
||||
if n := user_model.CountUsers(ctx, nil); n == 0 {
|
||||
changePassword = false
|
||||
}
|
||||
|
||||
@ -146,7 +146,7 @@ func runCreateUser(c *cli.Context) error {
|
||||
IsRestricted: restricted,
|
||||
}
|
||||
|
||||
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
|
||||
if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil {
|
||||
return fmt.Errorf("CreateUser: %w", err)
|
||||
}
|
||||
|
||||
@ -156,7 +156,7 @@ func runCreateUser(c *cli.Context) error {
|
||||
UID: u.ID,
|
||||
}
|
||||
|
||||
if err := auth_model.NewAccessToken(t); err != nil {
|
||||
if err := auth_model.NewAccessToken(ctx, t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -63,7 +63,7 @@ func runGenerateAccessToken(c *cli.Context) error {
|
||||
UID: user.ID,
|
||||
}
|
||||
|
||||
exist, err := auth_model.AccessTokenByNameExists(t)
|
||||
exist, err := auth_model.AccessTokenByNameExists(ctx, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -79,7 +79,7 @@ func runGenerateAccessToken(c *cli.Context) error {
|
||||
t.Scope = accessTokenScope
|
||||
|
||||
// create the token
|
||||
if err := auth_model.NewAccessToken(t); err != nil {
|
||||
if err := auth_model.NewAccessToken(ctx, t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ func runListUsers(c *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
users, err := user_model.GetAllUsers()
|
||||
users, err := user_model.GetAllUsers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -48,7 +48,7 @@ func runListUsers(c *cli.Context) error {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
twofa := user_model.UserList(users).GetTwoFaStatus()
|
||||
twofa := user_model.UserList(users).GetTwoFaStatus(ctx)
|
||||
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n")
|
||||
for _, u := range users {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID])
|
||||
|
||||
@ -20,9 +20,7 @@ import (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: "..",
|
||||
})
|
||||
unittest.MainTest(m)
|
||||
}
|
||||
|
||||
func makePathOutput(workPath, customPath, customConf string) string {
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"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"
|
||||
@ -30,7 +31,7 @@ func TestMigratePackages(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
defer buf.Close()
|
||||
|
||||
v, f, err := packages_service.CreatePackageAndAddFile(&packages_service.PackageCreationInfo{
|
||||
v, f, err := packages_service.CreatePackageAndAddFile(db.DefaultContext, &packages_service.PackageCreationInfo{
|
||||
PackageInfo: packages_service.PackageInfo{
|
||||
Owner: creator,
|
||||
PackageType: packages.TypeGeneric,
|
||||
|
||||
@ -2571,12 +2571,18 @@ LEVEL = Info
|
||||
|
||||
; [actions]
|
||||
;; Enable/Disable actions capabilities
|
||||
;ENABLED = false
|
||||
;ENABLED = true
|
||||
;;
|
||||
;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
||||
;DEFAULT_ACTIONS_URL = github
|
||||
;; Default artifact retention time in days, default is 90 days
|
||||
;ARTIFACT_RETENTION_DAYS = 90
|
||||
;; Timeout to stop the task which have running status, but haven't been updated for a long time
|
||||
;ZOMBIE_TASK_TIMEOUT = 10m
|
||||
;; Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time
|
||||
;ENDLESS_TASK_TIMEOUT = 3h
|
||||
;; Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time
|
||||
;ABANDONED_JOB_TIMEOUT = 24h
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@ -1387,11 +1387,14 @@ PROXY_HOSTS = *.github.com
|
||||
|
||||
## Actions (`actions`)
|
||||
|
||||
- `ENABLED`: **false**: Enable/Disable actions capabilities
|
||||
- `ENABLED`: **true**: Enable/Disable actions capabilities
|
||||
- `DEFAULT_ACTIONS_URL`: **github**: Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
||||
- `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
|
||||
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
|
||||
- `ARTIFACT_RETENTION_DAYS`: **90**: Number of days to keep artifacts. Set to 0 to disable artifact retention. Default is 90 days if not set.
|
||||
- `ZOMBIE_TASK_TIMEOUT`: **10m**: Timeout to stop the task which have running status, but haven't been updated for a long time
|
||||
- `ENDLESS_TASK_TIMEOUT`: **3h**: Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time
|
||||
- `ABANDONED_JOB_TIMEOUT`: **24h**: Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time
|
||||
|
||||
`DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path.
|
||||
For example, `uses: actions/checkout@v3` means `https://github.com/actions/checkout@v3` since the value of `DEFAULT_ACTIONS_URL` is `github`.
|
||||
|
||||
@ -1331,7 +1331,7 @@ PROXY_HOSTS = *.github.com
|
||||
|
||||
## Actions (`actions`)
|
||||
|
||||
- `ENABLED`: **false**:启用/禁用操作功能
|
||||
- `ENABLED`: **true**:启用/禁用操作功能
|
||||
- `DEFAULT_ACTIONS_URL`: **github**:获取操作插件的默认平台,`github`表示`https://github.com`,`self`表示当前的 Gitea 实例。
|
||||
- `STORAGE_TYPE`: **local**:用于操作日志的存储类型,`local`表示本地磁盘,`minio`表示与S3兼容的对象存储服务,默认为`local`,或者使用定义为`[storage.xxx]`的其他名称。
|
||||
- `MINIO_BASE_PATH`: **actions_log/**:Minio存储桶上的基本路径,仅在`STORAGE_TYPE`为`minio`时可用。
|
||||
|
||||
@ -95,7 +95,7 @@ Some lint rules and IDEs also have warnings if the returned Promise is not handl
|
||||
### Fetching data
|
||||
|
||||
To fetch data, use the wrapper functions `GET`, `POST` etc. from `modules/fetch.js`. They
|
||||
accept a `data` option for the content, will automatically set CSFR token and return a
|
||||
accept a `data` option for the content, will automatically set CSRF token and return a
|
||||
Promise for a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).
|
||||
|
||||
### HTML Attributes and `dataset`
|
||||
|
||||
@ -33,117 +33,117 @@ _Symbols used in table:_
|
||||
|
||||
## General Features
|
||||
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE |
|
||||
| ------------------------------------------------ | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ |
|
||||
| Open source and free | ✓ | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ |
|
||||
| Low RAM/ CPU usage | ✓ | ✓ | ✘ | ✘ | ✘ | ✘ | ✘ |
|
||||
| Multiple database support | ✓ | ✓ | ✘ | ⁄ | ⁄ | ✓ | ✓ |
|
||||
| Multiple OS support | ✓ | ✓ | ✘ | ✘ | ✘ | ✘ | ✓ |
|
||||
| Easy upgrades | ✓ | ✓ | ✘ | ✓ | ✓ | ✘ | ✓ |
|
||||
| Telemetry | **✘** | ✘ | ✓ | ✓ | ✓ | ✓ | ? |
|
||||
| Third-party render tool support | ✓ | ✘ | ✘ | ✘ | ✘ | ✓ | ? |
|
||||
| WebAuthn (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ? |
|
||||
| Extensive API | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Built-in Package/Container Registry | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Sync commits to an external repo (push mirror) | ✓ | ✓ | ✘ | ✓ | ✓ | ✘ | ✓ |
|
||||
| Sync commits from an external repo (pull mirror) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ? |
|
||||
| Light and Dark Theme | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ? |
|
||||
| Custom Theme Support | ✓ | ✓ | ✘ | ✘ | ✘ | ✓ | ✘ |
|
||||
| Markdown support | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| CSV support | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ? |
|
||||
| 'GitHub / GitLab pages' | [⚙️][gitea-pages-server], [⚙️][gitea-caddy-plugin] | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Repo-specific wiki (as a repo itself) | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ |
|
||||
| Deploy Tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Repository Tokens with write rights | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| RSS Feeds | ✓ | ✘ | ✓ | ✘ | ✘ | ✘ | ✘ |
|
||||
| Built-in CI/CD | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Subgroups: groups within groups | [✘](https://github.com/go-gitea/gitea/issues/1872) | ✘ | ✘ | ✓ | ✓ | ✘ | ✓ |
|
||||
| Interaction with other instances | [/](https://github.com/go-gitea/gitea/issues/18240) | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
|
||||
| Mermaid diagrams in Markdown | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Math syntax in Markdown | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | RhodeCode EE |
|
||||
| ------------------------------------------------ | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | ------------ |
|
||||
| Open source and free | ✓ | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ✓ |
|
||||
| Low RAM/ CPU usage | ✓ | ✓ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
|
||||
| Multiple database support | ✓ | ✓ | ✘ | ⁄ | ⁄ | ✓ | ✓ | ✓ |
|
||||
| Multiple OS support | ✓ | ✓ | ✘ | ✘ | ✘ | ✘ | ✓ | ✓ |
|
||||
| Easy upgrades | ✓ | ✓ | ✘ | ✓ | ✓ | ✘ | ✓ | ✓ |
|
||||
| Telemetry | **✘** | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Third-party render tool support | ✓ | ✘ | ✘ | ✘ | ✘ | ✓ | ✘ | ✘ |
|
||||
| WebAuthn (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✓ |
|
||||
| Extensive API | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Built-in Package/Container Registry | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Sync commits to an external repo (push mirror) | ✓ | ✓ | ✘ | ✓ | ✓ | ✘ | ✓ | ✓ |
|
||||
| Sync commits from an external repo (pull mirror) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✓ | ✓ |
|
||||
| Light and Dark Theme | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Custom Theme Support | ✓ | ✓ | ✘ | ✘ | ✘ | ✓ | ✓ | ✓ |
|
||||
| Markdown support | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| CSV support | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ✘ | ✘ |
|
||||
| 'GitHub / GitLab pages' | [⚙️][gitea-pages-server], [⚙️][gitea-caddy-plugin] | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Repo-specific wiki (as a repo itself) | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ | ✘ |
|
||||
| Deploy Tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Repository Tokens with write rights | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| RSS Feeds | ✓ | ✘ | ✓ | ✘ | ✘ | ✘ | ✓ | ✓ |
|
||||
| Built-in CI/CD | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Subgroups: groups within groups | [✘](https://github.com/go-gitea/gitea/issues/1872) | ✘ | ✘ | ✓ | ✓ | ✘ | ✓ | ✓ |
|
||||
| Interaction with other instances | [/](https://github.com/go-gitea/gitea/issues/18240) | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
|
||||
| Mermaid diagrams in Markdown | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Math syntax in Markdown | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ | ✓ |
|
||||
|
||||
## Code management
|
||||
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE |
|
||||
| ------------------------------------------- | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ |
|
||||
| Repository topics | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Repository code search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Global code search | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ |
|
||||
| Git LFS 2.0 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Group Milestones | [✘](https://github.com/go-gitea/gitea/issues/14622) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Granular user roles (Code, Issues, Wiki, …) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Verified Committer | ⁄ | ✘ | ? | ✓ | ✓ | ✓ | ✘ |
|
||||
| GPG Signed Commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| SSH Signed Commits | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ? |
|
||||
| Reject unsigned commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Migrating repos from other services | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Repository Activity page | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Branch manager | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Create new branches | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Web code editor | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Commit graph | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Template Repositories | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✘ |
|
||||
| Git Blame | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Visual comparison of image changes | ✓ | ✘ | ✓ | ? | ? | ? | ? |
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | RhodeCode EE |
|
||||
| ------------------------------------------- | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | ------------ |
|
||||
| Repository topics | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Repository code search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Global code search | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Git LFS 2.0 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Group Milestones | [✘](https://github.com/go-gitea/gitea/issues/14622) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Granular user roles (Code, Issues, Wiki, …) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Verified Committer | ⁄ | ✘ | ? | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| GPG Signed Commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| SSH Signed Commits | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ✘ | ✘ |
|
||||
| Reject unsigned commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Migrating repos from other services | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Repository Activity page | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Branch manager | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Create new branches | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Web code editor | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Commit graph | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Template Repositories | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Git Blame | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Visual comparison of image changes | ✓ | ✘ | ✓ | ? | ? | ? | ✘ | ✘ |
|
||||
|
||||
## Issue Tracker
|
||||
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE |
|
||||
| ----------------------------- | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ |
|
||||
| Issue tracker | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ |
|
||||
| Issue templates | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Labels | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Time tracking | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Multiple assignees for issues | ✓ | ✘ | ✓ | ✘ | ✓ | ✘ | ✘ |
|
||||
| Related issues | ✘ | ✘ | ⁄ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Confidential issues | [✘](https://github.com/go-gitea/gitea/issues/3217) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Comment reactions | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Lock Discussion | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Batch issue handling | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Issue Boards (Kanban) | [/](https://github.com/go-gitea/gitea/issues/14710) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Create branch from issue | [✘](https://github.com/go-gitea/gitea/issues/20226) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Convert comment to new issue | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Issue search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Global issue search | [/](https://github.com/go-gitea/gitea/issues/2434) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Issue dependency | ✓ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
|
||||
| Create issue via email | [✘](https://github.com/go-gitea/gitea/issues/6226) | ✘ | ✘ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Service Desk | [✘](https://github.com/go-gitea/gitea/issues/6219) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | RhodeCode EE |
|
||||
| ----------------------------- | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | ------------ |
|
||||
| Issue tracker | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ | ✘ |
|
||||
| Issue templates | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Labels | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Time tracking | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Multiple assignees for issues | ✓ | ✘ | ✓ | ✘ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Related issues | ✘ | ✘ | ⁄ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Confidential issues | [✘](https://github.com/go-gitea/gitea/issues/3217) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Comment reactions | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Lock Discussion | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Batch issue handling | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Issue Boards (Kanban) | [/](https://github.com/go-gitea/gitea/issues/14710) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Create branch from issue | [✘](https://github.com/go-gitea/gitea/issues/20226) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Convert comment to new issue | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Issue search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Global issue search | [/](https://github.com/go-gitea/gitea/issues/2434) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Issue dependency | ✓ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
|
||||
| Create issue via email | [✘](https://github.com/go-gitea/gitea/issues/6226) | ✘ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Service Desk | [✘](https://github.com/go-gitea/gitea/issues/6219) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
|
||||
## Pull/Merge requests
|
||||
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE |
|
||||
| ----------------------------------------------- | -------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ |
|
||||
| Pull/Merge requests | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Squash merging | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Rebase merging | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge request inline comments | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge request approval | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge require approval | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge multiple reviewers | ✓ | ✓ | ✓ | ✘ | ✓ | ✓ | ✓ |
|
||||
| Merge conflict resolution | [✘](https://github.com/go-gitea/gitea/issues/9014) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Restrict push and merge access to certain users | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Revert specific commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Pull/Merge requests templates | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Cherry-picking changes | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Download Patch | ✓ | ✘ | ✓ | ✓ | ✓ | / | ✘ |
|
||||
| Merge queues | ✘ | ✘ | ✓ | ✘ | ✓ | ✘ | ✘ |
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | RhodeCode EE |
|
||||
| ----------------------------------------------- | -------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | ------------ |
|
||||
| Pull/Merge requests | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Squash merging | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Rebase merging | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge request inline comments | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge request approval | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge require approval | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge multiple reviewers | ✓ | ✓ | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Merge conflict resolution | [✘](https://github.com/go-gitea/gitea/issues/9014) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Restrict push and merge access to certain users | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Revert specific commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Pull/Merge requests templates | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||
| Cherry-picking changes | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✓ |
|
||||
| Download Patch | ✓ | ✘ | ✓ | ✓ | ✓ | / | ✓ | ✓ |
|
||||
| Merge queues | ✘ | ✘ | ✓ | ✘ | ✓ | ✘ | ✘ | ✘ |
|
||||
|
||||
## 3rd-party integrations
|
||||
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE |
|
||||
| ---------------------------------------------- | ------------------------------------------------ | ---- | --------- | --------- | --------- | --------- | ------------ |
|
||||
| Webhooks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Git Hooks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| AD / LDAP integration | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Multiple LDAP / AD server support | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ |
|
||||
| LDAP user synchronization | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| SAML 2.0 service provider | [✘](https://github.com/go-gitea/gitea/issues/5512) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| OpenID Connect support | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ✘ |
|
||||
| OAuth 2.0 integration (external authorization) | ✓ | ✘ | ⁄ | ✓ | ✓ | ? | ✓ |
|
||||
| Act as OAuth 2.0 provider | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Two factor authentication (2FA) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Integration with the most common services | ✓ | / | ⁄ | ✓ | ✓ | ⁄ | ✓ |
|
||||
| Incorporate external CI/CD | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | RhodeCode EE |
|
||||
| ---------------------------------------------- | ------------------------------------------------ | ---- | --------- | --------- | --------- | --------- | ------------ | ------------ |
|
||||
| Webhooks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Git Hooks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| AD / LDAP integration | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Multiple LDAP / AD server support | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ |
|
||||
| LDAP user synchronization | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✓ |
|
||||
| SAML 2.0 service provider | [✘](https://github.com/go-gitea/gitea/issues/5512) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✓ |
|
||||
| OpenID Connect support | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ✘ | ✓ |
|
||||
| OAuth 2.0 integration (external authorization) | ✓ | ✘ | ⁄ | ✓ | ✓ | ? | ✘ | ✓ |
|
||||
| Act as OAuth 2.0 provider | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Two factor authentication (2FA) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✓ |
|
||||
| Integration with the most common services | ✓ | / | ⁄ | ✓ | ✓ | ⁄ | ✓ | ✓ |
|
||||
| Incorporate external CI/CD | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
|
||||
[gitea-caddy-plugin]: https://github.com/42wim/caddy-gitea
|
||||
[gitea-pages-server]: https://codeberg.org/Codeberg/pages-server
|
||||
|
||||
@ -17,13 +17,15 @@ menu:
|
||||
|
||||
# Database Preparation
|
||||
|
||||
You need a database to use Gitea. Gitea supports PostgreSQL (>=10), MySQL (>=5.7), SQLite, and MSSQL (>=2008R2 SP3). This page will guide into preparing database. Only PostgreSQL and MySQL will be covered here since those database engines are widely-used in production. If you plan to use SQLite, you can ignore this chapter.
|
||||
You need a database to use Gitea. Gitea supports PostgreSQL (>= 12), MySQL (>= 8.0), MariaDB, SQLite, and MSSQL (>= 2012 SP4). This page will guide into preparing database. Only PostgreSQL and MySQL will be covered here since those database engines are widely-used in production. If you plan to use SQLite, you can ignore this chapter.
|
||||
|
||||
If you use an unsupported database version, please [get in touch](/help/support) with us for information on our Extended Support Contracts. We can provide testing and support for older databases and integrate those fixes into the Gitea codebase.
|
||||
|
||||
Database instance can be on same machine as Gitea (local database setup), or on different machine (remote database).
|
||||
|
||||
Note: All steps below requires that the database engine of your choice is installed on your system. For remote database setup, install the server application on database instance and client program on your Gitea server. The client program is used to test connection to the database from Gitea server, while Gitea itself use database driver provided by Go to accomplish the same thing. In addition, make sure you use same engine version for both server and client for some engine features to work. For security reason, protect `root` (MySQL) or `postgres` (PostgreSQL) database superuser with secure password. The steps assumes that you run Linux for both database and Gitea servers.
|
||||
|
||||
## MySQL
|
||||
## MySQL/MariaDB
|
||||
|
||||
1. For remote database setup, you will need to make MySQL listen to your IP address. Edit `bind-address` option on `/etc/mysql/my.cnf` on database instance to:
|
||||
|
||||
@ -45,7 +47,7 @@ Note: All steps below requires that the database engine of your choice is instal
|
||||
|
||||
```sql
|
||||
SET old_passwords=0;
|
||||
CREATE USER 'gitea' IDENTIFIED BY 'gitea';
|
||||
CREATE USER 'gitea'@'%' IDENTIFIED BY 'gitea';
|
||||
```
|
||||
|
||||
For remote database:
|
||||
|
||||
@ -17,7 +17,7 @@ menu:
|
||||
|
||||
# 数据库准备
|
||||
|
||||
在使用 Gitea 前,您需要准备一个数据库。Gitea 支持 PostgreSQL(>=10)、MySQL(>=5.7)、SQLite 和 MSSQL(>=2008R2 SP3)这几种数据库。本页将指导您准备数据库。由于 PostgreSQL 和 MySQL 在生产环境中被广泛使用,因此本文档将仅涵盖这两种数据库。如果您计划使用 SQLite,则可以忽略本章内容。
|
||||
在使用 Gitea 前,您需要准备一个数据库。Gitea 支持 PostgreSQL(>= 12)、MySQL(>= 8.0)、SQLite 和 MSSQL(>= 2012 SP4)这几种数据库。本页将指导您准备数据库。由于 PostgreSQL 和 MySQL 在生产环境中被广泛使用,因此本文档将仅涵盖这两种数据库。如果您计划使用 SQLite,则可以忽略本章内容。
|
||||
|
||||
数据库实例可以与 Gitea 实例在相同机器上(本地数据库),也可以与 Gitea 实例在不同机器上(远程数据库)。
|
||||
|
||||
|
||||
@ -24,7 +24,6 @@ Following the [deployment from binary](installation/from-binary.md) guide may wo
|
||||
but is not supported. To install Gitea via `brew`:
|
||||
|
||||
```
|
||||
brew tap gitea/tap https://gitea.com/gitea/homebrew-gitea
|
||||
brew install gitea
|
||||
```
|
||||
|
||||
|
||||
@ -30,7 +30,6 @@ Nous n'avons pas encore publié de paquet pour Windows, nous allons mettre à jo
|
||||
Actuellement, nous ne supportons que l'installation via `brew` pour macOS. Si vous n'utilisez pas [Homebrew](http://brew.sh/), vous pouvez suivre les [instructions d'installation](installation/from-binary.md) avec le binaire pré-compilé. Pour installer Gitea depuis `brew`, utilisez les commandes suivantes :
|
||||
|
||||
```
|
||||
brew tap go-gitea/gitea
|
||||
brew install gitea
|
||||
```
|
||||
|
||||
|
||||
@ -22,7 +22,6 @@ menu:
|
||||
macOS 平台下当前我们仅支持通过 `brew` 来安装。如果你没有安装 [Homebrew](http://brew.sh/),你也可以查看 [从二进制安装](installation/from-binary.md)。在你安装了 `brew` 之后, 你可以执行以下命令:
|
||||
|
||||
```
|
||||
brew tap gitea/tap https://gitea.com/gitea/homebrew-gitea
|
||||
brew install gitea
|
||||
```
|
||||
|
||||
|
||||
@ -36,7 +36,6 @@ choco install gitea
|
||||
目前我們只支援透過 `brew` 來安裝套件。假如您尚未使用 [Homebrew](http://brew.sh/),您就必須參考[執行檔安裝](installation/from-binary.md)方式。透過 `brew` 安裝 Gitea,您只需要執行底下指令:
|
||||
|
||||
```
|
||||
brew tap go-gitea/gitea
|
||||
brew install gitea
|
||||
```
|
||||
|
||||
|
||||
@ -128,8 +128,6 @@ If pre-built frontend files are present it is possible to only build the backend
|
||||
TAGS="bindata" make backend
|
||||
```
|
||||
|
||||
Webpack source maps are by default enabled in development builds and disabled in production builds. They can be enabled by setting the `ENABLE_SOURCEMAP=true` environment variable.
|
||||
|
||||
## Test
|
||||
|
||||
After following the steps above, a `gitea` binary will be available in the working directory.
|
||||
@ -260,3 +258,11 @@ GOARCH=amd64 \
|
||||
TAGS="bindata sqlite sqlite_unlock_notify" \
|
||||
make build
|
||||
```
|
||||
|
||||
## Source Maps
|
||||
|
||||
By default, gitea generates reduced source maps for frontend files to conserve space. This can be controlled with the `ENABLE_SOURCEMAP` environment variable:
|
||||
|
||||
- `ENABLE_SOURCEMAP=true` generates all source maps, the default for development builds
|
||||
- `ENABLE_SOURCEMAP=reduced` generates limited source maps, the default for production builds
|
||||
- `ENABLE_SOURCEMAP=false` generates no source maps
|
||||
|
||||
@ -100,8 +100,6 @@ TAGS="bindata sqlite sqlite_unlock_notify" make build
|
||||
TAGS="bindata" make backend
|
||||
```
|
||||
|
||||
在开发构建中,默认启用 Webpack 源映射,在生产构建中禁用。可以通过设置`ENABLE_SOURCEMAP=true`环境变量来启用它们。
|
||||
|
||||
## 测试
|
||||
|
||||
按照上述步骤完成后,工作目录中将会有一个`gitea`二进制文件。可以从该目录进行测试,或将其移动到带有测试数据的目录中。当手动从命令行启动 Gitea 时,可以通过按下`Ctrl + C`来停止程序。
|
||||
@ -221,3 +219,11 @@ GOARCH=amd64 \
|
||||
TAGS="bindata sqlite sqlite_unlock_notify" \
|
||||
make build
|
||||
```
|
||||
|
||||
## Source Map
|
||||
|
||||
默认情况下,gitea 会为前端文件生成精简的 Source Map 以节省空间。 这可以通过“ENABLE_SOURCEMAP”环境变量进行控制:
|
||||
|
||||
- `ENABLE_SOURCEMAP=true` 生成所有Source Map,这是开发版本的默认设置
|
||||
- `ENABLE_SOURCEMAP=reduced` 生成有限的Source Map,这是生产版本的默认设置
|
||||
- `ENABLE_SOURCEMAP=false` 不生成Source Map
|
||||
|
||||
@ -1,112 +0,0 @@
|
||||
---
|
||||
date: "2016-12-01T16:00:00+02:00"
|
||||
title: "Upgrade from Gogs"
|
||||
slug: "upgrade-from-gogs"
|
||||
sidebar_position: 101
|
||||
toc: false
|
||||
draft: false
|
||||
aliases:
|
||||
- /en-us/upgrade-from-gogs
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "installation"
|
||||
name: "Upgrade From Gogs"
|
||||
sidebar_position: 101
|
||||
identifier: "upgrade-from-gogs"
|
||||
---
|
||||
|
||||
# Upgrade from Gogs
|
||||
|
||||
Gogs, version 0.9.146 and older, can be easily migrated to Gitea.
|
||||
|
||||
There are some basic steps to follow. On a Linux system run as the Gogs user:
|
||||
|
||||
* Create a Gogs backup with `gogs backup`. This creates `gogs-backup-[timestamp].zip` file
|
||||
containing all important Gogs data. You would need it if you wanted to move to the `gogs` back later.
|
||||
* Download the file matching the destination platform from the [downloads page](https://dl.gitea.com/gitea/).
|
||||
It should be `1.0.x` version. Migrating from `gogs` to any other version is impossible.
|
||||
* Put the binary at the desired install location.
|
||||
* Copy `gogs/custom/conf/app.ini` to `gitea/custom/conf/app.ini`.
|
||||
* Copy custom `templates, public` from `gogs/custom/` to `gitea/custom/`.
|
||||
* For any other custom folders, such as `gitignore, label, license, locale, readme` in
|
||||
`gogs/custom/conf`, copy them to `gitea/custom/options`.
|
||||
* Copy `gogs/data/` to `gitea/data/`. It contains issue attachments and avatars.
|
||||
* Verify by starting Gitea with `gitea web`.
|
||||
* Enter Gitea admin panel on the UI, run `Rewrite '.ssh/authorized_keys' file`.
|
||||
* Launch every major version of the binary ( `1.1.4` → `1.2.3` → `1.3.4` → `1.4.2` → etc ) to migrate database.
|
||||
* If custom or config path was changed, run `Rewrite all update hook of repositories`.
|
||||
|
||||
## Change gogs specific information
|
||||
|
||||
* Rename `gogs-repositories/` to `gitea-repositories/`
|
||||
* Rename `gogs-data/` to `gitea-data/`
|
||||
* In `gitea/custom/conf/app.ini` change:
|
||||
|
||||
FROM:
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gogs/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gogs-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gogs/log
|
||||
```
|
||||
|
||||
TO:
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gitea/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gitea-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gitea/log
|
||||
```
|
||||
|
||||
* Verify by starting Gitea with `gitea web`
|
||||
|
||||
## Upgrading to most recent `gitea` version
|
||||
|
||||
After successful migration from `gogs` to `gitea 1.0.x`, it is possible to upgrade `gitea` to a modern version
|
||||
in a two steps process.
|
||||
|
||||
Upgrade to [`gitea 1.6.4`](https://dl.gitea.com/gitea/1.6.4/) first. Download the file matching
|
||||
the destination platform from the [downloads page](https://dl.gitea.com/gitea/1.6.4/) and replace the binary.
|
||||
Run Gitea at least once and check that everything works as expected.
|
||||
|
||||
Then repeat the procedure, but this time using the [latest release](https://dl.gitea.com/gitea/@version@/).
|
||||
|
||||
## Upgrading from a more recent version of Gogs
|
||||
|
||||
Upgrading from a more recent version of Gogs (up to `0.11.x`) may also be possible, but will require a bit more work.
|
||||
See [#4286](https://github.com/go-gitea/gitea/issues/4286), which includes various Gogs `0.11.x` versions.
|
||||
|
||||
Upgrading from Gogs `0.12.x` and above will be increasingly more difficult as the projects diverge further apart in configuration and schema.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* If errors are encountered relating to custom templates in the `gitea/custom/templates`
|
||||
folder, try moving the templates causing the errors away one by one. They may not be
|
||||
compatible with Gitea or an update.
|
||||
|
||||
## Add Gitea to startup on Unix
|
||||
|
||||
Update the appropriate file from [gitea/contrib](https://github.com/go-gitea/gitea/tree/main/contrib)
|
||||
with the right environment variables.
|
||||
|
||||
For distros with systemd:
|
||||
|
||||
* Copy the updated script to `/etc/systemd/system/gitea.service`
|
||||
* Add the service to the startup with: `sudo systemctl enable gitea`
|
||||
* Disable old gogs startup script: `sudo systemctl disable gogs`
|
||||
|
||||
For distros with SysVinit:
|
||||
|
||||
* Copy the updated script to `/etc/init.d/gitea`
|
||||
* Add the service to the startup with: `sudo rc-update add gitea`
|
||||
* Disable old gogs startup script: `sudo rc-update del gogs`
|
||||
@ -1,85 +0,0 @@
|
||||
---
|
||||
date: "2017-08-23T09:00:00+02:00"
|
||||
title: "Mise à jour depuis Gogs"
|
||||
slug: "upgrade-from-gogs"
|
||||
sidebar_position: 101
|
||||
toc: false
|
||||
draft: false
|
||||
aliases:
|
||||
- /fr-fr/upgrade-from-gogs
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "installation"
|
||||
name: "Depuis Gogs"
|
||||
sidebar_position: 101
|
||||
identifier: "upgrade-from-gogs"
|
||||
---
|
||||
|
||||
# Mise à jour depuis Gogs
|
||||
|
||||
À partir de la version 0.9.146 (schéma de la base de données : version 15) de Gogs, Il est possible de migrer vers Gitea simplement et sans encombre.
|
||||
|
||||
Veuillez suivre les étapes ci-dessous. Sur Unix, toute les commandes s'exécutent en tant que l'utilisateur utilisé pour votre installation de Gogs :
|
||||
|
||||
* Crééer une sauvegarde de Gogs avec la commande `gogs dump`. Le fichier nouvellement créé `gogs-dump-[timestamp].zip` contient toutes les données de votre instance de Gogs.
|
||||
* Téléchargez le fichier correspondant à votre plateforme à partir de la [page de téléchargements](https://dl.gitea.com/gitea).
|
||||
* Mettez la binaire dans le répertoire d'installation souhaité.
|
||||
* Copiez le fichier `gogs/custom/conf/app.ini` vers `gitea/custom/conf/app.ini`.
|
||||
* Si vous avez personnalisé les répertoires `templates, public` dans `gogs/custom/`, copiez-les vers `gitea/custom/`.
|
||||
* Si vous avez d'autres répertoires personnalisés comme `gitignore, label, license, locale, readme` dans `gogs/custom/conf` copiez-les vers `gitea/custom/options`.
|
||||
* Copiez le répertoire `gogs/data/` vers `gitea/data/`.
|
||||
* Vérifiez votre installation en exécutant Gitea avec la commande `gitea web`.
|
||||
* Lancez le binaire de version majeure en version majeure ( `1.1.4` → `1.2.3` → `1.3.4` → `1.4.2` → etc ) afin de récupérer les migrations de base de données.
|
||||
* Connectez vous au panel d'administration de Gitea et exécutez l'action `Rewrite '.ssh/authorized_keys' file`, puis l'action `Rewrite all update hook of repositories` (obligatoire si le chemin menant à votre configuration personnalisée à changé).
|
||||
|
||||
## Modifier les informations spécifiques de gogs
|
||||
|
||||
* Renommez `gogs-repositories/` vers `gitea-repositories/`
|
||||
* Renommez `gogs-data/` to `gitea-data/`
|
||||
* Dans votre fichier `gitea/custom/conf/app.ini`, modifiez les éléments suivants:
|
||||
|
||||
DE :
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gogs/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gogs-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gogs/log
|
||||
```
|
||||
|
||||
VERS :
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gitea/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gitea-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gitea/log
|
||||
```
|
||||
|
||||
* Vérifiez votre installation en exécutant Gitea avec la commande `gitea web`.
|
||||
|
||||
## Dépannage
|
||||
|
||||
* Si vous rencontrez des erreurs relatives à des modèles personnalisés dans le dossier `gitea/custom/templates`, essayez de déplacer un par un les modèles provoquant les erreurs. Il est possible qu'ils ne soient pas compatibles avec Gitea.
|
||||
|
||||
## Démarrer automatiquement Gitea (Unix)
|
||||
|
||||
Distributions utilisant systemd:
|
||||
|
||||
* Copiez le script mis à jour vers `/etc/systemd/system/gitea.service`
|
||||
* Ajoutez le service avec la commande `sudo systemctl enable gitea`
|
||||
* Désactivez Gogs avec la commande `sudo systemctl disable gogs`
|
||||
|
||||
Distributions utilisant SysVinit:
|
||||
|
||||
* Copiez le script mis à jour vers `/etc/init.d/gitea`
|
||||
* Ajoutez le service avec la commande `sudo rc-update add gitea`
|
||||
* Désactivez Gogs avec la commande `sudo rc-update del gogs`
|
||||
@ -1,101 +0,0 @@
|
||||
---
|
||||
date: "2016-12-01T16:00:00+02:00"
|
||||
title: "从 Gogs 升级"
|
||||
slug: "upgrade-from-gogs"
|
||||
sidebar_position: 101
|
||||
toc: false
|
||||
draft: false
|
||||
aliases:
|
||||
- /zh-cn/upgrade-from-gogs
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "installation"
|
||||
name: "从 Gogs 升级"
|
||||
sidebar_position: 101
|
||||
identifier: "upgrade-from-gogs"
|
||||
---
|
||||
|
||||
# 从 Gogs 升级
|
||||
|
||||
如果你正在运行Gogs 0.9.146以下版本,你可以平滑的升级到Gitea。该升级需要如下的步骤:
|
||||
|
||||
* 使用 `gogs backup` 创建 Gogs 备份。这会创建一个名为 `gogs-backup-[时间戳].zip` 的文件,其中包含所有重要的 Gogs 数据。如果您将来想要返回到 `gogs`,您会需要这个备份文件。
|
||||
* 从 [下载页面](https://dl.gitea.com/gitea/) 下载适用于目标平台的文件。应该选择 `1.0.x` 版本。从 `gogs` 迁移到其他任何版本是不可能的。
|
||||
* 将二进制文件放置在所需的安装位置。
|
||||
* 将 `gogs/custom/conf/app.ini` 复制到 `gitea/custom/conf/app.ini`。
|
||||
* 将 `gogs/custom/` 中的自定义 `templates, public` 复制到 `gitea/custom/`。
|
||||
* 对于其他自定义文件夹,例如 `gogs/custom/conf` 中的 `gitignore, label, license, locale, readme`,将它们复制到 `gitea/custom/options`。
|
||||
* 将 `gogs/data/` 复制到 `gitea/data/`。其中包含问题附件和头像。
|
||||
* 使用 `gitea web` 启动 Gitea 进行验证。
|
||||
* 在 UI 上进入 Gitea 管理面板,运行 `Rewrite '.ssh/authorized_keys' file`。
|
||||
* 启动每个主要版本的二进制文件(例如 `1.1.4` → `1.2.3` → `1.3.4` → `1.4.2` → 等)以迁移数据库。
|
||||
* 如果自定义或配置路径已更改,请运行 `Rewrite all update hook of repositories`。
|
||||
|
||||
## 更改特定于 Gogs 的信息
|
||||
|
||||
* 将 `gogs-repositories/` 重命名为 `gitea-repositories/`
|
||||
* 将 `gogs-data/` 重命名为 `gitea-data/`
|
||||
* 在 `gitea/custom/conf/app.ini` 中进行更改:
|
||||
从:
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gogs/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gogs-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gogs/log
|
||||
```
|
||||
|
||||
到:
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gitea/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gitea-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gitea/log
|
||||
```
|
||||
|
||||
* 使用 `gitea web` 启动 Gitea 进行验证
|
||||
|
||||
## 升级到最新版本的 `gitea`
|
||||
|
||||
在成功从 `gogs` 迁移到 `gitea 1.0.x` 之后,可以通过两步过程将 `gitea` 升级到现代版本。
|
||||
|
||||
首先升级到 [`gitea 1.6.4`](https://dl.gitea.com/gitea/1.6.4/)。从 [下载页面](https://dl.gitea.com/gitea/1.6.4/) 下载适用于目标平台的文件,并替换二进制文件。至少运行一次 Gitea 并检查是否一切正常。
|
||||
|
||||
然后重复这个过程,但这次使用 [最新版本](https://dl.gitea.com/gitea/@version@/)。
|
||||
|
||||
## 从较新的 Gogs 版本升级
|
||||
|
||||
从较新的 Gogs 版本(最高到 `0.11.x`)可能也是可能的,但需要更多的工作。
|
||||
请参见 [#4286](https://github.com/go-gitea/gitea/issues/4286),其中包括各种 Gogs `0.11.x` 版本。
|
||||
|
||||
从 Gogs `0.12.x` 及更高版本升级将变得越来越困难,因为项目在配置和架构上逐渐分歧。
|
||||
|
||||
## 故障排除
|
||||
|
||||
* 如果在 `gitea/custom/templates` 文件夹中遇到与自定义模板相关的错误,请尝试逐个移除引发错误的模板。
|
||||
它们可能与 Gitea 或更新不兼容。
|
||||
|
||||
## 将 Gitea 添加到 Unix 的启动项
|
||||
|
||||
从 [gitea/contrib](https://github.com/go-gitea/gitea/tree/main/contrib) 更新适当的文件,确保正确的环境变量。
|
||||
|
||||
对于使用 systemd 的发行版:
|
||||
|
||||
* 将更新后的脚本复制到 `/etc/systemd/system/gitea.service`
|
||||
* 使用以下命令将服务添加到启动项:`sudo systemctl enable gitea`
|
||||
* 禁用旧的 gogs 启动脚本:`sudo systemctl disable gogs`
|
||||
|
||||
对于使用 SysVinit 的发行版:
|
||||
|
||||
* 将更新后的脚本复制到 `/etc/init.d/gitea`
|
||||
* 使用以下命令将服务添加到启动项:`sudo rc-update add gitea`
|
||||
* 禁用旧的 gogs 启动脚本:`sudo rc-update del gogs`
|
||||
@ -1,107 +0,0 @@
|
||||
---
|
||||
date: "2016-12-01T16:00:00+02:00"
|
||||
title: "從 Gogs 升級"
|
||||
slug: "upgrade-from-gogs"
|
||||
sidebar_position: 101
|
||||
toc: false
|
||||
draft: false
|
||||
aliases:
|
||||
- /zh-tw/upgrade-from-gogs
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "installation"
|
||||
name: "從 Gogs 升級"
|
||||
sidebar_position: 101
|
||||
identifier: "upgrade-from-gogs"
|
||||
---
|
||||
|
||||
# 從 Gogs 升級
|
||||
|
||||
**目錄**
|
||||
|
||||
若您正在執行 Gogs 0.9.146 以下版本,您可以很簡單地遷移到 Gitea。
|
||||
|
||||
請參考下列步驟。在 Linux 系統上請以 Gogs 的使用者身份執行:
|
||||
|
||||
- 使用 `gogs backup` 建立 Gogs 的備份。這會建立檔案 `gogs-backup-[timestamp].zip` 包含所有重要的 Gogs 資料。
|
||||
如果稍後您要恢復到 `gogs` 時會用到它。
|
||||
- 從[下載頁](https://dl.gitea.com/gitea/)下載對應您平臺的檔案。請下載 `1.0.x` 版,從 `gogs` 遷移到其它版本是不可行的。
|
||||
- 將二進位檔放到適當的安裝位置。
|
||||
- 複製 `gogs/custom/conf/app.ini` 到 `gitea/custom/conf/app.ini`。
|
||||
- 從 `gogs/custom/` 複製自訂 `templates, public` 到 `gitea/custom/`。
|
||||
- `gogs/custom/conf` 中的其它自訂資料夾如: `gitignore, label, license, locale, readme`,
|
||||
請複製到 `gitea/custom/options`。
|
||||
- 複製 `gogs/data/` 到 `gitea/data/`。它包含了問題附件和大頭貼。
|
||||
- 以指令 `gitea web` 啟動 Gitea 驗證上列設定是否正確。
|
||||
- 從網頁 UI 進入 Gitea 管理員面板, 執行 `Rewrite '.ssh/authorized_keys' file`。
|
||||
- 執行每個主要版本的二進位檔 ( `1.1.4` → `1.2.3` → `1.3.4` → `1.4.2` → 等等 ) 以遷移資料庫。
|
||||
- 如果變更了自訂檔、設定檔路徑,請執行 `Rewrite all update hook of repositories`。
|
||||
|
||||
## 修改指定的 gogs 資訊
|
||||
|
||||
- 重新命名 `gogs-repositories/` 為 `gitea-repositories/`
|
||||
- 重新命名 `gogs-data/` 為 `gitea-data/`
|
||||
- 在 `gitea/custom/conf/app.ini` 中修改:
|
||||
|
||||
修改前:
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gogs/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gogs-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gogs/log
|
||||
```
|
||||
|
||||
修改後:
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gitea/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gitea-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gitea/log
|
||||
```
|
||||
|
||||
- 執行 `gitea web` 啟動 Gitea 檢查是否正確執行
|
||||
|
||||
## 升級到最新版的 `gitea`
|
||||
|
||||
成功從 `gogs` 升級到 `gitea 1.0.x` 後再用 2 個步驟即可升級到最新版的 `gitea`。
|
||||
|
||||
請先升級到 [`gitea 1.6.4`](https://dl.gitea.com/gitea/1.6.4/),先從[下載頁](https://dl.gitea.com/gitea/1.6.4/)下載
|
||||
您平臺的二進位檔取代既有的。至少執行一次 Gitea 並確認一切符合預期。
|
||||
|
||||
接著重複上述步驟,但這次請使用[最新發行版本](https://dl.gitea.com/gitea/@version@/)。
|
||||
|
||||
## 從更新版本的 Gogs 升級
|
||||
|
||||
您也可以從更新版本的 Gogs 升級,但需要更多步驟。
|
||||
請參考 [#4286](https://github.com/go-gitea/gitea/issues/4286)。
|
||||
|
||||
## 疑難排解
|
||||
|
||||
- 如果錯誤和 `gitea/custom/templates` 中 的自訂樣板有關,請試著逐一移除它們。
|
||||
它們可能和 Gitea 或更新不相容。
|
||||
|
||||
## 在 Unix 啟動時執行 Gitea
|
||||
|
||||
從 [gitea/contrib](https://github.com/go-gitea/gitea/tree/master/contrib) 更新必要的檔案以取得正確的環境變數。
|
||||
|
||||
使用 systemd 的發行版:
|
||||
|
||||
- 複製新的腳本到 `/etc/systemd/system/gitea.service`
|
||||
- 啟動系統時執行服務: `sudo systemctl enable gitea`
|
||||
- 停用舊的 gogs 腳本: `sudo systemctl disable gogs`
|
||||
|
||||
使用 SysVinit 的發行版:
|
||||
|
||||
- 複製新的腳本到 `/etc/init.d/gitea`
|
||||
- 啟動系統時執行服務: `sudo rc-update add gitea`
|
||||
- 停用舊的 gogs 腳本: `sudo rc-update del gogs`
|
||||
@ -91,12 +91,6 @@ As a workaround, you can use [go-hashfiles](https://gitea.com/actions/go-hashfil
|
||||
|
||||
## Missing features
|
||||
|
||||
### Variables
|
||||
|
||||
See [Variables](https://docs.github.com/en/actions/learn-github-actions/variables).
|
||||
|
||||
It's under development.
|
||||
|
||||
### Problem Matchers
|
||||
|
||||
Problem Matchers are a way to scan the output of actions for a specified regex pattern and surface that information prominently in the UI.
|
||||
@ -120,15 +114,17 @@ Pre and Post steps don't have their own section in the job log user interface.
|
||||
|
||||
### Downloading actions
|
||||
|
||||
Gitea Actions doesn't download actions from GitHub by default.
|
||||
"By default" means that you don't specify the host in the `uses` field, like `uses: actions/checkout@v3`.
|
||||
As a contrast, `uses: https://github.com/actions/checkout@v3` has specified host.
|
||||
Previously (Pre 1.21.0), `[actions].DEFAULT_ACTIONS_URL` defaulted to `https://gitea.com`.
|
||||
We have since restricted this option to only allow two values (`github` and `self`).
|
||||
When set to `github`, the new default, Gitea will download non-fully-qualified actions from <https://github.com>.
|
||||
For example, if you use `uses: actions/checkout@v3`, it will download the checkout repository from <https://github.com/actions/checkout.git>.
|
||||
|
||||
The missing host will be filled with `https://gitea.com` if you don't configure it.
|
||||
That means `uses: actions/checkout@v3` will download the action from [gitea.com/actions/checkout](https://gitea.com/actions/checkout), instead of [github.com/actions/checkout](https://github.com/actions/checkout).
|
||||
If you want to download an action from another git hoster, you can use an absolute URL, e.g. `uses: https://gitea.com/actions/checkout@v3`.
|
||||
|
||||
As mentioned, it's configurable.
|
||||
If you want your runners to download actions from GitHub or your own Gitea instance by default, you can configure it by setting `[actions].DEFAULT_ACTIONS_URL`. See [Configuration Cheat Sheet](administration/config-cheat-sheet.md#actions-actions).
|
||||
If your Gitea instance is in an intranet or a restricted area, you can set the URL to `self` to only download actions from your own instance by default.
|
||||
Of course, you can still use absolute URLs in workflows.
|
||||
|
||||
More details about the `[actions].DEFAULT_ACTIONS_URL` configuration can be found in the [Configuration Cheat Sheet](administration/config-cheat-sheet.md#actions-actions)。
|
||||
|
||||
### Context availability
|
||||
|
||||
|
||||
@ -120,15 +120,13 @@ Gitea Actions目前不支持此功能。
|
||||
|
||||
### 下载Actions
|
||||
|
||||
Gitea Actions默认不从GitHub下载Actions。
|
||||
"默认" 意味着您在`uses` 字段中不指定主机,如`uses: actions/checkout@v3`。
|
||||
相反,`uses: https://github.com/actions/checkout@v3`是有指定主机的。
|
||||
当 `[actions].DEFAULT_ACTIONS_URL` 保持默认值为 `github` 时,Gitea将会从 https://github.com 下载相对路径的actions。比如:
|
||||
如果你使用 `uses: actions/checkout@v3`,Gitea将会从 https://github.com/actions/checkout.git 下载这个 actions 项目。
|
||||
如果你想要从另外一个 Git服务下载actions,你只需要使用绝对URL `uses: https://gitea.com/actions/checkout@v3` 来下载。
|
||||
|
||||
如果您不进行配置,缺失的主机将填充为`https://gitea.com`。
|
||||
这意味着`uses: actions/checkout@v3`将从[gitea.com/actions/checkout](https://gitea.com/actions/checkout)下载该Action,而不是[github.com/actions/checkout](https://github.com/actions/checkout)。
|
||||
如果你的 Gitea 实例是部署在一个互联网限制的网络中,有可以使用绝对地址来下载 actions。你也可以讲配置项修改为 `[actions].DEFAULT_ACTIONS_URL = self`。这样所有的相对路径的actions引用,将不再会从 github.com 去下载,而会从这个 Gitea 实例自己的仓库中去下载。例如: `uses: actions/checkout@v3` 将会从 `[server].ROOT_URL`/actions/checkout.git 这个地址去下载 actions。
|
||||
|
||||
正如前面提到的,这是可配置的。
|
||||
如果您希望您的运行程序默认从GitHub或您自己的Gitea实例下载动作,您可以通过设置`[actions].DEFAULT_ACTIONS_URL`进行配置。请参阅[配置备忘单](administration/config-cheat-sheet.md#actions-actions)。
|
||||
设置`[actions].DEFAULT_ACTIONS_URL`进行配置。请参阅[配置备忘单](administration/config-cheat-sheet.md#actions-actions)。
|
||||
|
||||
### 上下文可用性
|
||||
|
||||
|
||||
@ -180,3 +180,6 @@ For events supported only by GitHub, see GitHub's [documentation](https://docs.g
|
||||
| pull_request_review_comment | `created`, `edited` |
|
||||
| release | `published`, `edited` |
|
||||
| registry_package | `published` |
|
||||
|
||||
> For `pull_request` events, in [GitHub Actions](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request), the `ref` is `refs/pull/:prNumber/merge`, which is a reference to the merge commit preview. However, Gitea has no such reference.
|
||||
> Therefore, the `ref` in Gitea Actions is `refs/pull/:prNumber/head`, which points to the head of pull request rather than the preview of the merge commit.
|
||||
|
||||
@ -180,3 +180,6 @@ defaults:
|
||||
| pull_request_review_comment | `created`, `edited` |
|
||||
| release | `published`, `edited` |
|
||||
| registry_package | `published` |
|
||||
|
||||
> 对于 `pull_request` 事件,在 [GitHub Actions](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request) 中 `ref` 是 `refs/pull/:prNumber/merge`,它指向这个拉取请求合并提交的一个预览。但是 Gitea 没有这种 reference。
|
||||
> 因此,Gitea Actions 中 `ref` 是 `refs/pull/:prNumber/head`,它指向这个拉取请求的头分支而不是合并提交的预览。
|
||||
|
||||
38
docs/content/usage/blame.en-us.md
Normal file
38
docs/content/usage/blame.en-us.md
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
date: "2023-08-14T00:00:00+00:00"
|
||||
title: "Blame File View"
|
||||
slug: "blame"
|
||||
sidebar_position: 13
|
||||
toc: false
|
||||
draft: false
|
||||
aliases:
|
||||
- /en-us/blame
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
name: "Blame"
|
||||
sidebar_position: 13
|
||||
identifier: "blame"
|
||||
---
|
||||
|
||||
# Blame File View
|
||||
|
||||
Gitea supports viewing the line-by-line revision history for a file also known as blame view.
|
||||
You can also use [`git blame`](https://git-scm.com/docs/git-blame) on the command line to view the revision history of lines within a file.
|
||||
|
||||
1. Navigate to and open the file whose line history you want to view.
|
||||
1. Click the `Blame` button in the file header bar.
|
||||
1. The new view shows the line-by-line revision history for a file with author and commit information on the left side.
|
||||
1. To navigate to an older commit, click the  icon.
|
||||
|
||||
## Ignore commits in the blame view
|
||||
|
||||
All revisions specified in the `.git-blame-ignore-revs` file are hidden from the blame view.
|
||||
This is especially useful to hide reformatting changes and keep the benefits of `git blame`.
|
||||
Lines that were changed or added by an ignored commit will be blamed on the previous commit that changed that line or nearby lines.
|
||||
The `.git-blame-ignore-revs` file must be located in the root directory of the repository.
|
||||
For more information like the file format, see [the `git blame --ignore-revs-file` documentation](https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt).
|
||||
|
||||
### Bypassing `.git-blame-ignore-revs` in the blame view
|
||||
|
||||
If the blame view for a file shows a message about ignored revisions, you can see the normal blame view by appending the url parameter `?bypass-blame-ignore=true`.
|
||||
@ -113,7 +113,7 @@ menu:
|
||||
|
||||
## 外部跟踪器
|
||||
|
||||
Gitea 支持使用外部工单跟踪器,并可以在合并请求中创建对外部托管的工单的引用。但是,如果外部跟踪器使用数字来标识工单,那么它们将与 Gitea 中托管的合并请求无法区分。为了解决这个工单,Gitea 允许使用 `!` 标记来标识合并请求。例如:
|
||||
Gitea 支持使用外部工单跟踪器,并可以在合并请求中创建对外部托管的工单的引用。但是,如果外部跟踪器使用数字来标识工单,那么它们将与 Gitea 中托管的合并请求无法区分。为了解决这个问题,Gitea 允许使用 `!` 标记来标识合并请求。例如:
|
||||
|
||||
> 这是工单 [#1234](#),并链接到外部跟踪器。
|
||||
> 这是合并请求 [!1234](#),并链接到 Gitea 中的合并请求。
|
||||
|
||||
1
docs/static/octicon-versions.svg
vendored
Normal file
1
docs/static/octicon-versions.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M7.75 14A1.75 1.75 0 0 1 6 12.25v-8.5C6 2.784 6.784 2 7.75 2h6.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14Zm-.25-1.75c0 .138.112.25.25.25h6.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25h-6.5a.25.25 0 0 0-.25.25ZM4.9 3.508a.75.75 0 0 1-.274 1.025.249.249 0 0 0-.126.217v6.5c0 .09.048.173.126.217a.75.75 0 0 1-.752 1.298A1.75 1.75 0 0 1 3 11.25v-6.5c0-.649.353-1.214.874-1.516a.75.75 0 0 1 1.025.274ZM1.625 5.533h.001a.249.249 0 0 0-.126.217v4.5c0 .09.048.173.126.217a.75.75 0 0 1-.752 1.298A1.748 1.748 0 0 1 0 10.25v-4.5a1.748 1.748 0 0 1 .873-1.516.75.75 0 1 1 .752 1.299Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 696 B |
22
go.mod
22
go.mod
@ -19,7 +19,7 @@ require (
|
||||
github.com/PuerkitoBio/goquery v1.8.1
|
||||
github.com/alecthomas/chroma/v2 v2.9.1
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||
github.com/blevesearch/bleve/v2 v2.3.9
|
||||
github.com/blevesearch/bleve/v2 v2.3.10
|
||||
github.com/bufbuild/connect-go v1.10.0
|
||||
github.com/buildkite/terminal-to-html/v3 v3.9.1
|
||||
github.com/caddyserver/certmagic v0.19.2
|
||||
@ -42,7 +42,7 @@ require (
|
||||
github.com/go-chi/chi/v5 v5.0.10
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-co-op/gocron v1.31.1
|
||||
github.com/go-enry/go-enry/v2 v2.8.4
|
||||
github.com/go-enry/go-enry/v2 v2.8.5
|
||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
|
||||
github.com/go-git/go-billy/v5 v5.4.1
|
||||
github.com/go-git/go-git/v5 v5.8.1
|
||||
@ -145,22 +145,22 @@ require (
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.8.0 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.0.5 // indirect
|
||||
github.com/blevesearch/geo v0.1.17 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.9.0 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.0.6 // indirect
|
||||
github.com/blevesearch/geo v0.1.18 // indirect
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||
github.com/blevesearch/gtreap v0.1.1 // indirect
|
||||
github.com/blevesearch/mmap-go v1.0.4 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.5 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.6 // indirect
|
||||
github.com/blevesearch/segment v0.9.1 // indirect
|
||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
||||
github.com/blevesearch/vellum v1.0.10 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.3.9 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.3.9 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.3.9 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.3.9 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.3.12 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.3.10 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.3.10 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.3.10 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.3.10 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.3.13 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230611145640-acc696258285 // indirect
|
||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||
|
||||
44
go.sum
44
go.sum
@ -149,18 +149,18 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bits-and-blooms/bitset v1.1.10/go.mod h1:w0XsmFg8qg6cmpTtJ0z3pKgjTDBMMnI/+I2syrE6XBE=
|
||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
||||
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bitset v1.9.0 h1:g1YivPG8jOtrN013Fe8OBXubkiTwvm7/vG2vXz03ANU=
|
||||
github.com/bits-and-blooms/bitset v1.9.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||
github.com/blevesearch/bleve/v2 v2.0.5/go.mod h1:ZjWibgnbRX33c+vBRgla9QhPb4QOjD6fdVJ+R1Bk8LM=
|
||||
github.com/blevesearch/bleve/v2 v2.3.9 h1:pUMvK0mxAexqasZcVj8lazmWnEW5XiV0tASIqANiNTQ=
|
||||
github.com/blevesearch/bleve/v2 v2.3.9/go.mod h1:1PibElcjlQMQHF9uS9mRv58ODQgj4pCWHA1Wfd+qagU=
|
||||
github.com/blevesearch/bleve/v2 v2.3.10 h1:z8V0wwGoL4rp7nG/O3qVVLYxUqCbEwskMt4iRJsPLgg=
|
||||
github.com/blevesearch/bleve/v2 v2.3.10/go.mod h1:RJzeoeHC+vNHsoLR54+crS1HmOWpnH87fL70HAUCzIA=
|
||||
github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
|
||||
github.com/blevesearch/bleve_index_api v1.0.5 h1:Lc986kpC4Z0/n1g3gg8ul7H+lxgOQPcXb9SxvQGu+tw=
|
||||
github.com/blevesearch/bleve_index_api v1.0.5/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms=
|
||||
github.com/blevesearch/geo v0.1.17 h1:AguzI6/5mHXapzB0gE9IKWo+wWPHZmXZoscHcjFgAFA=
|
||||
github.com/blevesearch/geo v0.1.17/go.mod h1:uRMGWG0HJYfWfFJpK3zTdnnr1K+ksZTuWKhXeSokfnM=
|
||||
github.com/blevesearch/bleve_index_api v1.0.6 h1:gyUUxdsrvmW3jVhhYdCVL6h9dCjNT/geNU7PxGn37p8=
|
||||
github.com/blevesearch/bleve_index_api v1.0.6/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms=
|
||||
github.com/blevesearch/geo v0.1.18 h1:Np8jycHTZ5scFe7VEPLrDoHnnb9C4j636ue/CGrhtDw=
|
||||
github.com/blevesearch/geo v0.1.18/go.mod h1:uRMGWG0HJYfWfFJpK3zTdnnr1K+ksZTuWKhXeSokfnM=
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
|
||||
github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y=
|
||||
@ -169,8 +169,8 @@ github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+
|
||||
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
|
||||
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.0.1/go.mod h1:lq7yK2jQy1yQjtjTfU931aVqz7pYxEudHaDwOt1tXfU=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.5 h1:1g713kpCQZ8u4a3stRGBfrwVOuGRnmxOVU5MQkUPrHU=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.5/go.mod h1:f2nOkKS1HcjgIWZgDAErgBdxmr2eyt0Kn7IY+FU1Xe4=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.6 h1:CdekX/Ob6YCYmeHzD72cKpwzBjvkOGegHOqhAkXp6yA=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.6/go.mod h1:nQQYlp51XvoSVxcciBjtvuHPIVjlWrN1hX4qwK2cqdc=
|
||||
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
|
||||
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
|
||||
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
|
||||
@ -184,20 +184,20 @@ github.com/blevesearch/vellum v1.0.4/go.mod h1:cMhywHI0de50f7Nj42YgvyD6bFJ2WkNRv
|
||||
github.com/blevesearch/vellum v1.0.10 h1:HGPJDT2bTva12hrHepVT3rOyIKFFF4t7Gf6yMxyMIPI=
|
||||
github.com/blevesearch/vellum v1.0.10/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k=
|
||||
github.com/blevesearch/zapx/v11 v11.2.0/go.mod h1:gN/a0alGw1FZt/YGTo1G6Z6XpDkeOfujX5exY9sCQQM=
|
||||
github.com/blevesearch/zapx/v11 v11.3.9 h1:y3ijS4h4MJdmQ07MHASxat4owAixreK2xdo76w9ncrw=
|
||||
github.com/blevesearch/zapx/v11 v11.3.9/go.mod h1:jcAYnQwlr+LqD2vLjDWjWiZDXDXGFqPbpPDRTd3XmS4=
|
||||
github.com/blevesearch/zapx/v11 v11.3.10 h1:hvjgj9tZ9DeIqBCxKhi70TtSZYMdcFn7gDb71Xo/fvk=
|
||||
github.com/blevesearch/zapx/v11 v11.3.10/go.mod h1:0+gW+FaE48fNxoVtMY5ugtNHHof/PxCqh7CnhYdnMzQ=
|
||||
github.com/blevesearch/zapx/v12 v12.2.0/go.mod h1:fdjwvCwWWwJW/EYTYGtAp3gBA0geCYGLcVTtJEZnY6A=
|
||||
github.com/blevesearch/zapx/v12 v12.3.9 h1:MXGLlZ03oxXH3DMJTZaBaRj2xb6t4wQVZeZK/wu1M6w=
|
||||
github.com/blevesearch/zapx/v12 v12.3.9/go.mod h1:QXCMwmOkdLnMDgTN1P4CcuX5F851iUOtOwXbw0HMBYs=
|
||||
github.com/blevesearch/zapx/v12 v12.3.10 h1:yHfj3vXLSYmmsBleJFROXuO08mS3L1qDCdDK81jDl8s=
|
||||
github.com/blevesearch/zapx/v12 v12.3.10/go.mod h1:0yeZg6JhaGxITlsS5co73aqPtM04+ycnI6D1v0mhbCs=
|
||||
github.com/blevesearch/zapx/v13 v13.2.0/go.mod h1:o5rAy/lRS5JpAbITdrOHBS/TugWYbkcYZTz6VfEinAQ=
|
||||
github.com/blevesearch/zapx/v13 v13.3.9 h1:+VAz9V0VmllHXlZV4DCvfYj0nqaZHgF3MeEHwOyRBwQ=
|
||||
github.com/blevesearch/zapx/v13 v13.3.9/go.mod h1:s+WjNp4WSDtrBVBpa37DUOd7S/Gr/jTZ7ST/MbCVj/0=
|
||||
github.com/blevesearch/zapx/v13 v13.3.10 h1:0KY9tuxg06rXxOZHg3DwPJBjniSlqEgVpxIqMGahDE8=
|
||||
github.com/blevesearch/zapx/v13 v13.3.10/go.mod h1:w2wjSDQ/WBVeEIvP0fvMJZAzDwqwIEzVPnCPrz93yAk=
|
||||
github.com/blevesearch/zapx/v14 v14.2.0/go.mod h1:GNgZusc1p4ot040cBQMRGEZobvwjCquiEKYh1xLFK9g=
|
||||
github.com/blevesearch/zapx/v14 v14.3.9 h1:wuqxATgsTCNHM9xsOFOeFp8H2heZ/gMX/tsl9lRK8U4=
|
||||
github.com/blevesearch/zapx/v14 v14.3.9/go.mod h1:MWZ4v8AzFBRurhDzkLvokFW8ljcq9Evm27mkWe8OGbM=
|
||||
github.com/blevesearch/zapx/v14 v14.3.10 h1:SG6xlsL+W6YjhX5N3aEiL/2tcWh3DO75Bnz77pSwwKU=
|
||||
github.com/blevesearch/zapx/v14 v14.3.10/go.mod h1:qqyuR0u230jN1yMmE4FIAuCxmahRQEOehF78m6oTgns=
|
||||
github.com/blevesearch/zapx/v15 v15.2.0/go.mod h1:MmQceLpWfME4n1WrBFIwplhWmaQbQqLQARpaKUEOs/A=
|
||||
github.com/blevesearch/zapx/v15 v15.3.12 h1:w/kU9aHyfMDEdwHGZzCiakC3HZ9z5gYlXaALDC4Dct8=
|
||||
github.com/blevesearch/zapx/v15 v15.3.12/go.mod h1:tx53gDJS/7Oa3Je820cmVurqCuJ4dqdAy1kiDMV/IUo=
|
||||
github.com/blevesearch/zapx/v15 v15.3.13 h1:6EkfaZiPlAxqXz0neniq35my6S48QI94W/wyhnpDHHQ=
|
||||
github.com/blevesearch/zapx/v15 v15.3.13/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y7fAFy8F4LXQtGg=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
@ -347,8 +347,8 @@ github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-co-op/gocron v1.31.1 h1:LZAuBlU0t3SPGUMJGhrJ6VuCc3CsrYzkzicygvVWlfA=
|
||||
github.com/go-co-op/gocron v1.31.1/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y=
|
||||
github.com/go-enry/go-enry/v2 v2.8.4 h1:QrY3hx/RiqCJJRbdU0MOcjfTM1a586J0WSooqdlJIhs=
|
||||
github.com/go-enry/go-enry/v2 v2.8.4/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
|
||||
github.com/go-enry/go-enry/v2 v2.8.5 h1:jtYXblst2+d9k7ZgEgkv6Q5hKRKPf0qHRjt715BZEX4=
|
||||
github.com/go-enry/go-enry/v2 v2.8.5/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
|
||||
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
|
||||
github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
|
||||
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
||||
|
||||
@ -22,7 +22,7 @@ type ActionRunnerToken struct {
|
||||
Owner *user_model.User `xorm:"-"`
|
||||
RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global
|
||||
Repo *repo_model.Repository `xorm:"-"`
|
||||
IsActive bool
|
||||
IsActive bool // true means it can be used
|
||||
|
||||
Created timeutil.TimeStamp `xorm:"created"`
|
||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||
@ -57,7 +57,7 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string
|
||||
return err
|
||||
}
|
||||
|
||||
// NewRunnerToken creates a new runner token
|
||||
// NewRunnerToken creates a new active runner token and invalidate all old tokens
|
||||
func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
||||
token, err := util.CryptoRandomString(40)
|
||||
if err != nil {
|
||||
@ -66,17 +66,27 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo
|
||||
runnerToken := &ActionRunnerToken{
|
||||
OwnerID: ownerID,
|
||||
RepoID: repoID,
|
||||
IsActive: false,
|
||||
IsActive: true,
|
||||
Token: token,
|
||||
}
|
||||
_, err = db.GetEngine(ctx).Insert(runnerToken)
|
||||
return runnerToken, err
|
||||
|
||||
return runnerToken, db.WithTx(ctx, func(ctx context.Context) error {
|
||||
if _, err := db.GetEngine(ctx).Where("owner_id =? AND repo_id = ?", ownerID, repoID).Cols("is_active").Update(&ActionRunnerToken{
|
||||
IsActive: false,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.GetEngine(ctx).Insert(runnerToken)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// GetUnactivatedRunnerToken returns a unactivated runner token
|
||||
func GetUnactivatedRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
||||
// GetLastestRunnerToken returns the latest runner token
|
||||
func GetLastestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
||||
var runnerToken ActionRunnerToken
|
||||
has, err := db.GetEngine(ctx).Where("owner_id=? AND repo_id=? AND is_active=?", ownerID, repoID, false).OrderBy("id DESC").Get(&runnerToken)
|
||||
has, err := db.GetEngine(ctx).Where("owner_id=? AND repo_id=?", ownerID, repoID).
|
||||
OrderBy("id DESC").Get(&runnerToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
|
||||
@ -41,15 +41,15 @@ func init() {
|
||||
}
|
||||
|
||||
// GetSchedulesMapByIDs returns the schedules by given id slice.
|
||||
func GetSchedulesMapByIDs(ids []int64) (map[int64]*ActionSchedule, error) {
|
||||
func GetSchedulesMapByIDs(ctx context.Context, ids []int64) (map[int64]*ActionSchedule, error) {
|
||||
schedules := make(map[int64]*ActionSchedule, len(ids))
|
||||
return schedules, db.GetEngine(db.DefaultContext).In("id", ids).Find(&schedules)
|
||||
return schedules, db.GetEngine(ctx).In("id", ids).Find(&schedules)
|
||||
}
|
||||
|
||||
// GetReposMapByIDs returns the repos by given id slice.
|
||||
func GetReposMapByIDs(ids []int64) (map[int64]*repo_model.Repository, error) {
|
||||
func GetReposMapByIDs(ctx context.Context, ids []int64) (map[int64]*repo_model.Repository, error) {
|
||||
repos := make(map[int64]*repo_model.Repository, len(ids))
|
||||
return repos, db.GetEngine(db.DefaultContext).In("id", ids).Find(&repos)
|
||||
return repos, db.GetEngine(ctx).In("id", ids).Find(&repos)
|
||||
}
|
||||
|
||||
var cronParser = cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
|
||||
|
||||
@ -23,9 +23,9 @@ func (specs SpecList) GetScheduleIDs() []int64 {
|
||||
return ids.Values()
|
||||
}
|
||||
|
||||
func (specs SpecList) LoadSchedules() error {
|
||||
func (specs SpecList) LoadSchedules(ctx context.Context) error {
|
||||
scheduleIDs := specs.GetScheduleIDs()
|
||||
schedules, err := GetSchedulesMapByIDs(scheduleIDs)
|
||||
schedules, err := GetSchedulesMapByIDs(ctx, scheduleIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -34,7 +34,7 @@ func (specs SpecList) LoadSchedules() error {
|
||||
}
|
||||
|
||||
repoIDs := specs.GetRepoIDs()
|
||||
repos, err := GetReposMapByIDs(repoIDs)
|
||||
repos, err := GetReposMapByIDs(ctx, repoIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -95,7 +95,7 @@ func FindSpecs(ctx context.Context, opts FindSpecOptions) (SpecList, int64, erro
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err := specs.LoadSchedules(); err != nil {
|
||||
if err := specs.LoadSchedules(ctx); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return specs, total, nil
|
||||
|
||||
@ -140,7 +140,7 @@ func (at ActionType) InActions(actions ...string) bool {
|
||||
// used in template render.
|
||||
type Action struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 // Receiver user id.
|
||||
UserID int64 `xorm:"INDEX"` // Receiver user id.
|
||||
OpType ActionType
|
||||
ActUserID int64 // Action user id.
|
||||
ActUser *user_model.User `xorm:"-"`
|
||||
@ -208,91 +208,91 @@ func (a *Action) loadRepo(ctx context.Context) {
|
||||
}
|
||||
|
||||
// GetActFullName gets the action's user full name.
|
||||
func (a *Action) GetActFullName() string {
|
||||
a.LoadActUser(db.DefaultContext)
|
||||
func (a *Action) GetActFullName(ctx context.Context) string {
|
||||
a.LoadActUser(ctx)
|
||||
return a.ActUser.FullName
|
||||
}
|
||||
|
||||
// GetActUserName gets the action's user name.
|
||||
func (a *Action) GetActUserName() string {
|
||||
a.LoadActUser(db.DefaultContext)
|
||||
func (a *Action) GetActUserName(ctx context.Context) string {
|
||||
a.LoadActUser(ctx)
|
||||
return a.ActUser.Name
|
||||
}
|
||||
|
||||
// ShortActUserName gets the action's user name trimmed to max 20
|
||||
// chars.
|
||||
func (a *Action) ShortActUserName() string {
|
||||
return base.EllipsisString(a.GetActUserName(), 20)
|
||||
func (a *Action) ShortActUserName(ctx context.Context) string {
|
||||
return base.EllipsisString(a.GetActUserName(ctx), 20)
|
||||
}
|
||||
|
||||
// GetDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank.
|
||||
func (a *Action) GetDisplayName() string {
|
||||
func (a *Action) GetDisplayName(ctx context.Context) string {
|
||||
if setting.UI.DefaultShowFullName {
|
||||
trimmedFullName := strings.TrimSpace(a.GetActFullName())
|
||||
trimmedFullName := strings.TrimSpace(a.GetActFullName(ctx))
|
||||
if len(trimmedFullName) > 0 {
|
||||
return trimmedFullName
|
||||
}
|
||||
}
|
||||
return a.ShortActUserName()
|
||||
return a.ShortActUserName(ctx)
|
||||
}
|
||||
|
||||
// GetDisplayNameTitle gets the action's display name used for the title (tooltip) based on DEFAULT_SHOW_FULL_NAME
|
||||
func (a *Action) GetDisplayNameTitle() string {
|
||||
func (a *Action) GetDisplayNameTitle(ctx context.Context) string {
|
||||
if setting.UI.DefaultShowFullName {
|
||||
return a.ShortActUserName()
|
||||
return a.ShortActUserName(ctx)
|
||||
}
|
||||
return a.GetActFullName()
|
||||
return a.GetActFullName(ctx)
|
||||
}
|
||||
|
||||
// GetRepoUserName returns the name of the action repository owner.
|
||||
func (a *Action) GetRepoUserName() string {
|
||||
a.loadRepo(db.DefaultContext)
|
||||
func (a *Action) GetRepoUserName(ctx context.Context) string {
|
||||
a.loadRepo(ctx)
|
||||
return a.Repo.OwnerName
|
||||
}
|
||||
|
||||
// ShortRepoUserName returns the name of the action repository owner
|
||||
// trimmed to max 20 chars.
|
||||
func (a *Action) ShortRepoUserName() string {
|
||||
return base.EllipsisString(a.GetRepoUserName(), 20)
|
||||
func (a *Action) ShortRepoUserName(ctx context.Context) string {
|
||||
return base.EllipsisString(a.GetRepoUserName(ctx), 20)
|
||||
}
|
||||
|
||||
// GetRepoName returns the name of the action repository.
|
||||
func (a *Action) GetRepoName() string {
|
||||
a.loadRepo(db.DefaultContext)
|
||||
func (a *Action) GetRepoName(ctx context.Context) string {
|
||||
a.loadRepo(ctx)
|
||||
return a.Repo.Name
|
||||
}
|
||||
|
||||
// ShortRepoName returns the name of the action repository
|
||||
// trimmed to max 33 chars.
|
||||
func (a *Action) ShortRepoName() string {
|
||||
return base.EllipsisString(a.GetRepoName(), 33)
|
||||
func (a *Action) ShortRepoName(ctx context.Context) string {
|
||||
return base.EllipsisString(a.GetRepoName(ctx), 33)
|
||||
}
|
||||
|
||||
// GetRepoPath returns the virtual path to the action repository.
|
||||
func (a *Action) GetRepoPath() string {
|
||||
return path.Join(a.GetRepoUserName(), a.GetRepoName())
|
||||
func (a *Action) GetRepoPath(ctx context.Context) string {
|
||||
return path.Join(a.GetRepoUserName(ctx), a.GetRepoName(ctx))
|
||||
}
|
||||
|
||||
// ShortRepoPath returns the virtual path to the action repository
|
||||
// trimmed to max 20 + 1 + 33 chars.
|
||||
func (a *Action) ShortRepoPath() string {
|
||||
return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
|
||||
func (a *Action) ShortRepoPath(ctx context.Context) string {
|
||||
return path.Join(a.ShortRepoUserName(ctx), a.ShortRepoName(ctx))
|
||||
}
|
||||
|
||||
// GetRepoLink returns relative link to action repository.
|
||||
func (a *Action) GetRepoLink() string {
|
||||
func (a *Action) GetRepoLink(ctx context.Context) string {
|
||||
// path.Join will skip empty strings
|
||||
return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName()))
|
||||
return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName(ctx)), url.PathEscape(a.GetRepoName(ctx)))
|
||||
}
|
||||
|
||||
// GetRepoAbsoluteLink returns the absolute link to action repository.
|
||||
func (a *Action) GetRepoAbsoluteLink() string {
|
||||
return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName())
|
||||
func (a *Action) GetRepoAbsoluteLink(ctx context.Context) string {
|
||||
return setting.AppURL + url.PathEscape(a.GetRepoUserName(ctx)) + "/" + url.PathEscape(a.GetRepoName(ctx))
|
||||
}
|
||||
|
||||
// GetCommentHTMLURL returns link to action comment.
|
||||
func (a *Action) GetCommentHTMLURL() string {
|
||||
return a.getCommentHTMLURL(db.DefaultContext)
|
||||
func (a *Action) GetCommentHTMLURL(ctx context.Context) string {
|
||||
return a.getCommentHTMLURL(ctx)
|
||||
}
|
||||
|
||||
func (a *Action) loadComment(ctx context.Context) (err error) {
|
||||
@ -309,7 +309,7 @@ func (a *Action) getCommentHTMLURL(ctx context.Context) string {
|
||||
}
|
||||
_ = a.loadComment(ctx)
|
||||
if a.Comment != nil {
|
||||
return a.Comment.HTMLURL()
|
||||
return a.Comment.HTMLURL(ctx)
|
||||
}
|
||||
if len(a.GetIssueInfos()) == 0 {
|
||||
return "#"
|
||||
@ -334,8 +334,8 @@ func (a *Action) getCommentHTMLURL(ctx context.Context) string {
|
||||
}
|
||||
|
||||
// GetCommentLink returns link to action comment.
|
||||
func (a *Action) GetCommentLink() string {
|
||||
return a.getCommentLink(db.DefaultContext)
|
||||
func (a *Action) GetCommentLink(ctx context.Context) string {
|
||||
return a.getCommentLink(ctx)
|
||||
}
|
||||
|
||||
func (a *Action) getCommentLink(ctx context.Context) string {
|
||||
@ -344,7 +344,7 @@ func (a *Action) getCommentLink(ctx context.Context) string {
|
||||
}
|
||||
_ = a.loadComment(ctx)
|
||||
if a.Comment != nil {
|
||||
return a.Comment.Link()
|
||||
return a.Comment.Link(ctx)
|
||||
}
|
||||
if len(a.GetIssueInfos()) == 0 {
|
||||
return "#"
|
||||
@ -374,8 +374,8 @@ func (a *Action) GetBranch() string {
|
||||
}
|
||||
|
||||
// GetRefLink returns the action's ref link.
|
||||
func (a *Action) GetRefLink() string {
|
||||
return git.RefURL(a.GetRepoLink(), a.RefName)
|
||||
func (a *Action) GetRefLink(ctx context.Context) string {
|
||||
return git.RefURL(a.GetRepoLink(ctx), a.RefName)
|
||||
}
|
||||
|
||||
// GetTag returns the action's repository tag.
|
||||
@ -399,11 +399,10 @@ func (a *Action) GetIssueInfos() []string {
|
||||
return strings.SplitN(a.Content, "|", 3)
|
||||
}
|
||||
|
||||
// GetIssueTitle returns the title of first issue associated
|
||||
// with the action. This function will be invoked in template so keep db.DefaultContext here
|
||||
func (a *Action) GetIssueTitle() string {
|
||||
// GetIssueTitle returns the title of first issue associated with the action.
|
||||
func (a *Action) GetIssueTitle(ctx context.Context) string {
|
||||
index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
|
||||
issue, err := issues_model.GetIssueByIndex(db.DefaultContext, a.RepoID, index)
|
||||
issue, err := issues_model.GetIssueByIndex(ctx, a.RepoID, index)
|
||||
if err != nil {
|
||||
log.Error("GetIssueByIndex: %v", err)
|
||||
return "500 when get issue"
|
||||
@ -442,7 +441,7 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
|
||||
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
|
||||
}
|
||||
|
||||
cond, err := activityQueryCondition(opts)
|
||||
cond, err := activityQueryCondition(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
@ -473,11 +472,11 @@ func ActivityReadable(user, doer *user_model.User) bool {
|
||||
doer != nil && (doer.IsAdmin || user.ID == doer.ID)
|
||||
}
|
||||
|
||||
func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
|
||||
func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) {
|
||||
cond := builder.NewCond()
|
||||
|
||||
if opts.RequestedTeam != nil && opts.RequestedUser == nil {
|
||||
org, err := user_model.GetUserByID(db.DefaultContext, opts.RequestedTeam.OrgID)
|
||||
org, err := user_model.GetUserByID(ctx, opts.RequestedTeam.OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -525,7 +524,7 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
|
||||
}
|
||||
|
||||
if opts.RequestedTeam != nil {
|
||||
env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(opts.RequestedTeam)
|
||||
env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(ctx, opts.RequestedTeam)
|
||||
teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetTeamRepositories: %w", err)
|
||||
@ -564,12 +563,12 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
|
||||
}
|
||||
|
||||
// DeleteOldActions deletes all old actions from database.
|
||||
func DeleteOldActions(olderThan time.Duration) (err error) {
|
||||
func DeleteOldActions(ctx context.Context, olderThan time.Duration) (err error) {
|
||||
if olderThan <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = db.GetEngine(db.DefaultContext).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Action{})
|
||||
_, err = db.GetEngine(ctx).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Action{})
|
||||
return err
|
||||
}
|
||||
|
||||
@ -679,8 +678,8 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||
}
|
||||
|
||||
// NotifyWatchersActions creates batch of actions for every watcher.
|
||||
func NotifyWatchersActions(acts []*Action) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func NotifyWatchersActions(ctx context.Context, acts []*Action) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ func TestAction_GetRepoPath(t *testing.T) {
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
action := &activities_model.Action{RepoID: repo.ID}
|
||||
assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
|
||||
assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath(db.DefaultContext))
|
||||
}
|
||||
|
||||
func TestAction_GetRepoLink(t *testing.T) {
|
||||
@ -35,9 +35,9 @@ func TestAction_GetRepoLink(t *testing.T) {
|
||||
action := &activities_model.Action{RepoID: repo.ID, CommentID: comment.ID}
|
||||
setting.AppSubURL = "/suburl"
|
||||
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
|
||||
assert.Equal(t, expected, action.GetRepoLink())
|
||||
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink())
|
||||
assert.Equal(t, comment.HTMLURL(), action.GetCommentHTMLURL())
|
||||
assert.Equal(t, expected, action.GetRepoLink(db.DefaultContext))
|
||||
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink(db.DefaultContext))
|
||||
assert.Equal(t, comment.HTMLURL(db.DefaultContext), action.GetCommentHTMLURL(db.DefaultContext))
|
||||
}
|
||||
|
||||
func TestGetFeeds(t *testing.T) {
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
package activities_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
@ -14,7 +13,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", ".."),
|
||||
})
|
||||
unittest.MainTest(m)
|
||||
}
|
||||
|
||||
@ -175,8 +175,8 @@ func CreateRepoTransferNotification(ctx context.Context, doer, newOwner *user_mo
|
||||
// CreateOrUpdateIssueNotifications creates an issue notification
|
||||
// for each watcher, or updates it if already exists
|
||||
// receiverID > 0 just send to receiver, else send to all watcher
|
||||
func CreateOrUpdateIssueNotifications(issueID, commentID, notificationAuthorID, receiverID int64) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func CreateOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -435,21 +435,21 @@ func (n *Notification) loadUser(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
// GetRepo returns the repo of the notification
|
||||
func (n *Notification) GetRepo() (*repo_model.Repository, error) {
|
||||
return n.Repository, n.loadRepo(db.DefaultContext)
|
||||
func (n *Notification) GetRepo(ctx context.Context) (*repo_model.Repository, error) {
|
||||
return n.Repository, n.loadRepo(ctx)
|
||||
}
|
||||
|
||||
// GetIssue returns the issue of the notification
|
||||
func (n *Notification) GetIssue() (*issues_model.Issue, error) {
|
||||
return n.Issue, n.loadIssue(db.DefaultContext)
|
||||
func (n *Notification) GetIssue(ctx context.Context) (*issues_model.Issue, error) {
|
||||
return n.Issue, n.loadIssue(ctx)
|
||||
}
|
||||
|
||||
// HTMLURL formats a URL-string to the notification
|
||||
func (n *Notification) HTMLURL() string {
|
||||
func (n *Notification) HTMLURL(ctx context.Context) string {
|
||||
switch n.Source {
|
||||
case NotificationSourceIssue, NotificationSourcePullRequest:
|
||||
if n.Comment != nil {
|
||||
return n.Comment.HTMLURL()
|
||||
return n.Comment.HTMLURL(ctx)
|
||||
}
|
||||
return n.Issue.HTMLURL()
|
||||
case NotificationSourceCommit:
|
||||
@ -461,11 +461,11 @@ func (n *Notification) HTMLURL() string {
|
||||
}
|
||||
|
||||
// Link formats a relative URL-string to the notification
|
||||
func (n *Notification) Link() string {
|
||||
func (n *Notification) Link(ctx context.Context) string {
|
||||
switch n.Source {
|
||||
case NotificationSourceIssue, NotificationSourcePullRequest:
|
||||
if n.Comment != nil {
|
||||
return n.Comment.Link()
|
||||
return n.Comment.Link(ctx)
|
||||
}
|
||||
return n.Issue.Link()
|
||||
case NotificationSourceCommit:
|
||||
@ -733,12 +733,12 @@ type UserIDCount struct {
|
||||
}
|
||||
|
||||
// GetUIDsAndNotificationCounts between the two provided times
|
||||
func GetUIDsAndNotificationCounts(since, until timeutil.TimeStamp) ([]UserIDCount, error) {
|
||||
func GetUIDsAndNotificationCounts(ctx context.Context, since, until timeutil.TimeStamp) ([]UserIDCount, error) {
|
||||
sql := `SELECT user_id, count(*) AS count FROM notification ` +
|
||||
`WHERE user_id IN (SELECT user_id FROM notification WHERE updated_unix >= ? AND ` +
|
||||
`updated_unix < ?) AND status = ? GROUP BY user_id`
|
||||
var res []UserIDCount
|
||||
return res, db.GetEngine(db.DefaultContext).SQL(sql, since, until, NotificationStatusUnread).Find(&res)
|
||||
return res, db.GetEngine(ctx).SQL(sql, since, until, NotificationStatusUnread).Find(&res)
|
||||
}
|
||||
|
||||
// SetIssueReadBy sets issue to be read by given user.
|
||||
|
||||
@ -20,7 +20,7 @@ func TestCreateOrUpdateIssueNotifications(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
||||
|
||||
assert.NoError(t, activities_model.CreateOrUpdateIssueNotifications(issue.ID, 0, 2, 0))
|
||||
assert.NoError(t, activities_model.CreateOrUpdateIssueNotifications(db.DefaultContext, issue.ID, 0, 2, 0))
|
||||
|
||||
// User 9 is inactive, thus notifications for user 1 and 4 are created
|
||||
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: 1, IssueID: issue.ID})
|
||||
@ -50,7 +50,7 @@ func TestNotificationsForUser(t *testing.T) {
|
||||
func TestNotification_GetRepo(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1})
|
||||
repo, err := notf.GetRepo()
|
||||
repo, err := notf.GetRepo(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, repo, notf.Repository)
|
||||
assert.EqualValues(t, notf.RepoID, repo.ID)
|
||||
@ -59,7 +59,7 @@ func TestNotification_GetRepo(t *testing.T) {
|
||||
func TestNotification_GetIssue(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1})
|
||||
issue, err := notf.GetIssue()
|
||||
issue, err := notf.GetIssue(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, issue, notf.Issue)
|
||||
assert.EqualValues(t, notf.IssueID, issue.ID)
|
||||
|
||||
@ -342,7 +342,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
|
||||
|
||||
// Published releases list
|
||||
sess := releasesForActivityStatement(ctx, repoID, fromTime)
|
||||
sess.OrderBy("release.created_unix DESC")
|
||||
sess.OrderBy("`release`.created_unix DESC")
|
||||
stats.PublishedReleases = make([]*repo_model.Release, 0)
|
||||
if err = sess.Find(&stats.PublishedReleases); err != nil {
|
||||
return err
|
||||
@ -350,7 +350,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
|
||||
|
||||
// Published releases authors
|
||||
sess = releasesForActivityStatement(ctx, repoID, fromTime)
|
||||
if _, err = sess.Select("count(distinct release.publisher_id) as `count`").Table("release").Get(&count); err != nil {
|
||||
if _, err = sess.Select("count(distinct `release`.publisher_id) as `count`").Table("release").Get(&count); err != nil {
|
||||
return err
|
||||
}
|
||||
stats.PublishedReleaseAuthorCount = count
|
||||
@ -359,7 +359,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
|
||||
}
|
||||
|
||||
func releasesForActivityStatement(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
|
||||
return db.GetEngine(ctx).Where("release.repo_id = ?", repoID).
|
||||
And("release.is_draft = ?", false).
|
||||
And("release.created_unix >= ?", fromTime.Unix())
|
||||
return db.GetEngine(ctx).Where("`release`.repo_id = ?", repoID).
|
||||
And("`release`.is_draft = ?", false).
|
||||
And("`release`.created_unix >= ?", fromTime.Unix())
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
package activities
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
@ -47,12 +49,12 @@ type IssueByRepositoryCount struct {
|
||||
}
|
||||
|
||||
// GetStatistic returns the database statistics
|
||||
func GetStatistic() (stats Statistic) {
|
||||
e := db.GetEngine(db.DefaultContext)
|
||||
stats.Counter.User = user_model.CountUsers(nil)
|
||||
stats.Counter.Org, _ = organization.CountOrgs(organization.FindOrgOptions{IncludePrivate: true})
|
||||
func GetStatistic(ctx context.Context) (stats Statistic) {
|
||||
e := db.GetEngine(ctx)
|
||||
stats.Counter.User = user_model.CountUsers(ctx, nil)
|
||||
stats.Counter.Org, _ = organization.CountOrgs(ctx, organization.FindOrgOptions{IncludePrivate: true})
|
||||
stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey))
|
||||
stats.Counter.Repo, _ = repo_model.CountRepositories(db.DefaultContext, repo_model.CountRepositoryOptions{})
|
||||
stats.Counter.Repo, _ = repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{})
|
||||
stats.Counter.Watch, _ = e.Count(new(repo_model.Watch))
|
||||
stats.Counter.Star, _ = e.Count(new(repo_model.Star))
|
||||
stats.Counter.Access, _ = e.Count(new(access_model.Access))
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
package activities
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
@ -18,16 +20,16 @@ type UserHeatmapData struct {
|
||||
}
|
||||
|
||||
// GetUserHeatmapDataByUser returns an array of UserHeatmapData
|
||||
func GetUserHeatmapDataByUser(user, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||
return getUserHeatmapData(user, nil, doer)
|
||||
func GetUserHeatmapDataByUser(ctx context.Context, user, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||
return getUserHeatmapData(ctx, user, nil, doer)
|
||||
}
|
||||
|
||||
// GetUserHeatmapDataByUserTeam returns an array of UserHeatmapData
|
||||
func GetUserHeatmapDataByUserTeam(user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||
return getUserHeatmapData(user, team, doer)
|
||||
func GetUserHeatmapDataByUserTeam(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||
return getUserHeatmapData(ctx, user, team, doer)
|
||||
}
|
||||
|
||||
func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||
func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||
hdata := make([]*UserHeatmapData, 0)
|
||||
|
||||
if !ActivityReadable(user, doer) {
|
||||
@ -45,7 +47,7 @@ func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *us
|
||||
groupByName = groupBy
|
||||
}
|
||||
|
||||
cond, err := activityQueryCondition(GetFeedsOptions{
|
||||
cond, err := activityQueryCondition(ctx, GetFeedsOptions{
|
||||
RequestedUser: user,
|
||||
RequestedTeam: team,
|
||||
Actor: doer,
|
||||
@ -60,7 +62,7 @@ func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *us
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return hdata, db.GetEngine(db.DefaultContext).
|
||||
return hdata, db.GetEngine(ctx).
|
||||
Select(groupBy+" AS timestamp, count(user_id) as contributions").
|
||||
Table("action").
|
||||
Where(cond).
|
||||
|
||||
@ -83,7 +83,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get the heatmap and compare
|
||||
heatmap, err := activities_model.GetUserHeatmapDataByUser(user, doer)
|
||||
heatmap, err := activities_model.GetUserHeatmapDataByUser(db.DefaultContext, user, doer)
|
||||
var contributions int
|
||||
for _, hm := range heatmap {
|
||||
contributions += int(hm.Contributions)
|
||||
|
||||
@ -48,11 +48,7 @@ type TranslatableMessage struct {
|
||||
}
|
||||
|
||||
// LoadRepo loads repository of the task
|
||||
func (task *Task) LoadRepo() error {
|
||||
return task.loadRepo(db.DefaultContext)
|
||||
}
|
||||
|
||||
func (task *Task) loadRepo(ctx context.Context) error {
|
||||
func (task *Task) LoadRepo(ctx context.Context) error {
|
||||
if task.Repo != nil {
|
||||
return nil
|
||||
}
|
||||
@ -70,13 +66,13 @@ func (task *Task) loadRepo(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// LoadDoer loads do user
|
||||
func (task *Task) LoadDoer() error {
|
||||
func (task *Task) LoadDoer(ctx context.Context) error {
|
||||
if task.Doer != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var doer user_model.User
|
||||
has, err := db.GetEngine(db.DefaultContext).ID(task.DoerID).Get(&doer)
|
||||
has, err := db.GetEngine(ctx).ID(task.DoerID).Get(&doer)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
@ -90,13 +86,13 @@ func (task *Task) LoadDoer() error {
|
||||
}
|
||||
|
||||
// LoadOwner loads owner user
|
||||
func (task *Task) LoadOwner() error {
|
||||
func (task *Task) LoadOwner(ctx context.Context) error {
|
||||
if task.Owner != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var owner user_model.User
|
||||
has, err := db.GetEngine(db.DefaultContext).ID(task.OwnerID).Get(&owner)
|
||||
has, err := db.GetEngine(ctx).ID(task.OwnerID).Get(&owner)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
@ -110,8 +106,8 @@ func (task *Task) LoadOwner() error {
|
||||
}
|
||||
|
||||
// UpdateCols updates some columns
|
||||
func (task *Task) UpdateCols(cols ...string) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).ID(task.ID).Cols(cols...).Update(task)
|
||||
func (task *Task) UpdateCols(ctx context.Context, cols ...string) error {
|
||||
_, err := db.GetEngine(ctx).ID(task.ID).Cols(cols...).Update(task)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -169,12 +165,12 @@ func (err ErrTaskDoesNotExist) Unwrap() error {
|
||||
}
|
||||
|
||||
// GetMigratingTask returns the migrating task by repo's id
|
||||
func GetMigratingTask(repoID int64) (*Task, error) {
|
||||
func GetMigratingTask(ctx context.Context, repoID int64) (*Task, error) {
|
||||
task := Task{
|
||||
RepoID: repoID,
|
||||
Type: structs.TaskTypeMigrateRepo,
|
||||
}
|
||||
has, err := db.GetEngine(db.DefaultContext).Get(&task)
|
||||
has, err := db.GetEngine(ctx).Get(&task)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
@ -184,13 +180,13 @@ func GetMigratingTask(repoID int64) (*Task, error) {
|
||||
}
|
||||
|
||||
// GetMigratingTaskByID returns the migrating task by repo's id
|
||||
func GetMigratingTaskByID(id, doerID int64) (*Task, *migration.MigrateOptions, error) {
|
||||
func GetMigratingTaskByID(ctx context.Context, id, doerID int64) (*Task, *migration.MigrateOptions, error) {
|
||||
task := Task{
|
||||
ID: id,
|
||||
DoerID: doerID,
|
||||
Type: structs.TaskTypeMigrateRepo,
|
||||
}
|
||||
has, err := db.GetEngine(db.DefaultContext).Get(&task)
|
||||
has, err := db.GetEngine(ctx).Get(&task)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
} else if !has {
|
||||
@ -205,12 +201,12 @@ func GetMigratingTaskByID(id, doerID int64) (*Task, *migration.MigrateOptions, e
|
||||
}
|
||||
|
||||
// CreateTask creates a task on database
|
||||
func CreateTask(task *Task) error {
|
||||
return db.Insert(db.DefaultContext, task)
|
||||
func CreateTask(ctx context.Context, task *Task) error {
|
||||
return db.Insert(ctx, task)
|
||||
}
|
||||
|
||||
// FinishMigrateTask updates database when migrate task finished
|
||||
func FinishMigrateTask(task *Task) error {
|
||||
func FinishMigrateTask(ctx context.Context, task *Task) error {
|
||||
task.Status = structs.TaskStatusFinished
|
||||
task.EndTime = timeutil.TimeStampNow()
|
||||
|
||||
@ -231,6 +227,6 @@ func FinishMigrateTask(task *Task) error {
|
||||
}
|
||||
task.PayloadContent = string(confBytes)
|
||||
|
||||
_, err = db.GetEngine(db.DefaultContext).ID(task.ID).Cols("status", "end_time", "payload_content").Update(task)
|
||||
_, err = db.GetEngine(ctx).ID(task.ID).Cols("status", "end_time", "payload_content").Update(task)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -88,14 +88,14 @@ func ListGPGKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([]
|
||||
}
|
||||
|
||||
// CountUserGPGKeys return number of gpg keys a user own
|
||||
func CountUserGPGKeys(userID int64) (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{})
|
||||
func CountUserGPGKeys(ctx context.Context, userID int64) (int64, error) {
|
||||
return db.GetEngine(ctx).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{})
|
||||
}
|
||||
|
||||
// GetGPGKeyByID returns public key by given ID.
|
||||
func GetGPGKeyByID(keyID int64) (*GPGKey, error) {
|
||||
func GetGPGKeyByID(ctx context.Context, keyID int64) (*GPGKey, error) {
|
||||
key := new(GPGKey)
|
||||
has, err := db.GetEngine(db.DefaultContext).ID(keyID).Get(key)
|
||||
has, err := db.GetEngine(ctx).ID(keyID).Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
@ -105,9 +105,9 @@ func GetGPGKeyByID(keyID int64) (*GPGKey, error) {
|
||||
}
|
||||
|
||||
// GetGPGKeysByKeyID returns public key by given ID.
|
||||
func GetGPGKeysByKeyID(keyID string) ([]*GPGKey, error) {
|
||||
func GetGPGKeysByKeyID(ctx context.Context, keyID string) ([]*GPGKey, error) {
|
||||
keys := make([]*GPGKey, 0, 1)
|
||||
return keys, db.GetEngine(db.DefaultContext).Where("key_id=?", keyID).Find(&keys)
|
||||
return keys, db.GetEngine(ctx).Where("key_id=?", keyID).Find(&keys)
|
||||
}
|
||||
|
||||
// GPGKeyToEntity retrieve the imported key and the traducted entity
|
||||
@ -144,7 +144,7 @@ func parseSubGPGKey(ownerID int64, primaryID string, pubkey *packet.PublicKey, e
|
||||
}
|
||||
|
||||
// parseGPGKey parse a PrimaryKey entity (primary key + subs keys + self-signature)
|
||||
func parseGPGKey(ownerID int64, e *openpgp.Entity, verified bool) (*GPGKey, error) {
|
||||
func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified bool) (*GPGKey, error) {
|
||||
pubkey := e.PrimaryKey
|
||||
expiry := getExpiryTime(e)
|
||||
|
||||
@ -159,7 +159,7 @@ func parseGPGKey(ownerID int64, e *openpgp.Entity, verified bool) (*GPGKey, erro
|
||||
}
|
||||
|
||||
// Check emails
|
||||
userEmails, err := user_model.GetEmailAddresses(ownerID)
|
||||
userEmails, err := user_model.GetEmailAddresses(ctx, ownerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -224,8 +224,8 @@ func deleteGPGKey(ctx context.Context, keyID string) (int64, error) {
|
||||
}
|
||||
|
||||
// DeleteGPGKey deletes GPG key information in database.
|
||||
func DeleteGPGKey(doer *user_model.User, id int64) (err error) {
|
||||
key, err := GetGPGKeyByID(id)
|
||||
func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err error) {
|
||||
key, err := GetGPGKeyByID(ctx, id)
|
||||
if err != nil {
|
||||
if IsErrGPGKeyNotExist(err) {
|
||||
return nil
|
||||
@ -238,7 +238,7 @@ func DeleteGPGKey(doer *user_model.User, id int64) (err error) {
|
||||
return ErrGPGKeyAccessDenied{doer.ID, key.ID}
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -251,7 +251,7 @@ func DeleteGPGKey(doer *user_model.User, id int64) (err error) {
|
||||
return committer.Commit()
|
||||
}
|
||||
|
||||
func checkKeyEmails(email string, keys ...*GPGKey) (bool, string) {
|
||||
func checkKeyEmails(ctx context.Context, email string, keys ...*GPGKey) (bool, string) {
|
||||
uid := int64(0)
|
||||
var userEmails []*user_model.EmailAddress
|
||||
var user *user_model.User
|
||||
@ -263,10 +263,10 @@ func checkKeyEmails(email string, keys ...*GPGKey) (bool, string) {
|
||||
}
|
||||
if key.Verified && key.OwnerID != 0 {
|
||||
if uid != key.OwnerID {
|
||||
userEmails, _ = user_model.GetEmailAddresses(key.OwnerID)
|
||||
userEmails, _ = user_model.GetEmailAddresses(ctx, key.OwnerID)
|
||||
uid = key.OwnerID
|
||||
user = &user_model.User{ID: uid}
|
||||
_, _ = user_model.GetUser(user)
|
||||
_, _ = user_model.GetUser(ctx, user)
|
||||
}
|
||||
for _, e := range userEmails {
|
||||
if e.IsActivated && (email == "" || strings.EqualFold(e.Email, email)) {
|
||||
|
||||
@ -66,13 +66,13 @@ func addGPGSubKey(ctx context.Context, key *GPGKey) (err error) {
|
||||
}
|
||||
|
||||
// AddGPGKey adds new public key to database.
|
||||
func AddGPGKey(ownerID int64, content, token, signature string) ([]*GPGKey, error) {
|
||||
func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature string) ([]*GPGKey, error) {
|
||||
ekeys, err := checkArmoredGPGKeyString(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -153,7 +153,7 @@ func AddGPGKey(ownerID int64, content, token, signature string) ([]*GPGKey, erro
|
||||
|
||||
// Get DB session
|
||||
|
||||
key, err := parseGPGKey(ownerID, ekey, verified)
|
||||
key, err := parseGPGKey(ctx, ownerID, ekey, verified)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
|
||||
|
||||
// If this a SSH signature handle it differently
|
||||
if strings.HasPrefix(c.Signature.Signature, "-----BEGIN SSH SIGNATURE-----") {
|
||||
return ParseCommitWithSSHSignature(c, committer)
|
||||
return ParseCommitWithSSHSignature(ctx, c, committer)
|
||||
}
|
||||
|
||||
// Parsing signature
|
||||
@ -150,6 +150,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
|
||||
|
||||
// First check if the sig has a keyID and if so just look at that
|
||||
if commitVerification := hashAndVerifyForKeyID(
|
||||
ctx,
|
||||
sig,
|
||||
c.Signature.Payload,
|
||||
committer,
|
||||
@ -165,7 +166,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
|
||||
|
||||
// Now try to associate the signature with the committer, if present
|
||||
if committer.ID != 0 {
|
||||
keys, err := ListGPGKeys(db.DefaultContext, committer.ID, db.ListOptions{})
|
||||
keys, err := ListGPGKeys(ctx, committer.ID, db.ListOptions{})
|
||||
if err != nil { // Skipping failed to get gpg keys of user
|
||||
log.Error("ListGPGKeys: %v", err)
|
||||
return &CommitVerification{
|
||||
@ -175,7 +176,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
|
||||
}
|
||||
}
|
||||
|
||||
committerEmailAddresses, _ := user_model.GetEmailAddresses(committer.ID)
|
||||
committerEmailAddresses, _ := user_model.GetEmailAddresses(ctx, committer.ID)
|
||||
activated := false
|
||||
for _, e := range committerEmailAddresses {
|
||||
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
|
||||
@ -222,7 +223,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
|
||||
}
|
||||
if err := gpgSettings.LoadPublicKeyContent(); err != nil {
|
||||
log.Error("Error getting default signing key: %s %v", gpgSettings.KeyID, err)
|
||||
} else if commitVerification := verifyWithGPGSettings(&gpgSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil {
|
||||
} else if commitVerification := verifyWithGPGSettings(ctx, &gpgSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil {
|
||||
if commitVerification.Reason == BadSignature {
|
||||
defaultReason = BadSignature
|
||||
} else {
|
||||
@ -237,7 +238,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
|
||||
} else if defaultGPGSettings == nil {
|
||||
log.Warn("Unable to get defaultGPGSettings for unattached commit: %s", c.ID.String())
|
||||
} else if defaultGPGSettings.Sign {
|
||||
if commitVerification := verifyWithGPGSettings(defaultGPGSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil {
|
||||
if commitVerification := verifyWithGPGSettings(ctx, defaultGPGSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil {
|
||||
if commitVerification.Reason == BadSignature {
|
||||
defaultReason = BadSignature
|
||||
} else {
|
||||
@ -257,9 +258,9 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
|
||||
}
|
||||
}
|
||||
|
||||
func verifyWithGPGSettings(gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *CommitVerification {
|
||||
func verifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *CommitVerification {
|
||||
// First try to find the key in the db
|
||||
if commitVerification := hashAndVerifyForKeyID(sig, payload, committer, gpgSettings.KeyID, gpgSettings.Name, gpgSettings.Email); commitVerification != nil {
|
||||
if commitVerification := hashAndVerifyForKeyID(ctx, sig, payload, committer, gpgSettings.KeyID, gpgSettings.Name, gpgSettings.Email); commitVerification != nil {
|
||||
return commitVerification
|
||||
}
|
||||
|
||||
@ -387,11 +388,11 @@ func hashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload s
|
||||
return nil
|
||||
}
|
||||
|
||||
func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *user_model.User, keyID, name, email string) *CommitVerification {
|
||||
func hashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload string, committer *user_model.User, keyID, name, email string) *CommitVerification {
|
||||
if keyID == "" {
|
||||
return nil
|
||||
}
|
||||
keys, err := GetGPGKeysByKeyID(keyID)
|
||||
keys, err := GetGPGKeysByKeyID(ctx, keyID)
|
||||
if err != nil {
|
||||
log.Error("GetGPGKeysByKeyID: %v", err)
|
||||
return &CommitVerification{
|
||||
@ -406,7 +407,7 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use
|
||||
for _, key := range keys {
|
||||
var primaryKeys []*GPGKey
|
||||
if key.PrimaryKeyID != "" {
|
||||
primaryKeys, err = GetGPGKeysByKeyID(key.PrimaryKeyID)
|
||||
primaryKeys, err = GetGPGKeysByKeyID(ctx, key.PrimaryKeyID)
|
||||
if err != nil {
|
||||
log.Error("GetGPGKeysByKeyID: %v", err)
|
||||
return &CommitVerification{
|
||||
@ -417,7 +418,7 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use
|
||||
}
|
||||
}
|
||||
|
||||
activated, email := checkKeyEmails(email, append([]*GPGKey{key}, primaryKeys...)...)
|
||||
activated, email := checkKeyEmails(ctx, email, append([]*GPGKey{key}, primaryKeys...)...)
|
||||
if !activated {
|
||||
continue
|
||||
}
|
||||
@ -427,7 +428,7 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use
|
||||
Email: email,
|
||||
}
|
||||
if key.OwnerID != 0 {
|
||||
owner, err := user_model.GetUserByID(db.DefaultContext, key.OwnerID)
|
||||
owner, err := user_model.GetUserByID(ctx, key.OwnerID)
|
||||
if err == nil {
|
||||
signer = owner
|
||||
} else if !user_model.IsErrUserNotExist(err) {
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"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/timeutil"
|
||||
@ -228,7 +229,7 @@ Q0KHb+QcycSgbDx0ZAvdIacuKvBBcbxrsmFUI4LR+oIup0G9gUc0roPvr014jYQL
|
||||
=zHo9
|
||||
-----END PGP PUBLIC KEY BLOCK-----`
|
||||
|
||||
keys, err := AddGPGKey(1, testEmailWithUpperCaseLetters, "", "")
|
||||
keys, err := AddGPGKey(db.DefaultContext, 1, testEmailWithUpperCaseLetters, "", "")
|
||||
assert.NoError(t, err)
|
||||
if assert.NotEmpty(t, keys) {
|
||||
key := keys[0]
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
package asymkey
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
@ -12,7 +11,6 @@ import (
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", ".."),
|
||||
FixtureFiles: []string{
|
||||
"gpg_key.yml",
|
||||
"public_key.yml",
|
||||
|
||||
@ -117,7 +117,7 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
|
||||
// RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again.
|
||||
// Note: db.GetEngine(db.DefaultContext).Iterate does not get latest data after insert/delete, so we have to call this function
|
||||
// outside any session scope independently.
|
||||
func RewriteAllPublicKeys() error {
|
||||
func RewriteAllPublicKeys(ctx context.Context) error {
|
||||
// Don't rewrite key if internal server
|
||||
if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
|
||||
return nil
|
||||
@ -165,7 +165,7 @@ func RewriteAllPublicKeys() error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := RegeneratePublicKeys(db.DefaultContext, t); err != nil {
|
||||
if err := RegeneratePublicKeys(ctx, t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ package asymkey
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@ -17,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
// ParseCommitWithSSHSignature check if signature is good against keystore.
|
||||
func ParseCommitWithSSHSignature(c *git.Commit, committer *user_model.User) *CommitVerification {
|
||||
func ParseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committer *user_model.User) *CommitVerification {
|
||||
// Now try to associate the signature with the committer, if present
|
||||
if committer.ID != 0 {
|
||||
keys, err := ListPublicKeys(committer.ID, db.ListOptions{})
|
||||
@ -30,7 +31,7 @@ func ParseCommitWithSSHSignature(c *git.Commit, committer *user_model.User) *Com
|
||||
}
|
||||
}
|
||||
|
||||
committerEmailAddresses, err := user_model.GetEmailAddresses(committer.ID)
|
||||
committerEmailAddresses, err := user_model.GetEmailAddresses(ctx, committer.ID)
|
||||
if err != nil {
|
||||
log.Error("GetEmailAddresses: %v", err)
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
package asymkey
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@ -63,7 +64,7 @@ func AddPrincipalKey(ownerID int64, content string, authSourceID int64) (*Public
|
||||
}
|
||||
|
||||
// CheckPrincipalKeyString strips spaces and returns an error if the given principal contains newlines
|
||||
func CheckPrincipalKeyString(user *user_model.User, content string) (_ string, err error) {
|
||||
func CheckPrincipalKeyString(ctx context.Context, user *user_model.User, content string) (_ string, err error) {
|
||||
if setting.SSH.Disabled {
|
||||
return "", db.ErrSSHDisabled{}
|
||||
}
|
||||
@ -80,7 +81,7 @@ func CheckPrincipalKeyString(user *user_model.User, content string) (_ string, e
|
||||
case "anything":
|
||||
return content, nil
|
||||
case "email":
|
||||
emails, err := user_model.GetEmailAddresses(user.ID)
|
||||
emails, err := user_model.GetEmailAddresses(ctx, user.ID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
@ -17,7 +16,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", ".."),
|
||||
})
|
||||
unittest.MainTest(m)
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
@ -22,8 +23,8 @@ func init() {
|
||||
}
|
||||
|
||||
// UpdateSession updates the session with provided id
|
||||
func UpdateSession(key string, data []byte) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).ID(key).Update(&Session{
|
||||
func UpdateSession(ctx context.Context, key string, data []byte) error {
|
||||
_, err := db.GetEngine(ctx).ID(key).Update(&Session{
|
||||
Data: data,
|
||||
Expiry: timeutil.TimeStampNow(),
|
||||
})
|
||||
@ -31,12 +32,12 @@ func UpdateSession(key string, data []byte) error {
|
||||
}
|
||||
|
||||
// ReadSession reads the data for the provided session
|
||||
func ReadSession(key string) (*Session, error) {
|
||||
func ReadSession(ctx context.Context, key string) (*Session, error) {
|
||||
session := Session{
|
||||
Key: key,
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -55,24 +56,24 @@ func ReadSession(key string) (*Session, error) {
|
||||
}
|
||||
|
||||
// ExistSession checks if a session exists
|
||||
func ExistSession(key string) (bool, error) {
|
||||
func ExistSession(ctx context.Context, key string) (bool, error) {
|
||||
session := Session{
|
||||
Key: key,
|
||||
}
|
||||
return db.GetEngine(db.DefaultContext).Get(&session)
|
||||
return db.GetEngine(ctx).Get(&session)
|
||||
}
|
||||
|
||||
// DestroySession destroys a session
|
||||
func DestroySession(key string) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Delete(&Session{
|
||||
func DestroySession(ctx context.Context, key string) error {
|
||||
_, err := db.GetEngine(ctx).Delete(&Session{
|
||||
Key: key,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// RegenerateSession regenerates a session from the old id
|
||||
func RegenerateSession(oldKey, newKey string) (*Session, error) {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func RegenerateSession(ctx context.Context, oldKey, newKey string) (*Session, error) {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -114,12 +115,12 @@ func RegenerateSession(oldKey, newKey string) (*Session, error) {
|
||||
}
|
||||
|
||||
// CountSessions returns the number of sessions
|
||||
func CountSessions() (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Count(&Session{})
|
||||
func CountSessions(ctx context.Context) (int64, error) {
|
||||
return db.GetEngine(ctx).Count(&Session{})
|
||||
}
|
||||
|
||||
// CleanupSessions cleans up expired sessions
|
||||
func CleanupSessions(maxLifetime int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Where("expiry <= ?", timeutil.TimeStampNow().Add(-maxLifetime)).Delete(&Session{})
|
||||
func CleanupSessions(ctx context.Context, maxLifetime int64) error {
|
||||
_, err := db.GetEngine(ctx).Where("expiry <= ?", timeutil.TimeStampNow().Add(-maxLifetime)).Delete(&Session{})
|
||||
return err
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/subtle"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
@ -95,7 +96,7 @@ func init() {
|
||||
}
|
||||
|
||||
// NewAccessToken creates new access token.
|
||||
func NewAccessToken(t *AccessToken) error {
|
||||
func NewAccessToken(ctx context.Context, t *AccessToken) error {
|
||||
salt, err := util.CryptoRandomString(10)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -108,7 +109,7 @@ func NewAccessToken(t *AccessToken) error {
|
||||
t.Token = hex.EncodeToString(token)
|
||||
t.TokenHash = HashToken(t.Token, t.TokenSalt)
|
||||
t.TokenLastEight = t.Token[len(t.Token)-8:]
|
||||
_, err = db.GetEngine(db.DefaultContext).Insert(t)
|
||||
_, err = db.GetEngine(ctx).Insert(t)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -137,7 +138,7 @@ func getAccessTokenIDFromCache(token string) int64 {
|
||||
}
|
||||
|
||||
// GetAccessTokenBySHA returns access token by given token value
|
||||
func GetAccessTokenBySHA(token string) (*AccessToken, error) {
|
||||
func GetAccessTokenBySHA(ctx context.Context, token string) (*AccessToken, error) {
|
||||
if token == "" {
|
||||
return nil, ErrAccessTokenEmpty{}
|
||||
}
|
||||
@ -158,7 +159,7 @@ func GetAccessTokenBySHA(token string) (*AccessToken, error) {
|
||||
TokenLastEight: lastEight,
|
||||
}
|
||||
// Re-get the token from the db in case it has been deleted in the intervening period
|
||||
has, err := db.GetEngine(db.DefaultContext).ID(id).Get(accessToken)
|
||||
has, err := db.GetEngine(ctx).ID(id).Get(accessToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -169,7 +170,7 @@ func GetAccessTokenBySHA(token string) (*AccessToken, error) {
|
||||
}
|
||||
|
||||
var tokens []AccessToken
|
||||
err := db.GetEngine(db.DefaultContext).Table(&AccessToken{}).Where("token_last_eight = ?", lastEight).Find(&tokens)
|
||||
err := db.GetEngine(ctx).Table(&AccessToken{}).Where("token_last_eight = ?", lastEight).Find(&tokens)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if len(tokens) == 0 {
|
||||
@ -189,8 +190,8 @@ func GetAccessTokenBySHA(token string) (*AccessToken, error) {
|
||||
}
|
||||
|
||||
// AccessTokenByNameExists checks if a token name has been used already by a user.
|
||||
func AccessTokenByNameExists(token *AccessToken) (bool, error) {
|
||||
return db.GetEngine(db.DefaultContext).Table("access_token").Where("name = ?", token.Name).And("uid = ?", token.UID).Exist()
|
||||
func AccessTokenByNameExists(ctx context.Context, token *AccessToken) (bool, error) {
|
||||
return db.GetEngine(ctx).Table("access_token").Where("name = ?", token.Name).And("uid = ?", token.UID).Exist()
|
||||
}
|
||||
|
||||
// ListAccessTokensOptions contain filter options
|
||||
@ -201,8 +202,8 @@ type ListAccessTokensOptions struct {
|
||||
}
|
||||
|
||||
// ListAccessTokens returns a list of access tokens belongs to given user.
|
||||
func ListAccessTokens(opts ListAccessTokensOptions) ([]*AccessToken, error) {
|
||||
sess := db.GetEngine(db.DefaultContext).Where("uid=?", opts.UserID)
|
||||
func ListAccessTokens(ctx context.Context, opts ListAccessTokensOptions) ([]*AccessToken, error) {
|
||||
sess := db.GetEngine(ctx).Where("uid=?", opts.UserID)
|
||||
|
||||
if len(opts.Name) != 0 {
|
||||
sess = sess.Where("name=?", opts.Name)
|
||||
@ -222,14 +223,14 @@ func ListAccessTokens(opts ListAccessTokensOptions) ([]*AccessToken, error) {
|
||||
}
|
||||
|
||||
// UpdateAccessToken updates information of access token.
|
||||
func UpdateAccessToken(t *AccessToken) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).ID(t.ID).AllCols().Update(t)
|
||||
func UpdateAccessToken(ctx context.Context, t *AccessToken) error {
|
||||
_, err := db.GetEngine(ctx).ID(t.ID).AllCols().Update(t)
|
||||
return err
|
||||
}
|
||||
|
||||
// CountAccessTokens count access tokens belongs to given user by options
|
||||
func CountAccessTokens(opts ListAccessTokensOptions) (int64, error) {
|
||||
sess := db.GetEngine(db.DefaultContext).Where("uid=?", opts.UserID)
|
||||
func CountAccessTokens(ctx context.Context, opts ListAccessTokensOptions) (int64, error) {
|
||||
sess := db.GetEngine(ctx).Where("uid=?", opts.UserID)
|
||||
if len(opts.Name) != 0 {
|
||||
sess = sess.Where("name=?", opts.Name)
|
||||
}
|
||||
@ -237,8 +238,8 @@ func CountAccessTokens(opts ListAccessTokensOptions) (int64, error) {
|
||||
}
|
||||
|
||||
// DeleteAccessTokenByID deletes access token by given ID.
|
||||
func DeleteAccessTokenByID(id, userID int64) error {
|
||||
cnt, err := db.GetEngine(db.DefaultContext).ID(id).Delete(&AccessToken{
|
||||
func DeleteAccessTokenByID(ctx context.Context, id, userID int64) error {
|
||||
cnt, err := db.GetEngine(ctx).ID(id).Delete(&AccessToken{
|
||||
UID: userID,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -18,7 +19,7 @@ func TestNewAccessToken(t *testing.T) {
|
||||
UID: 3,
|
||||
Name: "Token C",
|
||||
}
|
||||
assert.NoError(t, auth_model.NewAccessToken(token))
|
||||
assert.NoError(t, auth_model.NewAccessToken(db.DefaultContext, token))
|
||||
unittest.AssertExistsAndLoadBean(t, token)
|
||||
|
||||
invalidToken := &auth_model.AccessToken{
|
||||
@ -26,7 +27,7 @@ func TestNewAccessToken(t *testing.T) {
|
||||
UID: 2,
|
||||
Name: "Token F",
|
||||
}
|
||||
assert.Error(t, auth_model.NewAccessToken(invalidToken))
|
||||
assert.Error(t, auth_model.NewAccessToken(db.DefaultContext, invalidToken))
|
||||
}
|
||||
|
||||
func TestAccessTokenByNameExists(t *testing.T) {
|
||||
@ -39,16 +40,16 @@ func TestAccessTokenByNameExists(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check to make sure it doesn't exists already
|
||||
exist, err := auth_model.AccessTokenByNameExists(token)
|
||||
exist, err := auth_model.AccessTokenByNameExists(db.DefaultContext, token)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, exist)
|
||||
|
||||
// Save it to the database
|
||||
assert.NoError(t, auth_model.NewAccessToken(token))
|
||||
assert.NoError(t, auth_model.NewAccessToken(db.DefaultContext, token))
|
||||
unittest.AssertExistsAndLoadBean(t, token)
|
||||
|
||||
// This token must be found by name in the DB now
|
||||
exist, err = auth_model.AccessTokenByNameExists(token)
|
||||
exist, err = auth_model.AccessTokenByNameExists(db.DefaultContext, token)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, exist)
|
||||
|
||||
@ -59,32 +60,32 @@ func TestAccessTokenByNameExists(t *testing.T) {
|
||||
|
||||
// Name matches but different user ID, this shouldn't exists in the
|
||||
// database
|
||||
exist, err = auth_model.AccessTokenByNameExists(user4Token)
|
||||
exist, err = auth_model.AccessTokenByNameExists(db.DefaultContext, user4Token)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, exist)
|
||||
}
|
||||
|
||||
func TestGetAccessTokenBySHA(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
token, err := auth_model.GetAccessTokenBySHA("d2c6c1ba3890b309189a8e618c72a162e4efbf36")
|
||||
token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "d2c6c1ba3890b309189a8e618c72a162e4efbf36")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(1), token.UID)
|
||||
assert.Equal(t, "Token A", token.Name)
|
||||
assert.Equal(t, "2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f", token.TokenHash)
|
||||
assert.Equal(t, "e4efbf36", token.TokenLastEight)
|
||||
|
||||
_, err = auth_model.GetAccessTokenBySHA("notahash")
|
||||
_, err = auth_model.GetAccessTokenBySHA(db.DefaultContext, "notahash")
|
||||
assert.Error(t, err)
|
||||
assert.True(t, auth_model.IsErrAccessTokenNotExist(err))
|
||||
|
||||
_, err = auth_model.GetAccessTokenBySHA("")
|
||||
_, err = auth_model.GetAccessTokenBySHA(db.DefaultContext, "")
|
||||
assert.Error(t, err)
|
||||
assert.True(t, auth_model.IsErrAccessTokenEmpty(err))
|
||||
}
|
||||
|
||||
func TestListAccessTokens(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
tokens, err := auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 1})
|
||||
tokens, err := auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 1})
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, tokens, 2) {
|
||||
assert.Equal(t, int64(1), tokens[0].UID)
|
||||
@ -93,39 +94,39 @@ func TestListAccessTokens(t *testing.T) {
|
||||
assert.Contains(t, []string{tokens[0].Name, tokens[1].Name}, "Token B")
|
||||
}
|
||||
|
||||
tokens, err = auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 2})
|
||||
tokens, err = auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 2})
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, tokens, 1) {
|
||||
assert.Equal(t, int64(2), tokens[0].UID)
|
||||
assert.Equal(t, "Token A", tokens[0].Name)
|
||||
}
|
||||
|
||||
tokens, err = auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 100})
|
||||
tokens, err = auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 100})
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, tokens)
|
||||
}
|
||||
|
||||
func TestUpdateAccessToken(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
token, err := auth_model.GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c")
|
||||
token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "4c6f36e6cf498e2a448662f915d932c09c5a146c")
|
||||
assert.NoError(t, err)
|
||||
token.Name = "Token Z"
|
||||
|
||||
assert.NoError(t, auth_model.UpdateAccessToken(token))
|
||||
assert.NoError(t, auth_model.UpdateAccessToken(db.DefaultContext, token))
|
||||
unittest.AssertExistsAndLoadBean(t, token)
|
||||
}
|
||||
|
||||
func TestDeleteAccessTokenByID(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
token, err := auth_model.GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c")
|
||||
token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "4c6f36e6cf498e2a448662f915d932c09c5a146c")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(1), token.UID)
|
||||
|
||||
assert.NoError(t, auth_model.DeleteAccessTokenByID(token.ID, 1))
|
||||
assert.NoError(t, auth_model.DeleteAccessTokenByID(db.DefaultContext, token.ID, 1))
|
||||
unittest.AssertNotExistsBean(t, token)
|
||||
|
||||
err = auth_model.DeleteAccessTokenByID(100, 100)
|
||||
err = auth_model.DeleteAccessTokenByID(db.DefaultContext, 100, 100)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, auth_model.IsErrAccessTokenNotExist(err))
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/subtle"
|
||||
"encoding/base32"
|
||||
@ -121,22 +122,22 @@ func (t *TwoFactor) ValidateTOTP(passcode string) (bool, error) {
|
||||
}
|
||||
|
||||
// NewTwoFactor creates a new two-factor authentication token.
|
||||
func NewTwoFactor(t *TwoFactor) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Insert(t)
|
||||
func NewTwoFactor(ctx context.Context, t *TwoFactor) error {
|
||||
_, err := db.GetEngine(ctx).Insert(t)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateTwoFactor updates a two-factor authentication token.
|
||||
func UpdateTwoFactor(t *TwoFactor) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).ID(t.ID).AllCols().Update(t)
|
||||
func UpdateTwoFactor(ctx context.Context, t *TwoFactor) error {
|
||||
_, err := db.GetEngine(ctx).ID(t.ID).AllCols().Update(t)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetTwoFactorByUID returns the two-factor authentication token associated with
|
||||
// the user, if any.
|
||||
func GetTwoFactorByUID(uid int64) (*TwoFactor, error) {
|
||||
func GetTwoFactorByUID(ctx context.Context, uid int64) (*TwoFactor, error) {
|
||||
twofa := &TwoFactor{}
|
||||
has, err := db.GetEngine(db.DefaultContext).Where("uid=?", uid).Get(twofa)
|
||||
has, err := db.GetEngine(ctx).Where("uid=?", uid).Get(twofa)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
@ -147,13 +148,13 @@ func GetTwoFactorByUID(uid int64) (*TwoFactor, error) {
|
||||
|
||||
// HasTwoFactorByUID returns the two-factor authentication token associated with
|
||||
// the user, if any.
|
||||
func HasTwoFactorByUID(uid int64) (bool, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where("uid=?", uid).Exist(&TwoFactor{})
|
||||
func HasTwoFactorByUID(ctx context.Context, uid int64) (bool, error) {
|
||||
return db.GetEngine(ctx).Where("uid=?", uid).Exist(&TwoFactor{})
|
||||
}
|
||||
|
||||
// DeleteTwoFactorByID deletes two-factor authentication token by given ID.
|
||||
func DeleteTwoFactorByID(id, userID int64) error {
|
||||
cnt, err := db.GetEngine(db.DefaultContext).ID(id).Delete(&TwoFactor{
|
||||
func DeleteTwoFactorByID(ctx context.Context, id, userID int64) error {
|
||||
cnt, err := db.GetEngine(ctx).ID(id).Delete(&TwoFactor{
|
||||
UID: userID,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@ -67,11 +67,7 @@ func (cred WebAuthnCredential) TableName() string {
|
||||
}
|
||||
|
||||
// UpdateSignCount will update the database value of SignCount
|
||||
func (cred *WebAuthnCredential) UpdateSignCount() error {
|
||||
return cred.updateSignCount(db.DefaultContext)
|
||||
}
|
||||
|
||||
func (cred *WebAuthnCredential) updateSignCount(ctx context.Context) error {
|
||||
func (cred *WebAuthnCredential) UpdateSignCount(ctx context.Context) error {
|
||||
_, err := db.GetEngine(ctx).ID(cred.ID).Cols("sign_count").Update(cred)
|
||||
return err
|
||||
}
|
||||
@ -113,30 +109,18 @@ func (list WebAuthnCredentialList) ToCredentials() []webauthn.Credential {
|
||||
}
|
||||
|
||||
// GetWebAuthnCredentialsByUID returns all WebAuthn credentials of the given user
|
||||
func GetWebAuthnCredentialsByUID(uid int64) (WebAuthnCredentialList, error) {
|
||||
return getWebAuthnCredentialsByUID(db.DefaultContext, uid)
|
||||
}
|
||||
|
||||
func getWebAuthnCredentialsByUID(ctx context.Context, uid int64) (WebAuthnCredentialList, error) {
|
||||
func GetWebAuthnCredentialsByUID(ctx context.Context, uid int64) (WebAuthnCredentialList, error) {
|
||||
creds := make(WebAuthnCredentialList, 0)
|
||||
return creds, db.GetEngine(ctx).Where("user_id = ?", uid).Find(&creds)
|
||||
}
|
||||
|
||||
// ExistsWebAuthnCredentialsForUID returns if the given user has credentials
|
||||
func ExistsWebAuthnCredentialsForUID(uid int64) (bool, error) {
|
||||
return existsWebAuthnCredentialsByUID(db.DefaultContext, uid)
|
||||
}
|
||||
|
||||
func existsWebAuthnCredentialsByUID(ctx context.Context, uid int64) (bool, error) {
|
||||
func ExistsWebAuthnCredentialsForUID(ctx context.Context, uid int64) (bool, error) {
|
||||
return db.GetEngine(ctx).Where("user_id = ?", uid).Exist(&WebAuthnCredential{})
|
||||
}
|
||||
|
||||
// GetWebAuthnCredentialByName returns WebAuthn credential by id
|
||||
func GetWebAuthnCredentialByName(uid int64, name string) (*WebAuthnCredential, error) {
|
||||
return getWebAuthnCredentialByName(db.DefaultContext, uid, name)
|
||||
}
|
||||
|
||||
func getWebAuthnCredentialByName(ctx context.Context, uid int64, name string) (*WebAuthnCredential, error) {
|
||||
func GetWebAuthnCredentialByName(ctx context.Context, uid int64, name string) (*WebAuthnCredential, error) {
|
||||
cred := new(WebAuthnCredential)
|
||||
if found, err := db.GetEngine(ctx).Where("user_id = ? AND lower_name = ?", uid, strings.ToLower(name)).Get(cred); err != nil {
|
||||
return nil, err
|
||||
@ -147,11 +131,7 @@ func getWebAuthnCredentialByName(ctx context.Context, uid int64, name string) (*
|
||||
}
|
||||
|
||||
// GetWebAuthnCredentialByID returns WebAuthn credential by id
|
||||
func GetWebAuthnCredentialByID(id int64) (*WebAuthnCredential, error) {
|
||||
return getWebAuthnCredentialByID(db.DefaultContext, id)
|
||||
}
|
||||
|
||||
func getWebAuthnCredentialByID(ctx context.Context, id int64) (*WebAuthnCredential, error) {
|
||||
func GetWebAuthnCredentialByID(ctx context.Context, id int64) (*WebAuthnCredential, error) {
|
||||
cred := new(WebAuthnCredential)
|
||||
if found, err := db.GetEngine(ctx).ID(id).Get(cred); err != nil {
|
||||
return nil, err
|
||||
@ -162,16 +142,12 @@ func getWebAuthnCredentialByID(ctx context.Context, id int64) (*WebAuthnCredenti
|
||||
}
|
||||
|
||||
// HasWebAuthnRegistrationsByUID returns whether a given user has WebAuthn registrations
|
||||
func HasWebAuthnRegistrationsByUID(uid int64) (bool, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where("user_id = ?", uid).Exist(&WebAuthnCredential{})
|
||||
func HasWebAuthnRegistrationsByUID(ctx context.Context, uid int64) (bool, error) {
|
||||
return db.GetEngine(ctx).Where("user_id = ?", uid).Exist(&WebAuthnCredential{})
|
||||
}
|
||||
|
||||
// GetWebAuthnCredentialByCredID returns WebAuthn credential by credential ID
|
||||
func GetWebAuthnCredentialByCredID(userID int64, credID []byte) (*WebAuthnCredential, error) {
|
||||
return getWebAuthnCredentialByCredID(db.DefaultContext, userID, credID)
|
||||
}
|
||||
|
||||
func getWebAuthnCredentialByCredID(ctx context.Context, userID int64, credID []byte) (*WebAuthnCredential, error) {
|
||||
func GetWebAuthnCredentialByCredID(ctx context.Context, userID int64, credID []byte) (*WebAuthnCredential, error) {
|
||||
cred := new(WebAuthnCredential)
|
||||
if found, err := db.GetEngine(ctx).Where("user_id = ? AND credential_id = ?", userID, credID).Get(cred); err != nil {
|
||||
return nil, err
|
||||
@ -182,11 +158,7 @@ func getWebAuthnCredentialByCredID(ctx context.Context, userID int64, credID []b
|
||||
}
|
||||
|
||||
// CreateCredential will create a new WebAuthnCredential from the given Credential
|
||||
func CreateCredential(userID int64, name string, cred *webauthn.Credential) (*WebAuthnCredential, error) {
|
||||
return createCredential(db.DefaultContext, userID, name, cred)
|
||||
}
|
||||
|
||||
func createCredential(ctx context.Context, userID int64, name string, cred *webauthn.Credential) (*WebAuthnCredential, error) {
|
||||
func CreateCredential(ctx context.Context, userID int64, name string, cred *webauthn.Credential) (*WebAuthnCredential, error) {
|
||||
c := &WebAuthnCredential{
|
||||
UserID: userID,
|
||||
Name: name,
|
||||
@ -205,18 +177,14 @@ func createCredential(ctx context.Context, userID int64, name string, cred *weba
|
||||
}
|
||||
|
||||
// DeleteCredential will delete WebAuthnCredential
|
||||
func DeleteCredential(id, userID int64) (bool, error) {
|
||||
return deleteCredential(db.DefaultContext, id, userID)
|
||||
}
|
||||
|
||||
func deleteCredential(ctx context.Context, id, userID int64) (bool, error) {
|
||||
func DeleteCredential(ctx context.Context, id, userID int64) (bool, error) {
|
||||
had, err := db.GetEngine(ctx).ID(id).Where("user_id = ?", userID).Delete(&WebAuthnCredential{})
|
||||
return had > 0, err
|
||||
}
|
||||
|
||||
// WebAuthnCredentials implementns the webauthn.User interface
|
||||
func WebAuthnCredentials(userID int64) ([]webauthn.Credential, error) {
|
||||
dbCreds, err := GetWebAuthnCredentialsByUID(userID)
|
||||
func WebAuthnCredentials(ctx context.Context, userID int64) ([]webauthn.Credential, error) {
|
||||
dbCreds, err := GetWebAuthnCredentialsByUID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
@ -16,11 +17,11 @@ import (
|
||||
func TestGetWebAuthnCredentialByID(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
res, err := auth_model.GetWebAuthnCredentialByID(1)
|
||||
res, err := auth_model.GetWebAuthnCredentialByID(db.DefaultContext, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "WebAuthn credential", res.Name)
|
||||
|
||||
_, err = auth_model.GetWebAuthnCredentialByID(342432)
|
||||
_, err = auth_model.GetWebAuthnCredentialByID(db.DefaultContext, 342432)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, auth_model.IsErrWebAuthnCredentialNotExist(err))
|
||||
}
|
||||
@ -28,7 +29,7 @@ func TestGetWebAuthnCredentialByID(t *testing.T) {
|
||||
func TestGetWebAuthnCredentialsByUID(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
res, err := auth_model.GetWebAuthnCredentialsByUID(32)
|
||||
res, err := auth_model.GetWebAuthnCredentialsByUID(db.DefaultContext, 32)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, res, 1)
|
||||
assert.Equal(t, "WebAuthn credential", res[0].Name)
|
||||
@ -42,7 +43,7 @@ func TestWebAuthnCredential_UpdateSignCount(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1})
|
||||
cred.SignCount = 1
|
||||
assert.NoError(t, cred.UpdateSignCount())
|
||||
assert.NoError(t, cred.UpdateSignCount(db.DefaultContext))
|
||||
unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 1})
|
||||
}
|
||||
|
||||
@ -50,14 +51,14 @@ func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1})
|
||||
cred.SignCount = 0xffffffff
|
||||
assert.NoError(t, cred.UpdateSignCount())
|
||||
assert.NoError(t, cred.UpdateSignCount(db.DefaultContext))
|
||||
unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 0xffffffff})
|
||||
}
|
||||
|
||||
func TestCreateCredential(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
res, err := auth_model.CreateCredential(1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test")})
|
||||
res, err := auth_model.CreateCredential(db.DefaultContext, 1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test")})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "WebAuthn Created Credential", res.Name)
|
||||
assert.Equal(t, []byte("Test"), res.CredentialID)
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
package avatars_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
@ -15,7 +14,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", ".."),
|
||||
})
|
||||
unittest.MainTest(m)
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
package db_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
@ -14,7 +13,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", ".."),
|
||||
})
|
||||
unittest.MainTest(m)
|
||||
}
|
||||
|
||||
@ -4,14 +4,11 @@
|
||||
package paginator
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", "..", ".."),
|
||||
})
|
||||
unittest.MainTest(m)
|
||||
}
|
||||
|
||||
@ -4,14 +4,11 @@
|
||||
package dbfs
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", ".."),
|
||||
})
|
||||
unittest.MainTest(m)
|
||||
}
|
||||
|
||||
@ -40,7 +40,9 @@ func GetYamlFixturesAccess() (string, error) {
|
||||
fmt.Fprintf(&b, " user_id: %d\n", a.UserID)
|
||||
fmt.Fprintf(&b, " repo_id: %d\n", a.RepoID)
|
||||
fmt.Fprintf(&b, " mode: %d\n", a.Mode)
|
||||
fmt.Fprintf(&b, "\n")
|
||||
if i < len(accesses)-1 {
|
||||
fmt.Fprintf(&b, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
return b.String(), nil
|
||||
|
||||
@ -22,12 +22,13 @@ func TestFixtureGeneration(t *testing.T) {
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
bytes, err := os.ReadFile(filepath.Join(unittest.FixturesDir(), name+".yml"))
|
||||
p := filepath.Join(unittest.FixturesDir(), name+".yml")
|
||||
bytes, err := os.ReadFile(p)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
data := string(util.NormalizeEOL(bytes))
|
||||
assert.True(t, data == expected, "Differences detected for %s.yml", name)
|
||||
assert.EqualValues(t, expected, data, "Differences detected for %s", p)
|
||||
}
|
||||
|
||||
test(GetYamlFixturesAccess, "access")
|
||||
|
||||
@ -135,4 +135,3 @@
|
||||
user_id: 31
|
||||
repo_id: 28
|
||||
mode: 4
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
id: 1
|
||||
uid: 1
|
||||
name: Token A
|
||||
#token: d2c6c1ba3890b309189a8e618c72a162e4efbf36
|
||||
# token: d2c6c1ba3890b309189a8e618c72a162e4efbf36
|
||||
token_hash: 2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f
|
||||
token_salt: QuSiZr1byZ
|
||||
token_last_eight: e4efbf36
|
||||
@ -13,7 +13,7 @@
|
||||
id: 2
|
||||
uid: 1
|
||||
name: Token B
|
||||
#token: 4c6f36e6cf498e2a448662f915d932c09c5a146c
|
||||
# token: 4c6f36e6cf498e2a448662f915d932c09c5a146c
|
||||
token_hash: 1a0e32a231ebbd582dc626c1543a42d3c63d4fa76c07c72862721467c55e8f81c923d60700f0528b5f5f443f055559d3a279
|
||||
token_salt: Lfwopukrq5
|
||||
token_last_eight: 9c5a146c
|
||||
@ -24,10 +24,10 @@
|
||||
id: 3
|
||||
uid: 2
|
||||
name: Token A
|
||||
#token: 90a18faa671dc43924b795806ffe4fd169d28c91
|
||||
# token: 90a18faa671dc43924b795806ffe4fd169d28c91
|
||||
token_hash: d6d404048048812d9e911d93aefbe94fc768d4876fdf75e3bef0bdc67828e0af422846d3056f2f25ec35c51dc92075685ec5
|
||||
token_salt: 99ArgXKlQQ
|
||||
token_last_eight: 69d28c91
|
||||
created_unix: 946687980
|
||||
updated_unix: 946687980
|
||||
#commented out tokens so you can see what they are in plaintext
|
||||
# commented out tokens so you can see what they are in plaintext
|
||||
|
||||
@ -140,3 +140,16 @@
|
||||
download_count: 0
|
||||
size: 0
|
||||
created_unix: 946684800
|
||||
|
||||
-
|
||||
id: 12
|
||||
uuid: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a22
|
||||
repo_id: 2
|
||||
issue_id: 0
|
||||
release_id: 11
|
||||
uploader_id: 2
|
||||
comment_id: 0
|
||||
name: README.md
|
||||
download_count: 0
|
||||
size: 0
|
||||
created_unix: 946684800
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
id: 1
|
||||
repo_id: 1
|
||||
sha: "1234123412341234123412341234123412341234"
|
||||
max_index: 5
|
||||
max_index: 5
|
||||
|
||||
@ -321,3 +321,20 @@
|
||||
created_unix: 946684830
|
||||
updated_unix: 978307200
|
||||
is_locked: false
|
||||
|
||||
-
|
||||
id: 20
|
||||
repo_id: 23
|
||||
index: 1
|
||||
poster_id: 2
|
||||
original_author_id: 0
|
||||
name: issue for pr
|
||||
content: content
|
||||
milestone_id: 0
|
||||
priority: 0
|
||||
is_closed: false
|
||||
is_pull: true
|
||||
num_comments: 0
|
||||
created_unix: 978307210
|
||||
updated_unix: 978307210
|
||||
is_locked: false
|
||||
|
||||
@ -8,4 +8,4 @@
|
||||
type: 1
|
||||
created_unix: 1559593109
|
||||
updated_unix: 1565224552
|
||||
login_source_id: 0
|
||||
login_source_id: 0
|
||||
|
||||
@ -89,3 +89,12 @@
|
||||
base_branch: main
|
||||
merge_base: cbff181af4c9c7fee3cf6c106699e07d9a3f54e6
|
||||
has_merged: false
|
||||
|
||||
-
|
||||
id: 8
|
||||
type: 0 # gitea pull request
|
||||
status: 2 # mergable
|
||||
issue_id: 20
|
||||
index: 1
|
||||
head_repo_id: 23
|
||||
base_repo_id: 23
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
-
|
||||
id: 1 #issue reaction
|
||||
id: 1 # issue reaction
|
||||
type: zzz # not allowed reaction (added before allowed reaction list has changed)
|
||||
issue_id: 1
|
||||
comment_id: 0
|
||||
@ -7,7 +7,7 @@
|
||||
created_unix: 1573248001
|
||||
|
||||
-
|
||||
id: 2 #issue reaction
|
||||
id: 2 # issue reaction
|
||||
type: zzz # not allowed reaction (added before allowed reaction list has changed)
|
||||
issue_id: 1
|
||||
comment_id: 0
|
||||
@ -15,7 +15,7 @@
|
||||
created_unix: 1573248002
|
||||
|
||||
-
|
||||
id: 3 #issue reaction
|
||||
id: 3 # issue reaction
|
||||
type: eyes # allowed reaction
|
||||
issue_id: 1
|
||||
comment_id: 0
|
||||
@ -23,7 +23,7 @@
|
||||
created_unix: 1573248003
|
||||
|
||||
-
|
||||
id: 4 #comment reaction
|
||||
id: 4 # comment reaction
|
||||
type: laugh # allowed reaction
|
||||
issue_id: 1
|
||||
comment_id: 2
|
||||
@ -31,7 +31,7 @@
|
||||
created_unix: 1573248004
|
||||
|
||||
-
|
||||
id: 5 #comment reaction
|
||||
id: 5 # comment reaction
|
||||
type: laugh # allowed reaction
|
||||
issue_id: 1
|
||||
comment_id: 2
|
||||
|
||||
@ -136,3 +136,17 @@
|
||||
is_prerelease: false
|
||||
is_tag: false
|
||||
created_unix: 946684803
|
||||
|
||||
- id: 11
|
||||
repo_id: 2
|
||||
publisher_id: 2
|
||||
tag_name: "v1.1"
|
||||
lower_tag_name: "v1.1"
|
||||
target: ""
|
||||
title: "v1.1"
|
||||
sha1: "205ac761f3326a7ebe416e8673760016450b5cec"
|
||||
num_commits: 2
|
||||
is_draft: false
|
||||
is_prerelease: false
|
||||
is_tag: false
|
||||
created_unix: 946684803
|
||||
|
||||
@ -649,3 +649,23 @@
|
||||
repo_id: 49
|
||||
type: 2
|
||||
created_unix: 946684810
|
||||
|
||||
-
|
||||
id: 98
|
||||
repo_id: 1
|
||||
type: 8
|
||||
created_unix: 946684810
|
||||
|
||||
-
|
||||
id: 99
|
||||
repo_id: 1
|
||||
type: 9
|
||||
config: "{}"
|
||||
created_unix: 946684810
|
||||
|
||||
-
|
||||
id: 100
|
||||
repo_id: 1
|
||||
type: 10
|
||||
config: "{}"
|
||||
created_unix: 946684810
|
||||
|
||||
@ -679,7 +679,7 @@
|
||||
num_forks: 0
|
||||
num_issues: 0
|
||||
num_closed_issues: 0
|
||||
num_pulls: 0
|
||||
num_pulls: 1
|
||||
num_closed_pulls: 0
|
||||
num_milestones: 0
|
||||
num_closed_milestones: 0
|
||||
|
||||
@ -132,3 +132,41 @@
|
||||
content: "singular review from org6 and final review for this pr"
|
||||
updated_unix: 946684831
|
||||
created_unix: 946684831
|
||||
|
||||
-
|
||||
id: 16
|
||||
type: 4
|
||||
reviewer_id: 20
|
||||
issue_id: 20
|
||||
content: "review request for user20"
|
||||
updated_unix: 946684832
|
||||
created_unix: 946684832
|
||||
|
||||
-
|
||||
id: 17
|
||||
type: 1
|
||||
reviewer_id: 20
|
||||
issue_id: 20
|
||||
content: "review approved by user20"
|
||||
updated_unix: 946684833
|
||||
created_unix: 946684833
|
||||
|
||||
-
|
||||
id: 18
|
||||
type: 4
|
||||
reviewer_id: 0
|
||||
reviewer_team_id: 5
|
||||
issue_id: 20
|
||||
content: "review request for team5"
|
||||
updated_unix: 946684834
|
||||
created_unix: 946684834
|
||||
|
||||
-
|
||||
id: 19
|
||||
type: 4
|
||||
reviewer_id: 15
|
||||
reviewer_team_id: 0
|
||||
issue_id: 20
|
||||
content: "review request for user15"
|
||||
updated_unix: 946684835
|
||||
created_unix: 946684835
|
||||
|
||||
@ -93,7 +93,7 @@
|
||||
name: review_team
|
||||
authorize: 1 # read
|
||||
num_repos: 1
|
||||
num_members: 2
|
||||
num_members: 3
|
||||
includes_all_repositories: false
|
||||
can_create_org_repo: false
|
||||
|
||||
|
||||
@ -62,4 +62,4 @@
|
||||
id: 11
|
||||
org_id: 17
|
||||
team_id: 9
|
||||
repo_id: 24
|
||||
repo_id: 24
|
||||
|
||||
@ -123,3 +123,9 @@
|
||||
org_id: 36
|
||||
team_id: 20
|
||||
uid: 5
|
||||
|
||||
-
|
||||
id: 22
|
||||
org_id: 17
|
||||
team_id: 9
|
||||
uid: 15
|
||||
|
||||
@ -26,4 +26,4 @@
|
||||
id: 5
|
||||
user_id: 11
|
||||
repo_id: 1
|
||||
mode: 3 # auto
|
||||
mode: 3 # auto
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user