Compare commits
55 Commits
main
...
knacker_wo
Author | SHA1 | Date | |
---|---|---|---|
|
8c5c2a2ce9 | ||
|
e77b76425e | ||
|
1d52228ee7 | ||
|
371dd96e3e | ||
|
c8b217110b | ||
|
1c7496c7a7 | ||
|
2e5ac53bdc | ||
|
2836382f34 | ||
|
c2fb27beb4 | ||
|
e4eaa68a2b | ||
|
b4802b9b2e | ||
|
9380bb6d0c | ||
|
43aafc5ba1 | ||
|
32db62515f | ||
|
d3f850cc0e | ||
|
c8f3eb6acb | ||
|
eec1c71880 | ||
|
044c754ea5 | ||
|
fefdb7ffd1 | ||
|
595d940daa | ||
|
6da8bc6be9 | ||
|
20385b52a3 | ||
|
0b993a0d04 | ||
|
6dbcf724ac | ||
|
88d5275614 | ||
|
43ab9324c5 | ||
|
c144942b23 | ||
|
92dd24716d | ||
|
f311d15a0b | ||
|
40229a7dd8 | ||
|
6c8ff32511 | ||
|
c772934ff6 | ||
|
de6dfb7141 | ||
|
55115dbb73 | ||
|
d9ba7f7442 | ||
|
3e3975e0fa | ||
|
8ce2dd588a | ||
|
0ace4cee33 | ||
|
6f3efdfe11 | ||
|
bea25d77ce | ||
|
34283a74e8 | ||
|
a0a425a13b | ||
|
158b088ec3 | ||
|
aed1622766 | ||
|
bf2078640f | ||
|
9f8e778918 | ||
|
9db221780f | ||
|
50dd32ede4 | ||
|
2cbea23d70 | ||
|
fb704f6c72 | ||
|
92525ddffd | ||
|
1d22911cfe | ||
|
385462d36c | ||
|
ce5aafbc69 | ||
|
99688ef994 |
114
.dockerignore
Normal file
114
.dockerignore
Normal file
@ -0,0 +1,114 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
# Goland's output filename can not be set manually
|
||||
/go_build_*
|
||||
|
||||
# MS VSCode
|
||||
.vscode
|
||||
__debug_bin
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
*coverage.out
|
||||
coverage.all
|
||||
cpu.out
|
||||
|
||||
/modules/migration/bindata.go
|
||||
/modules/migration/bindata.go.hash
|
||||
/modules/options/bindata.go
|
||||
/modules/options/bindata.go.hash
|
||||
/modules/public/bindata.go
|
||||
/modules/public/bindata.go.hash
|
||||
/modules/templates/bindata.go
|
||||
/modules/templates/bindata.go.hash
|
||||
|
||||
*.db
|
||||
*.log
|
||||
|
||||
/gitea
|
||||
/gitea-vet
|
||||
/debug
|
||||
/integrations.test
|
||||
|
||||
/bin
|
||||
/dist
|
||||
/custom/*
|
||||
!/custom/conf
|
||||
/custom/conf/*
|
||||
!/custom/conf/app.example.ini
|
||||
/data
|
||||
/indexers
|
||||
/log
|
||||
/public/img/avatar
|
||||
/tests/integration/gitea-integration-*
|
||||
/tests/integration/indexers-*
|
||||
/tests/e2e/gitea-e2e-*
|
||||
/tests/e2e/indexers-*
|
||||
/tests/e2e/reports
|
||||
/tests/e2e/test-artifacts
|
||||
/tests/e2e/test-snapshots
|
||||
/tests/*.ini
|
||||
/node_modules
|
||||
/yarn.lock
|
||||
/yarn-error.log
|
||||
/npm-debug.log*
|
||||
/public/js
|
||||
/public/serviceworker.js
|
||||
/public/css
|
||||
/public/fonts
|
||||
/public/img/webpack
|
||||
/vendor
|
||||
/web_src/fomantic/node_modules
|
||||
/web_src/fomantic/build/*
|
||||
!/web_src/fomantic/build/semantic.js
|
||||
!/web_src/fomantic/build/semantic.css
|
||||
!/web_src/fomantic/build/themes
|
||||
/web_src/fomantic/build/themes/*
|
||||
!/web_src/fomantic/build/themes/default
|
||||
/web_src/fomantic/build/themes/default/assets/*
|
||||
!/web_src/fomantic/build/themes/default/assets/fonts
|
||||
/web_src/fomantic/build/themes/default/assets/fonts/*
|
||||
!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2
|
||||
!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2
|
||||
/VERSION
|
||||
/.air
|
||||
/.go-licenses
|
||||
|
||||
# Snapcraft
|
||||
snap/.snapcraft/
|
||||
parts/
|
||||
stage/
|
||||
prime/
|
||||
*.snap
|
||||
*.snap-build
|
||||
*_source.tar.bz2
|
||||
.DS_Store
|
||||
|
||||
# Make evidence files
|
||||
/.make_evidence
|
||||
|
||||
# Manpage
|
||||
/man
|
12
.drone.yml
12
.drone.yml
@ -39,16 +39,6 @@ steps:
|
||||
- make lint-frontend
|
||||
depends_on: [deps-frontend]
|
||||
|
||||
- name: security-check
|
||||
image: golang:1.19
|
||||
pull: always
|
||||
commands:
|
||||
- make security-check
|
||||
depends_on: [deps-backend]
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go
|
||||
|
||||
- name: lint-backend
|
||||
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
|
||||
pull: always
|
||||
@ -561,7 +551,7 @@ steps:
|
||||
|
||||
# TODO: We should probably build all dependencies into a test image
|
||||
- name: test-e2e
|
||||
image: mcr.microsoft.com/playwright:v1.27.1-focal
|
||||
image: mcr.microsoft.com/playwright:v1.28.0-focal
|
||||
commands:
|
||||
- curl -sLO https://go.dev/dl/go1.19.linux-amd64.tar.gz && tar -C /usr/local -xzf go1.19.linux-amd64.tar.gz
|
||||
- groupadd --gid 1001 gitea && useradd -m --gid 1001 --uid 1001 gitea
|
||||
|
@ -199,7 +199,7 @@ rules:
|
||||
newline-per-chained-call: [0]
|
||||
no-alert: [0]
|
||||
no-array-constructor: [2]
|
||||
no-async-promise-executor: [2]
|
||||
no-async-promise-executor: [0]
|
||||
no-await-in-loop: [0]
|
||||
no-bitwise: [0]
|
||||
no-buffer-constructor: [0]
|
||||
@ -229,6 +229,7 @@ rules:
|
||||
no-empty-character-class: [2]
|
||||
no-empty-function: [0]
|
||||
no-empty-pattern: [2]
|
||||
no-empty-static-block: [2]
|
||||
no-empty: [2, {allowEmptyCatch: true}]
|
||||
no-eq-null: [2]
|
||||
no-eval: [2]
|
||||
@ -269,6 +270,7 @@ rules:
|
||||
no-negated-condition: [0]
|
||||
no-nested-ternary: [0]
|
||||
no-new-func: [2]
|
||||
no-new-native-nonconstructor: [2]
|
||||
no-new-object: [2]
|
||||
no-new-symbol: [2]
|
||||
no-new-wrappers: [2]
|
||||
@ -443,6 +445,7 @@ rules:
|
||||
unicorn/no-invalid-remove-event-listener: [2]
|
||||
unicorn/no-keyword-prefix: [0]
|
||||
unicorn/no-lonely-if: [2]
|
||||
unicorn/no-negated-condition: [0]
|
||||
unicorn/no-nested-ternary: [0]
|
||||
unicorn/no-new-array: [0]
|
||||
unicorn/no-new-buffer: [0]
|
||||
@ -453,6 +456,7 @@ rules:
|
||||
unicorn/no-static-only-class: [2]
|
||||
unicorn/no-thenable: [2]
|
||||
unicorn/no-this-assignment: [2]
|
||||
unicorn/no-typeof-undefined: [2]
|
||||
unicorn/no-unnecessary-await: [2]
|
||||
unicorn/no-unreadable-array-destructuring: [0]
|
||||
unicorn/no-unreadable-iife: [2]
|
||||
@ -503,6 +507,7 @@ rules:
|
||||
unicorn/prefer-regexp-test: [2]
|
||||
unicorn/prefer-replace-all: [0]
|
||||
unicorn/prefer-set-has: [0]
|
||||
unicorn/prefer-set-size: [2]
|
||||
unicorn/prefer-spread: [0]
|
||||
unicorn/prefer-starts-ends-with: [2]
|
||||
unicorn/prefer-string-slice: [0]
|
||||
|
4
Makefile
4
Makefile
@ -333,7 +333,7 @@ checks: checks-frontend checks-backend
|
||||
checks-frontend: lockfile-check svg-check
|
||||
|
||||
.PHONY: checks-backend
|
||||
checks-backend: tidy-check swagger-check fmt-check misspell-check swagger-validate
|
||||
checks-backend: tidy-check swagger-check fmt-check misspell-check swagger-validate security-check
|
||||
|
||||
.PHONY: lint
|
||||
lint: lint-frontend lint-backend
|
||||
@ -745,7 +745,7 @@ generate-go: $(TAGS_PREREQ)
|
||||
|
||||
.PHONY: security-check
|
||||
security-check:
|
||||
govulncheck -v ./...
|
||||
go run $(GOVULNCHECK_PACKAGE) -v ./...
|
||||
|
||||
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
|
||||
|
10
cmd/admin.go
10
cmd/admin.go
@ -413,9 +413,9 @@ var (
|
||||
Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "addr",
|
||||
Name: "host",
|
||||
Value: "",
|
||||
Usage: "SMTP Addr",
|
||||
Usage: "SMTP Host",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "port",
|
||||
@ -727,7 +727,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
|
||||
|
||||
log.Trace("Synchronizing repository releases (this may take a while)")
|
||||
for page := 1; ; page++ {
|
||||
repos, count, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
|
||||
repos, count, err := repo_model.SearchRepositoryByName(ctx, &repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
PageSize: repo_model.RepositoryListDefaultPageSize,
|
||||
Page: page,
|
||||
@ -955,8 +955,8 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
|
||||
}
|
||||
conf.Auth = c.String("auth-type")
|
||||
}
|
||||
if c.IsSet("addr") {
|
||||
conf.Addr = c.String("addr")
|
||||
if c.IsSet("host") {
|
||||
conf.Host = c.String("host")
|
||||
}
|
||||
if c.IsSet("port") {
|
||||
conf.Port = c.Int("port")
|
||||
|
@ -7,6 +7,38 @@
|
||||
;; see https://docs.gitea.io/en-us/config-cheat-sheet/ for additional documentation.
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Default Configuration (non-`app.ini` configuration)
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; These values are environment-dependent but form the basis of a lot of values. They will be
|
||||
;; reported as part of the default configuration when running `gitea --help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up.
|
||||
;;
|
||||
;; - _`AppPath`_: This is the absolute path of the running gitea binary.
|
||||
;; - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy:
|
||||
;; - The `--work-path` flag passed to the binary
|
||||
;; - The environment variable `$GITEA_WORK_DIR`
|
||||
;; - A built-in value set at build time (see building from source)
|
||||
;; - Otherwise it defaults to the directory of the _`AppPath`_
|
||||
;; - If any of the above are relative paths then they are made absolute against the
|
||||
;; the directory of the _`AppPath`_
|
||||
;; - _`CustomPath`_: This is the base directory for custom templates and other options.
|
||||
;; It is determined by using the first set thing in the following hierarchy:
|
||||
;; - The `--custom-path` flag passed to the binary
|
||||
;; - The environment variable `$GITEA_CUSTOM`
|
||||
;; - A built-in value set at build time (see building from source)
|
||||
;; - Otherwise it defaults to _`AppWorkPath`_`/custom`
|
||||
;; - If any of the above are relative paths then they are made absolute against the
|
||||
;; the directory of the _`AppWorkPath`_
|
||||
;; - _`CustomConf`_: This is the path to the `app.ini` file.
|
||||
;; - The `--config` flag passed to the binary
|
||||
;; - A built-in value set at build time (see building from source)
|
||||
;; - Otherwise it defaults to _`CustomPath`_`/conf/app.ini`
|
||||
;; - If any of the above are relative paths then they are made absolute against the
|
||||
;; the directory of the _`CustomPath`_
|
||||
;;
|
||||
;; In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; General Settings
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@ -26,7 +58,7 @@ RUN_MODE = ; prod
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; The protocol the server listens on. One of 'http', 'https', 'unix' or 'fcgi'. Defaults to 'http'
|
||||
;; The protocol the server listens on. One of 'http', 'https', 'http+unix', 'fcgi' or 'fcgi+unix'. Defaults to 'http'
|
||||
;PROTOCOL = http
|
||||
;;
|
||||
;; Expect PROXY protocol headers on connections
|
||||
@ -51,6 +83,8 @@ RUN_MODE = ; prod
|
||||
;STATIC_URL_PREFIX =
|
||||
;;
|
||||
;; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket.
|
||||
;; If PROTOCOL is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use.
|
||||
;; Relative paths will be made absolute against the _`AppWorkPath`_.
|
||||
;HTTP_ADDR = 0.0.0.0
|
||||
;;
|
||||
;; The port to listen on. Leave empty when using a unix socket.
|
||||
@ -64,7 +98,7 @@ RUN_MODE = ; prod
|
||||
;PORT_TO_REDIRECT = 80
|
||||
;;
|
||||
;; expect PROXY protocol header on connections to https redirector.
|
||||
;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)
|
||||
;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s
|
||||
;; Minimum and maximum supported TLS versions
|
||||
;SSL_MIN_VERSION=TLSv1.2
|
||||
;SSL_MAX_VERSION=
|
||||
@ -91,7 +125,7 @@ RUN_MODE = ; prod
|
||||
;LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
|
||||
;;
|
||||
;; When making local connections pass the PROXY protocol header.
|
||||
;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)
|
||||
;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s
|
||||
;;
|
||||
;; Disable SSH feature when not available
|
||||
;DISABLE_SSH = false
|
||||
@ -145,7 +179,7 @@ RUN_MODE = ; prod
|
||||
;;
|
||||
;; For the built-in SSH server, choose the keypair to offer as the host key
|
||||
;; The private key should be at SSH_SERVER_HOST_KEY and the public SSH_SERVER_HOST_KEY.pub
|
||||
;; relative paths are made absolute relative to the APP_DATA_PATH
|
||||
;; relative paths are made absolute relative to the %(APP_DATA_PATH)s
|
||||
;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa
|
||||
;;
|
||||
;; Directory to create temporary files in when testing public keys using ssh-keygen,
|
||||
@ -241,10 +275,10 @@ RUN_MODE = ; prod
|
||||
;;
|
||||
;; Root directory containing templates and static files.
|
||||
;; default is the path where Gitea is executed
|
||||
;STATIC_ROOT_PATH =
|
||||
;STATIC_ROOT_PATH = ; Will default to the built-in value _`StaticRootPath`_
|
||||
;;
|
||||
;; Default path for App data
|
||||
;APP_DATA_PATH = data
|
||||
;APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_
|
||||
;;
|
||||
;; Enable gzip compression for runtime-generated content, static resources excluded
|
||||
;ENABLE_GZIP = false
|
||||
@ -255,7 +289,7 @@ RUN_MODE = ; prod
|
||||
;ENABLE_PPROF = false
|
||||
;;
|
||||
;; PPROF_DATA_PATH, use an absolute path when you start gitea as service
|
||||
;PPROF_DATA_PATH = data/tmp/pprof
|
||||
;PPROF_DATA_PATH = data/tmp/pprof ; Path is relative to _`AppWorkPath`_
|
||||
;;
|
||||
;; Landing page, can be "home", "explore", "organizations", "login", or any URL such as "/org/repo" or even "https://anotherwebsite.com"
|
||||
;; The "login" choice is not a security measure but just a UI flow change, use REQUIRE_SIGNIN_VIEW to force users to log in.
|
||||
@ -633,7 +667,7 @@ ROUTER = console
|
||||
;PATH =
|
||||
;;
|
||||
;; The HOME directory for Git
|
||||
;HOME_PATH = %(APP_DATA_PATH)/home
|
||||
;HOME_PATH = %(APP_DATA_PATH)s/home
|
||||
;;
|
||||
;; Disables highlight of added and removed changes
|
||||
;DISABLE_DIFF_HIGHLIGHT = false
|
||||
@ -838,8 +872,8 @@ ROUTER = console
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;[repository]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)/gitea-repositories.
|
||||
;; A relative path is interpreted as %(GITEA_WORK_DIR)/%(ROOT)
|
||||
;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)s/gitea-repositories.
|
||||
;; A relative path is interpreted as _`AppWorkPath`_/%(ROOT)s
|
||||
;ROOT =
|
||||
;;
|
||||
;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available.
|
||||
@ -1104,6 +1138,9 @@ ROUTER = console
|
||||
;; allow request with credentials
|
||||
;ALLOW_CREDENTIALS = false
|
||||
;;
|
||||
;; headers to permit
|
||||
;HEADERS = Content-Type,User-Agent
|
||||
;;
|
||||
;; set X-FRAME-OPTIONS header
|
||||
;X_FRAME_OPTIONS = SAMEORIGIN
|
||||
|
||||
@ -1296,7 +1333,7 @@ ROUTER = console
|
||||
;ISSUE_INDEXER_TYPE = bleve
|
||||
;;
|
||||
;; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve
|
||||
;ISSUE_INDEXER_PATH = indexers/issues.bleve
|
||||
;ISSUE_INDEXER_PATH = indexers/issues.bleve ; Relative paths will be made absolute against _`AppWorkPath`_.
|
||||
;;
|
||||
;; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch
|
||||
;ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
|
||||
@ -1314,7 +1351,7 @@ ROUTER = console
|
||||
;; When ISSUE_INDEXER_QUEUE_TYPE is levelqueue, this will be the path where the queue will be saved.
|
||||
;; This can be overridden by `ISSUE_INDEXER_QUEUE_CONN_STR`.
|
||||
;; default is queues/common
|
||||
;ISSUE_INDEXER_QUEUE_DIR = queues/common; **DEPRECATED** use settings in `[queue.issue_indexer]`.
|
||||
;ISSUE_INDEXER_QUEUE_DIR = queues/common; **DEPRECATED** use settings in `[queue.issue_indexer]`. Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
|
||||
;;
|
||||
;; When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string.
|
||||
;; When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this is a directory or additional options of
|
||||
@ -1370,7 +1407,7 @@ ROUTER = console
|
||||
;TYPE = persistable-channel
|
||||
;;
|
||||
;; data-dir for storing persistable queues and level queues, individual queues will default to `queues/common` meaning the queue is shared.
|
||||
;DATADIR = queues/
|
||||
;DATADIR = queues/ ; Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
|
||||
;;
|
||||
;; Default queue length before a channel queue will block
|
||||
;LENGTH = 20
|
||||
@ -1672,7 +1709,7 @@ ROUTER = console
|
||||
;; file: session file path, e.g. `data/sessions`
|
||||
;; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
|
||||
;; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table`
|
||||
;PROVIDER_CONFIG = data/sessions
|
||||
;PROVIDER_CONFIG = data/sessions ; Relative paths will be made absolute against _`AppWorkPath`_.
|
||||
;;
|
||||
;; Session cookie name
|
||||
;COOKIE_NAME = i_like_gitea
|
||||
@ -2197,7 +2234,9 @@ ROUTER = console
|
||||
;; Show template execution time in the footer
|
||||
;SHOW_FOOTER_TEMPLATE_LOAD_TIME = true
|
||||
;; Generate sitemap. Defaults to `true`.
|
||||
; ENABLE_SITEMAP = true
|
||||
;ENABLE_SITEMAP = true
|
||||
;; Enable/Disable RSS/Atom feed
|
||||
;ENABLE_FEED = true
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -27,23 +27,56 @@ accurately recorded in [app.example.ini](https://github.com/go-gitea/gitea/blob/
|
||||
(s/main/\<tag|release\>). Any string in the format `%(X)s` is a feature powered
|
||||
by [ini](https://github.com/go-ini/ini/#recursive-values), for reading values recursively.
|
||||
|
||||
In the default values below, a value in the form `$XYZ` refers to an environment variable. (However, see `environment-to-ini`.) Values in the form _`XxYyZz`_ refer to values listed as part of the default configuration. These notation forms will not work in your own `app.ini` file and are only listed here as documentation.
|
||||
|
||||
Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
||||
|
||||
**Note:** A full restart is required for Gitea configuration changes to take effect.
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Default Configuration (non-`app.ini` configuration)
|
||||
|
||||
These values are environment-dependent but form the basis of a lot of values. They will be
|
||||
reported as part of the default configuration when running `gitea --help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up.
|
||||
|
||||
- _`AppPath`_: This is the absolute path of the running gitea binary.
|
||||
- _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy:
|
||||
- The `--work-path` flag passed to the binary
|
||||
- The environment variable `$GITEA_WORK_DIR`
|
||||
- A built-in value set at build time (see building from source)
|
||||
- Otherwise it defaults to the directory of the _`AppPath`_
|
||||
- If any of the above are relative paths then they are made absolute against the
|
||||
the directory of the _`AppPath`_
|
||||
- _`CustomPath`_: This is the base directory for custom templates and other options.
|
||||
It is determined by using the first set thing in the following hierarchy:
|
||||
- The `--custom-path` flag passed to the binary
|
||||
- The environment variable `$GITEA_CUSTOM`
|
||||
- A built-in value set at build time (see building from source)
|
||||
- Otherwise it defaults to _`AppWorkPath`_`/custom`
|
||||
- If any of the above are relative paths then they are made absolute against the
|
||||
the directory of the _`AppWorkPath`_
|
||||
- _`CustomConf`_: This is the path to the `app.ini` file.
|
||||
- The `--config` flag passed to the binary
|
||||
- A built-in value set at build time (see building from source)
|
||||
- Otherwise it defaults to _`CustomPath`_`/conf/app.ini`
|
||||
- If any of the above are relative paths then they are made absolute against the
|
||||
the directory of the _`CustomPath`_
|
||||
|
||||
In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_
|
||||
|
||||
## Overall (`DEFAULT`)
|
||||
|
||||
- `APP_NAME`: **Gitea: Git with a cup of tea**: Application name, used in the page title.
|
||||
- `RUN_USER`: **git**: The user Gitea will run as. This should be a dedicated system
|
||||
(non-user) account. Setting this incorrectly will cause Gitea to not start.
|
||||
- `RUN_USER`: **_current OS username_/`$USER`/`$USERNAME` e.g. git**: The user Gitea will run as.
|
||||
This should be a dedicated system (non-user) account. Setting this incorrectly will cause Gitea
|
||||
to not start.
|
||||
- `RUN_MODE`: **prod**: Application run mode, affects performance and debugging. Either "dev", "prod" or "test".
|
||||
|
||||
## Repository (`repository`)
|
||||
|
||||
- `ROOT`: **%(APP_DATA_PATH)/gitea-repositories**: Root path for storing all repository data.
|
||||
A relative path is interpreted as **%(GITEA_WORK_DIR)/%(ROOT)**.
|
||||
- `ROOT`: **%(APP_DATA_PATH)s/gitea-repositories**: Root path for storing all repository data.
|
||||
A relative path is interpreted as **_`AppWorkPath`_/%(ROOT)s**.
|
||||
- `SCRIPT_TYPE`: **bash**: The script type this server supports. Usually this is `bash`,
|
||||
but some users report that only `sh` is available.
|
||||
- `DETECTED_CHARSETS_ORDER`: **UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE, ISO-8859, windows-1252, ISO-8859, windows-1250, ISO-8859, ISO-8859, ISO-8859, windows-1253, ISO-8859, windows-1255, ISO-8859, windows-1251, windows-1256, KOI8-R, ISO-8859, windows-1254, Shift_JIS, GB18030, EUC-JP, EUC-KR, Big5, ISO-2022, ISO-2022, ISO-2022, IBM424_rtl, IBM424_ltr, IBM420_rtl, IBM420_ltr**: Tie-break order of detected charsets - if the detected charsets have equal confidence, charsets earlier in the list will be chosen in preference to those later. Adding `defaults` will place the unnamed charsets at that point.
|
||||
@ -167,6 +200,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
||||
- `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: list of methods allowed to request
|
||||
- `MAX_AGE`: **10m**: max time to cache response
|
||||
- `ALLOW_CREDENTIALS`: **false**: allow request with credentials
|
||||
- `HEADERS`: **Content-Type,User-Agent**: additional headers that are permitted in requests
|
||||
- `X_FRAME_OPTIONS`: **SAMEORIGIN**: Set the `X-Frame-Options` header value.
|
||||
|
||||
## UI (`ui`)
|
||||
@ -240,6 +274,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
||||
|
||||
## Server (`server`)
|
||||
|
||||
- `APP_DATA_PATH`: **_`AppWorkPath`_/data**: This is the default root path for storing data.
|
||||
- `PROTOCOL`: **http**: \[http, https, fcgi, http+unix, fcgi+unix\]
|
||||
- `USE_PROXY_PROTOCOL`: **false**: Expect PROXY protocol headers on connections
|
||||
- `PROXY_PROTOCOL_TLS_BRIDGING`: **false**: When protocol is https, expect PROXY protocol headers after TLS negotiation.
|
||||
@ -254,12 +289,17 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
||||
This includes CSS files, images, JS files and web fonts.
|
||||
Avatar images are dynamic resources and still served by Gitea.
|
||||
The option can be just a different path, as in `/static`, or another domain, as in `https://cdn.example.com`.
|
||||
Requests are then made as `%(ROOT_URL)s/static/css/index.css` and `https://cdn.example.com/css/index.css` respective.
|
||||
Requests are then made as `%(ROOT_URL)s/static/assets/css/index.css` or `https://cdn.example.com/assets/css/index.css` respectively.
|
||||
The static files are located in the `public/` directory of the Gitea source repository.
|
||||
You can proxy the STATIC_URL_PREFIX requests to Gitea server to serve the static
|
||||
assets, or copy the manually built Gitea assets from `$GITEA_BUILD/public` to
|
||||
the assets location, eg: `/var/www/assets`, make sure `$STATIC_URL_PREFIX/assets/css/index.css`
|
||||
points to `/var/www/assets/css/index.css`.
|
||||
|
||||
- `HTTP_ADDR`: **0.0.0.0**: HTTP listen address.
|
||||
- If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket
|
||||
defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings.
|
||||
- If `PROTOCOL` is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use. Relative paths will be made absolute against the AppWorkPath.
|
||||
- If `PROTOCOL` is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use. Relative paths will be made absolute against the _`AppWorkPath`_.
|
||||
- `HTTP_PORT`: **3000**: HTTP listen port.
|
||||
- If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket
|
||||
defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings.
|
||||
@ -269,7 +309,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
||||
most cases you do not need to change the default value. Alter it only if
|
||||
your SSH server node is not the same as HTTP node. Do not set this variable
|
||||
if `PROTOCOL` is set to `http+unix`.
|
||||
- `LOCAL_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)**: When making local connections pass the PROXY protocol header.
|
||||
- `LOCAL_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)s**: When making local connections pass the PROXY protocol header.
|
||||
This should be set to false if the local connection will go through the proxy.
|
||||
- `PER_WRITE_TIMEOUT`: **30s**: Timeout for any write to the connection. (Set to -1 to
|
||||
disable all timeouts.)
|
||||
@ -279,7 +319,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
||||
- `START_SSH_SERVER`: **false**: When enabled, use the built-in SSH server.
|
||||
- `SSH_SERVER_USE_PROXY_PROTOCOL`: **false**: Expect PROXY protocol header on connections to the built-in SSH Server.
|
||||
- `BUILTIN_SSH_SERVER_USER`: **%(RUN_USER)s**: Username to use for the built-in SSH Server.
|
||||
- `SSH_USER`: **%(BUILTIN_SSH_SERVER_USER)**: SSH username displayed in clone URLs. This is only for people who configure the SSH server themselves; in most cases, you want to leave this blank and modify the `BUILTIN_SSH_SERVER_USER`.
|
||||
- `SSH_USER`: **%(BUILTIN_SSH_SERVER_USER)s**: SSH username displayed in clone URLs. This is only for people who configure the SSH server themselves; in most cases, you want to leave this blank and modify the `BUILTIN_SSH_SERVER_USER`.
|
||||
- `SSH_DOMAIN`: **%(DOMAIN)s**: Domain name of this server, used for displayed clone URL.
|
||||
- `SSH_PORT`: **22**: SSH port displayed in clone URL.
|
||||
- `SSH_LISTEN_HOST`: **0.0.0.0**: Listen address for the built-in SSH server.
|
||||
@ -308,22 +348,22 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
||||
- `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures.
|
||||
- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`.
|
||||
- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`.
|
||||
- `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path.
|
||||
- `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data.
|
||||
- `STATIC_ROOT_PATH`: **_`StaticRootPath`_**: Upper level of template and static files path.
|
||||
- `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data. Relative paths will be made absolute against _`AppWorkPath`_.
|
||||
- `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. Note that this cache is disabled when `RUN_MODE` is "dev".
|
||||
- `ENABLE_GZIP`: **false**: Enable gzip compression for runtime-generated content, static resources excluded.
|
||||
- `ENABLE_PPROF`: **false**: Application profiling (memory and cpu). For "web" command it listens on `localhost:6060`. For "serv" command it dumps to disk at `PPROF_DATA_PATH` as `(cpuprofile|memprofile)_<username>_<temporary id>`
|
||||
- `PPROF_DATA_PATH`: **data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start Gitea as service
|
||||
- `PPROF_DATA_PATH`: **_`AppWorkPath`_/data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start Gitea as service
|
||||
- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login, **custom**\]. Where custom would instead be any URL such as "/org/repo" or even `https://anotherwebsite.com`
|
||||
- `LFS_START_SERVER`: **false**: Enables Git LFS support.
|
||||
- `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)/lfs**: Default LFS content path. (if it is on local storage.) **DEPRECATED** use settings in `[lfs]`.
|
||||
- `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)s/lfs**: Default LFS content path. (if it is on local storage.) **DEPRECATED** use settings in `[lfs]`.
|
||||
- `LFS_JWT_SECRET`: **\<empty\>**: LFS authentication secret, change this a unique string.
|
||||
- `LFS_HTTP_AUTH_EXPIRY`: **20m**: LFS authentication validity period in time.Duration, pushes taking longer than this may fail.
|
||||
- `LFS_MAX_FILE_SIZE`: **0**: Maximum allowed LFS file size in bytes (Set to 0 for no limit).
|
||||
- `LFS_LOCKS_PAGING_NUM`: **50**: Maximum number of LFS Locks returned per page.
|
||||
|
||||
- `REDIRECT_OTHER_PORT`: **false**: If true and `PROTOCOL` is https, allows redirecting http requests on `PORT_TO_REDIRECT` to the https port Gitea listens on.
|
||||
- `REDIRECTOR_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)**: expect PROXY protocol header on connections to https redirector.
|
||||
- `REDIRECTOR_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)s**: expect PROXY protocol header on connections to https redirector.
|
||||
- `PORT_TO_REDIRECT`: **80**: Port for the http redirection service to listen on. Used when `REDIRECT_OTHER_PORT` is true.
|
||||
- `SSL_MIN_VERSION`: **TLSv1.2**: Set the minimum version of ssl support.
|
||||
- `SSL_MAX_VERSION`: **\<empty\>**: Set the maximum version of ssl support.
|
||||
@ -413,10 +453,10 @@ relation to port exhaustion.
|
||||
- `ISSUE_INDEXER_TYPE`: **bleve**: Issue indexer type, currently supported: `bleve`, `db` or `elasticsearch`.
|
||||
- `ISSUE_INDEXER_CONN_STR`: ****: Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch. i.e. http://elastic:changeme@localhost:9200
|
||||
- `ISSUE_INDEXER_NAME`: **gitea_issues**: Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch
|
||||
- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search; available when ISSUE_INDEXER_TYPE is bleve and elasticsearch.
|
||||
- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search; available when ISSUE_INDEXER_TYPE is bleve and elasticsearch. Relative paths will be made absolute against _`AppWorkPath`_.
|
||||
- The next 4 configuration values are deprecated and should be set in `queue.issue_indexer` however are kept for backwards compatibility:
|
||||
- `ISSUE_INDEXER_QUEUE_TYPE`: **levelqueue**: Issue indexer queue, currently supports:`channel`, `levelqueue`, `redis`. **DEPRECATED** use settings in `[queue.issue_indexer]`.
|
||||
- `ISSUE_INDEXER_QUEUE_DIR`: **queues/common**: When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this will be the path where the queue will be saved. **DEPRECATED** use settings in `[queue.issue_indexer]`.
|
||||
- `ISSUE_INDEXER_QUEUE_DIR`: **queues/common**: When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this will be the path where the queue will be saved. **DEPRECATED** use settings in `[queue.issue_indexer]`. Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
|
||||
- `ISSUE_INDEXER_QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string. When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this is a directory or additional options of the form `leveldb://path/to/db?option=value&....`, and overrides `ISSUE_INDEXER_QUEUE_DIR`. **DEPRECATED** use settings in `[queue.issue_indexer]`.
|
||||
- `ISSUE_INDEXER_QUEUE_BATCH_NUMBER`: **20**: Batch queue number. **DEPRECATED** use settings in `[queue.issue_indexer]`.
|
||||
|
||||
@ -438,7 +478,7 @@ relation to port exhaustion.
|
||||
Configuration at `[queue]` will set defaults for queues with overrides for individual queues at `[queue.*]`. (However see below.)
|
||||
|
||||
- `TYPE`: **persistable-channel**: General queue type, currently support: `persistable-channel` (uses a LevelDB internally), `channel`, `level`, `redis`, `dummy`
|
||||
- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for individual queues can be set in `queue.name` sections but will default to `DATADIR/`**`common`**. (Previously each queue would default to `DATADIR/`**`name`**.)
|
||||
- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for individual queues can be set in `queue.name` sections but will default to `DATADIR/`**`common`**. (Previously each queue would default to `DATADIR/`**`name`**.) Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
|
||||
- `LENGTH`: **20**: Maximal queue size before channel queues block
|
||||
- `BATCH_LENGTH`: **20**: Batch data before passing to the handler
|
||||
- `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. Options can be set using query params. Similarly LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**, and will override `DATADIR`
|
||||
@ -722,7 +762,7 @@ and
|
||||
## Session (`session`)
|
||||
|
||||
- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, db, mysql, couchbase, memcache, postgres\]. Setting `db` will reuse the configuration in `[database]`
|
||||
- `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for db, empty (database config will be used); for others, the connection string.
|
||||
- `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for db, empty (database config will be used); for others, the connection string. Relative paths will be made absolute against _`AppWorkPath`_.
|
||||
- `COOKIE_SECURE`: **false**: Enable this to force using HTTPS for all session access.
|
||||
- `COOKIE_NAME`: **i\_like\_gitea**: The name of the cookie used for the session ID.
|
||||
- `GC_INTERVAL_TIME`: **86400**: GC interval in seconds.
|
||||
@ -980,7 +1020,7 @@ Default templates for project boards:
|
||||
## Git (`git`)
|
||||
|
||||
- `PATH`: **""**: The path of Git executable. If empty, Gitea searches through the PATH environment.
|
||||
- `HOME_PATH`: **%(APP_DATA_PATH)/home**: The HOME directory for Git.
|
||||
- `HOME_PATH`: **%(APP_DATA_PATH)s/home**: The HOME directory for Git.
|
||||
This directory will be used to contain the `.gitconfig` and possible `.gnupg` directories that Gitea's git calls will use. If you can confirm Gitea is the only application running in this environment, you can set it to the normal home directory for Gitea user.
|
||||
- `DISABLE_DIFF_HIGHLIGHT`: **false**: Disables highlight of added and removed changes.
|
||||
- `MAX_GIT_DIFF_LINES`: **1000**: Max number of lines allowed of a single file in diff view.
|
||||
@ -1248,3 +1288,4 @@ PROXY_HOSTS = *.github.com
|
||||
- `SHOW_FOOTER_VERSION`: **true**: Show Gitea and Go version information in the footer.
|
||||
- `SHOW_FOOTER_TEMPLATE_LOAD_TIME`: **true**: Show time of template execution in the footer.
|
||||
- `ENABLE_SITEMAP`: **true**: Generate sitemap.
|
||||
- `ENABLE_FEED`: **true**: Enable/Disable RSS/Atom feed.
|
||||
|
@ -15,6 +15,14 @@ menu:
|
||||
|
||||
# Logging Configuration
|
||||
|
||||
The logging configuration of Gitea mainly consists of 3 types of components:
|
||||
|
||||
- The `[log]` section for general configuration
|
||||
- `[log.<sublogger>]` sections for the configuration of different log outputs
|
||||
- `[log.<sublogger>.<group>]` sections for output specific configuration of a log group
|
||||
|
||||
As mentioned below, there is a fully functional log output by default, so it is not necessary to define one.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
@ -23,6 +31,166 @@ menu:
|
||||
|
||||
To collect logs for help and issue report, see [Support Options]({{< relref "doc/help/seek-help.en-us.md" >}}).
|
||||
|
||||
## The `[log]` section
|
||||
|
||||
Configuration of logging facilities in Gitea happen in the `[log]` section and it's subsections.
|
||||
|
||||
In the top level `[log]` section the following configurations can be placed:
|
||||
|
||||
- `ROOT_PATH`: (Default: **%(GITEA_WORK_DIR)/log**): Base path for log files
|
||||
- `MODE`: (Default: **console**) List of log outputs to use for the Default logger.
|
||||
- `ROUTER`: (Default: **console**): List of log outputs to use for the Router logger.
|
||||
- `ACCESS`: List of log outputs to use for the Access logger.
|
||||
- `XORM`: (Default: **,**) List of log outputs to use for the XORM logger.
|
||||
- `ENABLE_ACCESS_LOG`: (Default: **false**): whether the Access logger is allowed to emit logs
|
||||
- `ENABLE_XORM_LOG`: (Default: **true**): whether the XORM logger is allowed to emit logs
|
||||
|
||||
For details on the loggers check the "Log Groups" section.
|
||||
Important: log outputs won't be used if you don't enable them for the desired loggers in the corresponding list value.
|
||||
|
||||
Lists are specified as comma separated values. This format also works in subsection.
|
||||
|
||||
This section may be used for defining default values for subsections.
|
||||
Examples:
|
||||
|
||||
- `LEVEL`: (Default: **Info**) Least severe log events to persist. Case insensitive. The full list of levels as of v1.17.3 can be read [here](https://github.com/go-gitea/gitea/blob/v1.17.3/custom/conf/app.example.ini#L507).
|
||||
- `STACKTRACE_LEVEL`: (Default: **None**) For this and more severe events the stacktrace will be printed upon getting logged.
|
||||
|
||||
Some values are not inherited by subsections. For details see the "Non-inherited default values" section.
|
||||
|
||||
## Log outputs
|
||||
|
||||
Log outputs are the targets to which log messages will be sent.
|
||||
The content and the format of the log messages to be saved can be configured in these.
|
||||
|
||||
Log outputs are also called subloggers.
|
||||
|
||||
Gitea provides 4 possible log outputs:
|
||||
|
||||
- `console` - Log to `os.Stdout` or `os.Stderr`
|
||||
- `file` - Log to a file
|
||||
- `conn` - Log to a socket (network or unix)
|
||||
- `smtp` - Log via email
|
||||
|
||||
By default, Gitea has a `console` output configured, which is used by the loggers as seen in the section "The log section" above.
|
||||
|
||||
### Common configuration
|
||||
|
||||
Certain configuration is common to all modes of log output:
|
||||
|
||||
- `MODE` is the mode of the log output. It will default to the sublogger
|
||||
name, thus `[log.console.router]` will default to `MODE = console`.
|
||||
For mode specific confgurations read further.
|
||||
- `LEVEL` is the lowest level that this output will log. This value
|
||||
is inherited from `[log]` and in the case of the non-default loggers
|
||||
from `[log.sublogger]`.
|
||||
- `STACKTRACE_LEVEL` is the lowest level that this output will print
|
||||
a stacktrace. This value is inherited.
|
||||
- `COLORIZE` will default to `true` for `console` as
|
||||
described, otherwise it will default to `false`.
|
||||
|
||||
### Non-inherited default values
|
||||
|
||||
There are several values which are not inherited as described above but
|
||||
rather default to those specific to type of logger, these are:
|
||||
`EXPRESSION`, `FLAGS`, `PREFIX` and `FILE_NAME`.
|
||||
|
||||
#### `EXPRESSION`
|
||||
|
||||
`EXPRESSION` represents a regular expression that log events must match to be logged by the sublogger. Either the log message, (with colors removed), must match or the `longfilename:linenumber:functionname` must match. NB: the whole message or string doesn't need to completely match.
|
||||
|
||||
Please note this expression will be run in the sublogger's goroutine
|
||||
not the logging event subroutine. Therefore it can be complicated.
|
||||
|
||||
#### `FLAGS`
|
||||
|
||||
`FLAGS` represents the preceding logging context information that is
|
||||
printed before each message. It is a comma-separated string set. The order of values does not matter.
|
||||
|
||||
Possible values are:
|
||||
|
||||
- `none` or `,` - No flags.
|
||||
- `date` - the date in the local time zone: `2009/01/23`.
|
||||
- `time` - the time in the local time zone: `01:23:23`.
|
||||
- `microseconds` - microsecond resolution: `01:23:23.123123`. Assumes
|
||||
time.
|
||||
- `longfile` - full file name and line number: `/a/b/c/d.go:23`.
|
||||
- `shortfile` - final file name element and line number: `d.go:23`.
|
||||
- `funcname` - function name of the caller: `runtime.Caller()`.
|
||||
- `shortfuncname` - last part of the function name. Overrides
|
||||
`funcname`.
|
||||
- `utc` - if date or time is set, use UTC rather than the local time
|
||||
zone.
|
||||
- `levelinitial` - Initial character of the provided level in brackets eg. `[I]` for info.
|
||||
- `level` - Provided level in brackets `[INFO]`
|
||||
- `medfile` - Last 20 characters of the filename - equivalent to
|
||||
`shortfile,longfile`.
|
||||
- `stdflags` - Equivalent to `date,time,medfile,shortfuncname,levelinitial`
|
||||
|
||||
### Console mode
|
||||
|
||||
In this mode the logger will forward log messages to the stdout and
|
||||
stderr streams attached to the Gitea process.
|
||||
|
||||
For loggers in console mode, `COLORIZE` will default to `true` if not
|
||||
on windows, or the windows terminal can be set into ANSI mode or is a
|
||||
cygwin or Msys pipe.
|
||||
|
||||
Settings:
|
||||
|
||||
- `STDERR`: **false**: Whether the logger should print to `stderr` instead of `stdout`.
|
||||
|
||||
### File mode
|
||||
|
||||
In this mode the logger will save log messages to a file.
|
||||
|
||||
Settings:
|
||||
|
||||
- `FILE_NAME`: The file to write the log events to. For details see below.
|
||||
- `MAX_SIZE_SHIFT`: **28**: Maximum size shift of a single file. 28 represents 256Mb. For details see below.
|
||||
- `LOG_ROTATE` **true**: Whether to rotate the log files. TODO: if false, will it delete instead on daily rotate, or do nothing?.
|
||||
- `DAILY_ROTATE`: **true**: Whether to rotate logs daily.
|
||||
- `MAX_DAYS`: **7**: Delete rotated log files after this number of days.
|
||||
- `COMPRESS`: **true**: Whether to compress old log files by default with gzip.
|
||||
- `COMPRESSION_LEVEL`: **-1**: Compression level. For details see below.
|
||||
|
||||
The default value of `FILE_NAME` depends on the respective logger facility.
|
||||
If unset, their own default will be used.
|
||||
If set it will be relative to the provided `ROOT_PATH` in the master `[log]` section.
|
||||
|
||||
`MAX_SIZE_SHIFT` defines the maximum size of a file by left shifting 1 the given number of times (`1 << x`).
|
||||
The exact behavior at the time of v1.17.3 can be seen [here](https://github.com/go-gitea/gitea/blob/v1.17.3/modules/setting/log.go#L185).
|
||||
|
||||
The useful values of `COMPRESSION_LEVEL` are from 1 to (and including) 9, where higher numbers mean better compression.
|
||||
Beware that better compression might come with higher resource usage.
|
||||
Must be preceded with a `-` sign.
|
||||
|
||||
### Conn mode
|
||||
|
||||
In this mode the logger will send log messages over a network socket.
|
||||
|
||||
Settings:
|
||||
|
||||
- `ADDR`: **:7020**: Sets the address to connect to.
|
||||
- `PROTOCOL`: **tcp**: Set the protocol, either "tcp", "unix" or "udp".
|
||||
- `RECONNECT`: **false**: Try to reconnect when connection is lost.
|
||||
- `RECONNECT_ON_MSG`: **false**: Reconnect host for every single message.
|
||||
|
||||
### SMTP mode
|
||||
|
||||
In this mode the logger will send log messages in email.
|
||||
|
||||
It is not recommended to use this logger to send general logging
|
||||
messages. However, you could perhaps set this logger to work on `FATAL` messages only.
|
||||
|
||||
Settings:
|
||||
|
||||
- `HOST`: **127.0.0.1:25**: The SMTP host to connect to.
|
||||
- `USER`: User email address to send from.
|
||||
- `PASSWD`: Password for the smtp server.
|
||||
- `RECEIVERS`: Email addresses to send to.
|
||||
- `SUBJECT`: **Diagnostic message from Gitea**. The content of the email's subject field.
|
||||
|
||||
## Log Groups
|
||||
|
||||
The fundamental thing to be aware of in Gitea is that there are several
|
||||
@ -172,106 +340,6 @@ which will not be inherited from the `[log]` or relevant
|
||||
- `EXPRESSION` will default to `""`
|
||||
- `PREFIX` will default to `""`
|
||||
|
||||
## Log outputs
|
||||
|
||||
Gitea provides 4 possible log outputs:
|
||||
|
||||
- `console` - Log to `os.Stdout` or `os.Stderr`
|
||||
- `file` - Log to a file
|
||||
- `conn` - Log to a keep-alive TCP connection
|
||||
- `smtp` - Log via email
|
||||
|
||||
Certain configuration is common to all modes of log output:
|
||||
|
||||
- `LEVEL` is the lowest level that this output will log. This value
|
||||
is inherited from `[log]` and in the case of the non-default loggers
|
||||
from `[log.sublogger]`.
|
||||
- `STACKTRACE_LEVEL` is the lowest level that this output will print
|
||||
a stacktrace. This value is inherited.
|
||||
- `MODE` is the mode of the log output. It will default to the sublogger
|
||||
name. Thus `[log.console.router]` will default to `MODE = console`.
|
||||
- `COLORIZE` will default to `true` for `console` as
|
||||
described, otherwise it will default to `false`.
|
||||
|
||||
### Non-inherited default values
|
||||
|
||||
There are several values which are not inherited as described above but
|
||||
rather default to those specific to type of logger, these are:
|
||||
`EXPRESSION`, `FLAGS`, `PREFIX` and `FILE_NAME`.
|
||||
|
||||
#### `EXPRESSION`
|
||||
|
||||
`EXPRESSION` represents a regular expression that log events must match to be logged by the sublogger. Either the log message, (with colors removed), must match or the `longfilename:linenumber:functionname` must match. NB: the whole message or string doesn't need to completely match.
|
||||
|
||||
Please note this expression will be run in the sublogger's goroutine
|
||||
not the logging event subroutine. Therefore it can be complicated.
|
||||
|
||||
#### `FLAGS`
|
||||
|
||||
`FLAGS` represents the preceding logging context information that is
|
||||
printed before each message. It is a comma-separated string set. The order of values does not matter.
|
||||
|
||||
Possible values are:
|
||||
|
||||
- `none` or `,` - No flags.
|
||||
- `date` - the date in the local time zone: `2009/01/23`.
|
||||
- `time` - the time in the local time zone: `01:23:23`.
|
||||
- `microseconds` - microsecond resolution: `01:23:23.123123`. Assumes
|
||||
time.
|
||||
- `longfile` - full file name and line number: `/a/b/c/d.go:23`.
|
||||
- `shortfile` - final file name element and line number: `d.go:23`.
|
||||
- `funcname` - function name of the caller: `runtime.Caller()`.
|
||||
- `shortfuncname` - last part of the function name. Overrides
|
||||
`funcname`.
|
||||
- `utc` - if date or time is set, use UTC rather than the local time
|
||||
zone.
|
||||
- `levelinitial` - Initial character of the provided level in brackets eg. `[I]` for info.
|
||||
- `level` - Provided level in brackets `[INFO]`
|
||||
- `medfile` - Last 20 characters of the filename - equivalent to
|
||||
`shortfile,longfile`.
|
||||
- `stdflags` - Equivalent to `date,time,medfile,shortfuncname,levelinitial`
|
||||
|
||||
### Console mode
|
||||
|
||||
For loggers in console mode, `COLORIZE` will default to `true` if not
|
||||
on windows, or the windows terminal can be set into ANSI mode or is a
|
||||
cygwin or Msys pipe.
|
||||
|
||||
If `STDERR` is set to `true` the logger will use `os.Stderr` instead of
|
||||
`os.Stdout`.
|
||||
|
||||
### File mode
|
||||
|
||||
The `FILE_NAME` defaults as described above. If set it will be relative
|
||||
to the provided `ROOT_PATH` in the master `[log]` section.
|
||||
|
||||
Other values:
|
||||
|
||||
- `LOG_ROTATE`: **true**: Rotate the log files.
|
||||
- `MAX_SIZE_SHIFT`: **28**: Maximum size shift of a single file, 28 represents 256Mb.
|
||||
- `DAILY_ROTATE`: **true**: Rotate logs daily.
|
||||
- `MAX_DAYS`: **7**: Delete the log file after n days
|
||||
- `COMPRESS`: **true**: Compress old log files by default with gzip
|
||||
- `COMPRESSION_LEVEL`: **-1**: Compression level
|
||||
|
||||
### Conn mode
|
||||
|
||||
- `RECONNECT_ON_MSG`: **false**: Reconnect host for every single message.
|
||||
- `RECONNECT`: **false**: Try to reconnect when connection is lost.
|
||||
- `PROTOCOL`: **tcp**: Set the protocol, either "tcp", "unix" or "udp".
|
||||
- `ADDR`: **:7020**: Sets the address to connect to.
|
||||
|
||||
### SMTP mode
|
||||
|
||||
It is not recommended to use this logger to send general logging
|
||||
messages. However, you could perhaps set this logger to work on `FATAL`.
|
||||
|
||||
- `USER`: User email address to send from.
|
||||
- `PASSWD`: Password for the smtp server.
|
||||
- `HOST`: **127.0.0.1:25**: The SMTP host to connect to.
|
||||
- `RECEIVERS`: Email addresses to send to.
|
||||
- `SUBJECT`: **Diagnostic message from Gitea**
|
||||
|
||||
## Debugging problems
|
||||
|
||||
When submitting logs in Gitea issues it is often helpful to submit
|
||||
|
@ -41,13 +41,15 @@ For an existing remote repository, you can set up pull mirroring as follows:
|
||||
|
||||
The repository now gets mirrored periodically from the remote repository. You can force a sync by selecting **Synchronize Now** in the repository settings.
|
||||
|
||||
:exclamation::exclamation: **NOTE:** You can only set up pull mirroring for repos that don't exist yet on your instance. Once the repo is created, you can't convert it into a pull mirror anymore. :exclamation::exclamation:
|
||||
|
||||
## Pushing to a remote repository
|
||||
|
||||
For an existing repository, you can set up push mirroring as follows:
|
||||
|
||||
1. In your repository, go to **Settings** > **Repository**, and then the **Mirror Settings** section.
|
||||
2. Enter a repository URL.
|
||||
3. If the repository needs authentication expand the **Authorization** section and fill in your authentication information.
|
||||
3. If the repository needs authentication expand the **Authorization** section and fill in your authentication information. Note that the requested **password** can also be your access token.
|
||||
4. Select **Add Push Mirror** to save the configuration.
|
||||
|
||||
The repository now gets mirrored periodically to the remote repository. You can force a sync by selecting **Synchronize Now**. In case of an error a message displayed to help you resolve it.
|
||||
@ -59,9 +61,11 @@ The repository now gets mirrored periodically to the remote repository. You can
|
||||
To set up a mirror from Gitea to GitHub, you need to follow these steps:
|
||||
|
||||
1. Create a [GitHub personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with the *public_repo* box checked.
|
||||
2. Fill in the **Git Remote Repository URL**: `https://github.com/<your_github_group>/<your_github_project>.git`.
|
||||
3. Fill in the **Authorization** fields with your GitHub username and the personal access token.
|
||||
4. Select **Add Push Mirror** to save the configuration.
|
||||
2. Create a repository with that name on GitHub. Unlike Gitea, GitHub does not support creating repositories by pushing to the remote. You can also use an existing remote repo if it has the same commit history as your Gitea repo.
|
||||
3. In the settings of your Gitea repo, fill in the **Git Remote Repository URL**: `https://github.com/<your_github_group>/<your_github_project>.git`.
|
||||
4. Fill in the **Authorization** fields with your GitHub username and the personal access token as **Password**.
|
||||
5. (Optional, available on Gitea 1.18+) Select `Sync when new commits are pushed` so that the mirror will be updated as well as soon as there are changes. You can also disable the periodic sync if you like.
|
||||
6. Select **Add Push Mirror** to save the configuration.
|
||||
|
||||
The repository pushes shortly thereafter. To force a push, select the **Synchronize Now** button.
|
||||
|
||||
|
@ -166,11 +166,47 @@ Uses the following fields:
|
||||
|
||||
## PAM (Pluggable Authentication Module)
|
||||
|
||||
To configure PAM, set the 'PAM Service Name' to a filename in `/etc/pam.d/`. To
|
||||
work with normal Linux passwords, the user running Gitea must have read access
|
||||
to `/etc/shadow`.
|
||||
This procedure enables PAM authentication. Users may still be added to the
|
||||
system manually using the user administration. PAM provides a mechanism to
|
||||
automatically add users to the current database by testing them against PAM
|
||||
authentication. To work with normal Linux passwords, the user running Gitea
|
||||
must also have read access to `/etc/shadow` in order to check the validity of
|
||||
the account when logging in using a public key.
|
||||
|
||||
**Note**: PAM support is added via [build-time flags](https://docs.gitea.io/en-us/install-from-source/#build), and the official binaries provided do not have this enabled.
|
||||
**Note**: If a user has added SSH public keys into Gitea, the use of these
|
||||
keys _may_ bypass the login check system. Therefore, if you wish to disable a user who
|
||||
authenticates with PAM, you _should_ also manually disable the account in Gitea using the
|
||||
built-in user manager.
|
||||
|
||||
1. Configure and prepare the installation.
|
||||
- It is recommended that you create an administrative user.
|
||||
- Deselecting automatic sign-up may also be desired.
|
||||
1. Once the database has been initialized, log in as the newly created
|
||||
administrative user.
|
||||
1. Navigate to the user setting (icon in top-right corner), and select
|
||||
`Site Administration` -> `Authentication Sources`, and select
|
||||
`Add Authentication Source`.
|
||||
1. Fill out the field as follows:
|
||||
- `Authentication Type` : `PAM`
|
||||
- `Name` : Any value should be valid here, use "System Authentication" if
|
||||
you'd like.
|
||||
- `PAM Service Name` : Select the appropriate file listed under `/etc/pam.d/`
|
||||
that performs the authentication desired.[^1]
|
||||
- `PAM Email Domain` : The e-mail suffix to append to user authentication.
|
||||
For example, if the login system expects a user called `gituser`, and this
|
||||
field is set to `mail.com`, then Gitea will expect the `user email` field
|
||||
for an authenticated GIT instance to be `gituser@mail.com`.[^2]
|
||||
|
||||
**Note**: PAM support is added via [build-time flags](https://docs.gitea.io/en-us/install-from-source/#build),
|
||||
and the official binaries provided do not have this enabled. PAM requires that
|
||||
the necessary libpam dynamic library be available and the necessary PAM
|
||||
development headers be accessible to the compiler.
|
||||
|
||||
[^1]: For example, using standard Linux log-in on Debian "Bullseye" use
|
||||
`common-session-noninteractive` - this value may be valid for other flavors of
|
||||
Debian including Ubuntu and Mint, consult your distribution's documentation.
|
||||
[^2]: **This is a required field for PAM**. Be aware: In the above example, the
|
||||
user will log into the Gitea web interface as `gituser` and not `gituser@mail.com`
|
||||
|
||||
## SMTP (Simple Mail Transfer Protocol)
|
||||
|
||||
|
@ -58,29 +58,33 @@ https://github.com/loganinak/MigrateGitlabToGogs
|
||||
|
||||
## Where does Gitea store what file
|
||||
|
||||
- WorkPath
|
||||
- Environment variable `GITEA_WORK_DIR`
|
||||
- Else `--work-path` flag
|
||||
- _`AppWorkPath`_
|
||||
- The `--work-path` flag
|
||||
- Else Environment variable `GITEA_WORK_DIR`
|
||||
- Else a built-in value set at build time
|
||||
- Else the directory that contains the Gitea binary
|
||||
- AppDataPath (default for database, indexers, etc.)
|
||||
- `%(APP_DATA_PATH)` (default for database, indexers, etc.)
|
||||
- `APP_DATA_PATH` from `app.ini`
|
||||
- Else `%(WorkPath)/data`
|
||||
- CustomPath (custom templates)
|
||||
- Environment variable `GITEA_CUSTOM`
|
||||
- Else `%(WorkPath)/custom`
|
||||
- Else _`AppWorkPath`_`/data`
|
||||
- _`CustomPath`_ (custom templates)
|
||||
- The `--custom-path` flag
|
||||
- Else Environment variable `GITEA_CUSTOM`
|
||||
- Else a built-in value set at build time
|
||||
- Else _`AppWorkPath`_`/custom`
|
||||
- HomeDir
|
||||
- Unix: Environment variable `HOME`
|
||||
- Windows: Environment variable `USERPROFILE`, else environment variables `HOMEDRIVE`+`HOMEPATH`
|
||||
- RepoRootPath
|
||||
- `ROOT` in the \[repository] section of `app.ini` if absolute
|
||||
- Else `%(AppWorkPath)/ROOT` if `ROOT` in the \[repository] section of `app.ini` if relative
|
||||
- Default `%(AppDataPath)/gitea-repositories`
|
||||
- Else _`AppWorkPath`_`/ROOT` if `ROOT` in the \[repository] section of `app.ini` if relative
|
||||
- Default `%(APP_DATA_PATH)/gitea-repositories`
|
||||
- INI (config file)
|
||||
- `-c` flag
|
||||
- Else `%(CustomPath)/conf/app.ini`
|
||||
- `--config` flag
|
||||
- A possible built-in value set a build time
|
||||
- Else _`CustomPath`_`/conf/app.ini`
|
||||
- SQLite Database
|
||||
- `PATH` in `database` section of `app.ini`
|
||||
- Else `%(AppDataPath)/gitea.db`
|
||||
- Else `%(APP_DATA_PATH)/gitea.db`
|
||||
|
||||
## Not seeing a clone URL or the clone URL being incorrect
|
||||
|
||||
|
@ -94,7 +94,7 @@ are provided to keep the build process as simple as possible.
|
||||
|
||||
Depending on requirements, the following build tags can be included.
|
||||
|
||||
- `bindata`: Build a single monolithic binary, with all assets included.
|
||||
- `bindata`: Build a single monolithic binary, with all assets included. Required for production build.
|
||||
- `sqlite sqlite_unlock_notify`: Enable support for a
|
||||
[SQLite3](https://sqlite.org/) database. Suggested only for tiny
|
||||
installations.
|
||||
@ -103,11 +103,10 @@ Depending on requirements, the following build tags can be included.
|
||||
available to PAM.
|
||||
- `gogit`: (EXPERIMENTAL) Use go-git variants of Git commands.
|
||||
|
||||
Bundling assets into the binary using the `bindata` build tag is recommended for
|
||||
production deployments. It is possible to serve the static assets directly via a reverse proxy,
|
||||
but in most cases it is not necessary, and assets should still be bundled in the binary.
|
||||
You may want to exclude bindata while developing/testing Gitea.
|
||||
To include assets, add the `bindata` tag:
|
||||
Bundling all assets (JS/CSS/templates, etc) into the binary. Using the `bindata` build tag is required for
|
||||
production deployments. You could exclude `bindata` when you are developing/testing Gitea or able to separate the assets correctly.
|
||||
|
||||
To include all assets, use the `bindata` tag:
|
||||
|
||||
```bash
|
||||
TAGS="bindata" make build
|
||||
@ -144,11 +143,11 @@ launched manually from command line, it can be killed by pressing `Ctrl + C`.
|
||||
|
||||
## Changing default paths
|
||||
|
||||
Gitea will search for a number of things from the `CustomPath`. By default this is
|
||||
Gitea will search for a number of things from the _`CustomPath`_. By default this is
|
||||
the `custom/` directory in the current working directory when running Gitea. It will also
|
||||
look for its configuration file `CustomConf` in `$CustomPath/conf/app.ini`, and will use the
|
||||
current working directory as the relative base path `AppWorkPath` for a number configurable
|
||||
values. Finally the static files will be served from `StaticRootPath` which defaults to the `AppWorkPath`.
|
||||
look for its configuration file _`CustomConf`_ in _`CustomPath`_/conf/app.ini`, and will use the
|
||||
current working directory as the relative base path _`AppWorkPath`_ for a number configurable
|
||||
values. Finally the static files will be served from _`StaticRootPath`_ which defaults to the _`AppWorkPath`_.
|
||||
|
||||
These values, although useful when developing, may conflict with downstream users preferences.
|
||||
|
||||
@ -156,10 +155,10 @@ One option is to use a script file to shadow the `gitea` binary and create an ap
|
||||
environment before running Gitea. However, when building you can change these defaults
|
||||
using the `LDFLAGS` environment variable for `make`. The appropriate settings are as follows
|
||||
|
||||
- To set the `CustomPath` use `LDFLAGS="-X \"code.gitea.io/gitea/modules/setting.CustomPath=custom-path\""`
|
||||
- For `CustomConf` you should use `-X \"code.gitea.io/gitea/modules/setting.CustomConf=conf.ini\"`
|
||||
- For `AppWorkPath` you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=working-path\"`
|
||||
- For `StaticRootPath` you should use `-X \"code.gitea.io/gitea/modules/setting.StaticRootPath=static-root-path\"`
|
||||
- To set the _`CustomPath`_ use `LDFLAGS="-X \"code.gitea.io/gitea/modules/setting.CustomPath=custom-path\""`
|
||||
- For _`CustomConf`_ you should use `-X \"code.gitea.io/gitea/modules/setting.CustomConf=conf.ini\"`
|
||||
- For _`AppWorkPath`_ you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=working-path\"`
|
||||
- For _`StaticRootPath`_ you should use `-X \"code.gitea.io/gitea/modules/setting.StaticRootPath=static-root-path\"`
|
||||
- To change the default PID file location use `-X \"code.gitea.io/gitea/modules/setting.PIDFile=/run/gitea.pid\"`
|
||||
|
||||
Add as many of the strings with their preceding `-X` to the `LDFLAGS` variable and run `make build`
|
||||
|
84
docs/content/doc/packages/storage.en-us.md
Normal file
84
docs/content/doc/packages/storage.en-us.md
Normal file
@ -0,0 +1,84 @@
|
||||
---
|
||||
date: "2022-11-01T00:00:00+00:00"
|
||||
title: "Storage"
|
||||
slug: "packages/storage"
|
||||
draft: false
|
||||
toc: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "packages"
|
||||
name: "storage"
|
||||
weight: 5
|
||||
identifier: "storage"
|
||||
---
|
||||
|
||||
# Storage
|
||||
|
||||
This document describes the storage of the package registry and how it can be managed.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Deduplication
|
||||
|
||||
The package registry has a build-in deduplication of uploaded blobs.
|
||||
If two identical files are uploaded only one blob is saved on the filesystem.
|
||||
This ensures no space is wasted for duplicated files.
|
||||
|
||||
If two packages are uploaded with identical files, both packages will display the same size but on the filesystem they require only half of the size.
|
||||
Whenever a package gets deleted only the references to the underlaying blobs are removed.
|
||||
The blobs get not removed at this moment, so they still require space on the filesystem.
|
||||
When a new package gets uploaded the existing blobs may get referenced again.
|
||||
|
||||
These unreferenced blobs get deleted by a [clean up job]({{< relref "doc/advanced/config-cheat-sheet.en-us.md#cron---cleanup-expired-packages-croncleanup_packages" >}}).
|
||||
The config setting `OLDER_THAN` configures how long unreferenced blobs are kept before they get deleted.
|
||||
|
||||
## Cleanup Rules
|
||||
|
||||
Package registries can become large over time without cleanup.
|
||||
It's recommended to delete unnecessary packages and set up cleanup rules to automatically manage the package registry usage.
|
||||
Every package owner (user or organization) manages the cleanup rules which are applied to their packages.
|
||||
|
||||
|Setting|Description|
|
||||
|-|-|
|
||||
|Enabled|Turn the cleanup rule on or off.|
|
||||
|Type|Every rule manages a specific package type.|
|
||||
|Apply pattern to full package name|If enabled, the patterns below are applied to the full package name (`package/version`). Otherwise only the version (`version`) is used.|
|
||||
|Keep the most recent|How many versions to *always* keep for each package.|
|
||||
|Keep versions matching|The regex pattern that determines which versions to keep. An empty pattern keeps no version while `.+` keeps all versions. The container registry will always keep the `latest` version even if not configured.|
|
||||
|Remove versions older than|Remove only versions older than the selected days.|
|
||||
|Remove versions matching|The regex pattern that determines which versions to remove. An empty pattern or `.+` leads to the removal of every package if no other setting tells otherwise.|
|
||||
|
||||
Every cleanup rule can show a preview of the affected packages.
|
||||
This can be used to check if the cleanup rules is proper configured.
|
||||
|
||||
### Regex examples
|
||||
|
||||
Regex patterns are automatically surrounded with `\A` and `\z` anchors.
|
||||
Do not include any `\A`, `\z`, `^` or `$` token in the regex patterns as they are not necessary.
|
||||
The patterns are case-insensitive which matches the behaviour of the package registry in Gitea.
|
||||
|
||||
|Pattern|Description|
|
||||
|-|-|
|
||||
|`.*`|Match every possible version.|
|
||||
|`v.+`|Match versions that start with `v`.|
|
||||
|`release`|Match only the version `release`.|
|
||||
|`release.*`|Match versions that are either named or start with `release`.|
|
||||
|`.+-temp-.+`|Match versions that contain `-temp-`.|
|
||||
|`v.+\|release`|Match versions that either start with `v` or are named `release`.|
|
||||
|`package/v.+\|other/release`|Match versions of the package `package` that start with `v` or the version `release` of the package `other`. This needs the setting *Apply pattern to full package name* enabled.|
|
||||
|
||||
### How the cleanup rules work
|
||||
|
||||
The cleanup rules are part of the [clean up job]({{< relref "doc/advanced/config-cheat-sheet.en-us.md#cron---cleanup-expired-packages-croncleanup_packages" >}}) and run periodicly.
|
||||
|
||||
The cleanup rule:
|
||||
|
||||
1. Collects all packages of the package type for the owners registry.
|
||||
1. For every package it collects all versions.
|
||||
1. Excludes from the list the # versions based on the *Keep the most recent* value.
|
||||
1. Excludes from the list any versions matching the *Keep versions matching* value.
|
||||
1. Excludes from the list the versions more recent than the *Remove versions older than* value.
|
||||
1. Excludes from the list any versions not matching the *Remove versions matching* value.
|
||||
1. Deletes the remaining versions.
|
@ -45,15 +45,15 @@ Beispiel: Wenn der Button mit `löschen` beschriftet ist, sollte im Modal die Fr
|
||||
## Artikeldefinitionen für Anglizismen
|
||||
|
||||
* _Der_ Commit (m.)
|
||||
* _Der_ Branch (m.)
|
||||
* _Der_ Branch (m.), plural: die Branches
|
||||
* _Das_ Issue (n.)
|
||||
* _Der_ Fork (m.)
|
||||
* _Das_ Repository (n.)
|
||||
* _Das_ Repository (n.), plural: die Repositories
|
||||
* _Der_ Pull-Request (m.)
|
||||
* _Der_ Token (m.)
|
||||
* _Der_ Token (m.), plural: die Token
|
||||
* _Das_ Review (n.)
|
||||
* _Der_ Key (m.)
|
||||
* _Der_ Committer (m.)
|
||||
* _Der_ Committer (m.), plural: die Committer
|
||||
|
||||
## Weiterführende Links
|
||||
|
||||
|
10
go.mod
10
go.mod
@ -94,15 +94,14 @@ require (
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
go.jolheiser.com/hcaptcha v0.0.4
|
||||
go.jolheiser.com/pwn v0.0.3
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc
|
||||
golang.org/x/crypto v0.2.1-0.20221112162523-6fad3dfc1891
|
||||
golang.org/x/net v0.2.0
|
||||
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
|
||||
golang.org/x/text v0.3.8
|
||||
golang.org/x/sys v0.2.0
|
||||
golang.org/x/text v0.4.0
|
||||
golang.org/x/tools v0.1.12
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
mvdan.cc/xurls/v2 v2.4.0
|
||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
|
||||
@ -293,6 +292,7 @@ require (
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
)
|
||||
|
||||
|
18
go.sum
18
go.sum
@ -1608,8 +1608,8 @@ golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.2.1-0.20221112162523-6fad3dfc1891 h1:WhEPFM1Ck5gaKybeSWvzI7Y/cd8K9K5tJGRxXMACOBA=
|
||||
golang.org/x/crypto v0.2.1-0.20221112162523-6fad3dfc1891/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -1721,8 +1721,8 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -1876,13 +1876,13 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -1892,8 +1892,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -461,7 +461,8 @@ func DeleteOldActions(olderThan time.Duration) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func notifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||
// NotifyWatchers creates batch of actions for every watcher.
|
||||
func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||
var watchers []*repo_model.Watch
|
||||
var repo *repo_model.Repository
|
||||
var err error
|
||||
@ -565,20 +566,15 @@ func notifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotifyWatchers creates batch of actions for every watcher.
|
||||
func NotifyWatchers(actions ...*Action) error {
|
||||
return notifyWatchers(db.DefaultContext, actions...)
|
||||
}
|
||||
|
||||
// NotifyWatchersActions creates batch of actions for every watcher.
|
||||
func NotifyWatchersActions(acts []*Action) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
for _, act := range acts {
|
||||
if err := notifyWatchers(ctx, act); err != nil {
|
||||
if err := NotifyWatchers(ctx, act); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -603,17 +599,17 @@ func DeleteIssueActions(ctx context.Context, repoID, issueID int64) error {
|
||||
}
|
||||
|
||||
// CountActionCreatedUnixString count actions where created_unix is an empty string
|
||||
func CountActionCreatedUnixString() (int64, error) {
|
||||
func CountActionCreatedUnixString(ctx context.Context) (int64, error) {
|
||||
if setting.Database.UseSQLite3 {
|
||||
return db.GetEngine(db.DefaultContext).Where(`created_unix = ""`).Count(new(Action))
|
||||
return db.GetEngine(ctx).Where(`created_unix = ""`).Count(new(Action))
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// FixActionCreatedUnixString set created_unix to zero if it is an empty string
|
||||
func FixActionCreatedUnixString() (int64, error) {
|
||||
func FixActionCreatedUnixString(ctx context.Context) (int64, error) {
|
||||
if setting.Database.UseSQLite3 {
|
||||
res, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`)
|
||||
res, err := db.GetEngine(ctx).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ func TestNotifyWatchers(t *testing.T) {
|
||||
RepoID: 1,
|
||||
OpType: activities_model.ActionStarRepo,
|
||||
}
|
||||
assert.NoError(t, activities_model.NotifyWatchers(action))
|
||||
assert.NoError(t, activities_model.NotifyWatchers(db.DefaultContext, action))
|
||||
|
||||
// One watchers are inactive, thus action is only created for user 8, 1, 4, 11
|
||||
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
|
||||
@ -256,17 +256,17 @@ func TestConsistencyUpdateAction(t *testing.T) {
|
||||
//
|
||||
// Get rid of incorrectly set created_unix
|
||||
//
|
||||
count, err := activities_model.CountActionCreatedUnixString()
|
||||
count, err := activities_model.CountActionCreatedUnixString(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, count)
|
||||
count, err = activities_model.FixActionCreatedUnixString()
|
||||
count, err = activities_model.FixActionCreatedUnixString(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, count)
|
||||
|
||||
count, err = activities_model.CountActionCreatedUnixString()
|
||||
count, err = activities_model.CountActionCreatedUnixString(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 0, count)
|
||||
count, err = activities_model.FixActionCreatedUnixString()
|
||||
count, err = activities_model.FixActionCreatedUnixString(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 0, count)
|
||||
|
||||
|
@ -136,56 +136,48 @@ func GetNotifications(ctx context.Context, options *FindNotificationOptions) (nl
|
||||
}
|
||||
|
||||
// CountNotifications count all notifications that fit to the given options and ignore pagination.
|
||||
func CountNotifications(opts *FindNotificationOptions) (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where(opts.ToCond()).Count(&Notification{})
|
||||
func CountNotifications(ctx context.Context, opts *FindNotificationOptions) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(opts.ToCond()).Count(&Notification{})
|
||||
}
|
||||
|
||||
// CreateRepoTransferNotification creates notification for the user a repository was transferred to
|
||||
func CreateRepoTransferNotification(doer, newOwner *user_model.User, repo *repo_model.Repository) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
func CreateRepoTransferNotification(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) error {
|
||||
return db.AutoTx(ctx, func(ctx context.Context) error {
|
||||
var notify []*Notification
|
||||
|
||||
var notify []*Notification
|
||||
|
||||
if newOwner.IsOrganization() {
|
||||
users, err := organization.GetUsersWhoCanCreateOrgRepo(ctx, newOwner.ID)
|
||||
if err != nil || len(users) == 0 {
|
||||
return err
|
||||
}
|
||||
for i := range users {
|
||||
notify = append(notify, &Notification{
|
||||
UserID: users[i].ID,
|
||||
if newOwner.IsOrganization() {
|
||||
users, err := organization.GetUsersWhoCanCreateOrgRepo(ctx, newOwner.ID)
|
||||
if err != nil || len(users) == 0 {
|
||||
return err
|
||||
}
|
||||
for i := range users {
|
||||
notify = append(notify, &Notification{
|
||||
UserID: users[i].ID,
|
||||
RepoID: repo.ID,
|
||||
Status: NotificationStatusUnread,
|
||||
UpdatedBy: doer.ID,
|
||||
Source: NotificationSourceRepository,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
notify = []*Notification{{
|
||||
UserID: newOwner.ID,
|
||||
RepoID: repo.ID,
|
||||
Status: NotificationStatusUnread,
|
||||
UpdatedBy: doer.ID,
|
||||
Source: NotificationSourceRepository,
|
||||
})
|
||||
}}
|
||||
}
|
||||
} else {
|
||||
notify = []*Notification{{
|
||||
UserID: newOwner.ID,
|
||||
RepoID: repo.ID,
|
||||
Status: NotificationStatusUnread,
|
||||
UpdatedBy: doer.ID,
|
||||
Source: NotificationSourceRepository,
|
||||
}}
|
||||
}
|
||||
|
||||
if err := db.Insert(ctx, notify); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return committer.Commit()
|
||||
return db.Insert(ctx, notify)
|
||||
})
|
||||
}
|
||||
|
||||
// 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()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -379,11 +371,7 @@ func CountUnread(ctx context.Context, userID int64) int64 {
|
||||
}
|
||||
|
||||
// LoadAttributes load Repo Issue User and Comment if not loaded
|
||||
func (n *Notification) LoadAttributes() (err error) {
|
||||
return n.loadAttributes(db.DefaultContext)
|
||||
}
|
||||
|
||||
func (n *Notification) loadAttributes(ctx context.Context) (err error) {
|
||||
func (n *Notification) LoadAttributes(ctx context.Context) (err error) {
|
||||
if err = n.loadRepo(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
@ -481,10 +469,10 @@ func (n *Notification) APIURL() string {
|
||||
type NotificationList []*Notification
|
||||
|
||||
// LoadAttributes load Repo Issue User and Comment if not loaded
|
||||
func (nl NotificationList) LoadAttributes() error {
|
||||
func (nl NotificationList) LoadAttributes(ctx context.Context) error {
|
||||
var err error
|
||||
for i := 0; i < len(nl); i++ {
|
||||
err = nl[i].LoadAttributes()
|
||||
err = nl[i].LoadAttributes(ctx)
|
||||
if err != nil && !issues_model.IsErrCommentNotExist(err) {
|
||||
return err
|
||||
}
|
||||
@ -504,7 +492,7 @@ func (nl NotificationList) getPendingRepoIDs() []int64 {
|
||||
}
|
||||
|
||||
// LoadRepos loads repositories from database
|
||||
func (nl NotificationList) LoadRepos() (repo_model.RepositoryList, []int, error) {
|
||||
func (nl NotificationList) LoadRepos(ctx context.Context) (repo_model.RepositoryList, []int, error) {
|
||||
if len(nl) == 0 {
|
||||
return repo_model.RepositoryList{}, []int{}, nil
|
||||
}
|
||||
@ -517,7 +505,7 @@ func (nl NotificationList) LoadRepos() (repo_model.RepositoryList, []int, error)
|
||||
if left < limit {
|
||||
limit = left
|
||||
}
|
||||
rows, err := db.GetEngine(db.DefaultContext).
|
||||
rows, err := db.GetEngine(ctx).
|
||||
In("id", repoIDs[:limit]).
|
||||
Rows(new(repo_model.Repository))
|
||||
if err != nil {
|
||||
@ -578,7 +566,7 @@ func (nl NotificationList) getPendingIssueIDs() []int64 {
|
||||
}
|
||||
|
||||
// LoadIssues loads issues from database
|
||||
func (nl NotificationList) LoadIssues() ([]int, error) {
|
||||
func (nl NotificationList) LoadIssues(ctx context.Context) ([]int, error) {
|
||||
if len(nl) == 0 {
|
||||
return []int{}, nil
|
||||
}
|
||||
@ -591,7 +579,7 @@ func (nl NotificationList) LoadIssues() ([]int, error) {
|
||||
if left < limit {
|
||||
limit = left
|
||||
}
|
||||
rows, err := db.GetEngine(db.DefaultContext).
|
||||
rows, err := db.GetEngine(ctx).
|
||||
In("id", issueIDs[:limit]).
|
||||
Rows(new(issues_model.Issue))
|
||||
if err != nil {
|
||||
@ -662,7 +650,7 @@ func (nl NotificationList) getPendingCommentIDs() []int64 {
|
||||
}
|
||||
|
||||
// LoadComments loads comments from database
|
||||
func (nl NotificationList) LoadComments() ([]int, error) {
|
||||
func (nl NotificationList) LoadComments(ctx context.Context) ([]int, error) {
|
||||
if len(nl) == 0 {
|
||||
return []int{}, nil
|
||||
}
|
||||
@ -675,7 +663,7 @@ func (nl NotificationList) LoadComments() ([]int, error) {
|
||||
if left < limit {
|
||||
limit = left
|
||||
}
|
||||
rows, err := db.GetEngine(db.DefaultContext).
|
||||
rows, err := db.GetEngine(ctx).
|
||||
In("id", commentIDs[:limit]).
|
||||
Rows(new(issues_model.Comment))
|
||||
if err != nil {
|
||||
@ -775,8 +763,8 @@ func SetRepoReadBy(ctx context.Context, userID, repoID int64) error {
|
||||
}
|
||||
|
||||
// SetNotificationStatus change the notification status
|
||||
func SetNotificationStatus(notificationID int64, user *user_model.User, status NotificationStatus) (*Notification, error) {
|
||||
notification, err := getNotificationByID(db.DefaultContext, notificationID)
|
||||
func SetNotificationStatus(ctx context.Context, notificationID int64, user *user_model.User, status NotificationStatus) (*Notification, error) {
|
||||
notification, err := GetNotificationByID(ctx, notificationID)
|
||||
if err != nil {
|
||||
return notification, err
|
||||
}
|
||||
@ -787,16 +775,12 @@ func SetNotificationStatus(notificationID int64, user *user_model.User, status N
|
||||
|
||||
notification.Status = status
|
||||
|
||||
_, err = db.GetEngine(db.DefaultContext).ID(notificationID).Update(notification)
|
||||
_, err = db.GetEngine(ctx).ID(notificationID).Update(notification)
|
||||
return notification, err
|
||||
}
|
||||
|
||||
// GetNotificationByID return notification by ID
|
||||
func GetNotificationByID(notificationID int64) (*Notification, error) {
|
||||
return getNotificationByID(db.DefaultContext, notificationID)
|
||||
}
|
||||
|
||||
func getNotificationByID(ctx context.Context, notificationID int64) (*Notification, error) {
|
||||
func GetNotificationByID(ctx context.Context, notificationID int64) (*Notification, error) {
|
||||
notification := new(Notification)
|
||||
ok, err := db.GetEngine(ctx).
|
||||
Where("id = ?", notificationID).
|
||||
@ -813,9 +797,9 @@ func getNotificationByID(ctx context.Context, notificationID int64) (*Notificati
|
||||
}
|
||||
|
||||
// UpdateNotificationStatuses updates the statuses of all of a user's notifications that are of the currentStatus type to the desiredStatus
|
||||
func UpdateNotificationStatuses(user *user_model.User, currentStatus, desiredStatus NotificationStatus) error {
|
||||
func UpdateNotificationStatuses(ctx context.Context, user *user_model.User, currentStatus, desiredStatus NotificationStatus) error {
|
||||
n := &Notification{Status: desiredStatus, UpdatedBy: user.ID}
|
||||
_, err := db.GetEngine(db.DefaultContext).
|
||||
_, err := db.GetEngine(ctx).
|
||||
Where("user_id = ? AND status = ?", user.ID, currentStatus).
|
||||
Cols("status", "updated_by", "updated_unix").
|
||||
Update(n)
|
||||
|
@ -82,14 +82,14 @@ func TestSetNotificationStatus(t *testing.T) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
notf := unittest.AssertExistsAndLoadBean(t,
|
||||
&activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusRead})
|
||||
_, err := activities_model.SetNotificationStatus(notf.ID, user, activities_model.NotificationStatusPinned)
|
||||
_, err := activities_model.SetNotificationStatus(db.DefaultContext, notf.ID, user, activities_model.NotificationStatusPinned)
|
||||
assert.NoError(t, err)
|
||||
unittest.AssertExistsAndLoadBean(t,
|
||||
&activities_model.Notification{ID: notf.ID, Status: activities_model.NotificationStatusPinned})
|
||||
|
||||
_, err = activities_model.SetNotificationStatus(1, user, activities_model.NotificationStatusRead)
|
||||
_, err = activities_model.SetNotificationStatus(db.DefaultContext, 1, user, activities_model.NotificationStatusRead)
|
||||
assert.Error(t, err)
|
||||
_, err = activities_model.SetNotificationStatus(unittest.NonexistentID, user, activities_model.NotificationStatusRead)
|
||||
_, err = activities_model.SetNotificationStatus(db.DefaultContext, unittest.NonexistentID, user, activities_model.NotificationStatusRead)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ func TestUpdateNotificationStatuses(t *testing.T) {
|
||||
&activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusRead})
|
||||
notfPinned := unittest.AssertExistsAndLoadBean(t,
|
||||
&activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusPinned})
|
||||
assert.NoError(t, activities_model.UpdateNotificationStatuses(user, activities_model.NotificationStatusUnread, activities_model.NotificationStatusRead))
|
||||
assert.NoError(t, activities_model.UpdateNotificationStatuses(db.DefaultContext, user, activities_model.NotificationStatusUnread, activities_model.NotificationStatusRead))
|
||||
unittest.AssertExistsAndLoadBean(t,
|
||||
&activities_model.Notification{ID: notfUnread.ID, Status: activities_model.NotificationStatusRead})
|
||||
unittest.AssertExistsAndLoadBean(t,
|
||||
|
@ -234,7 +234,7 @@ func DeleteGPGKey(doer *user_model.User, id int64) (err error) {
|
||||
return ErrGPGKeyAccessDenied{doer.ID, key.ID}
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ func AddGPGKey(ownerID int64, content, token, signature string) ([]*GPGKey, erro
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ import (
|
||||
|
||||
// VerifyGPGKey marks a GPG key as verified
|
||||
func VerifyGPGKey(ownerID int64, keyID, token, signature string) (string, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ func AddPublicKey(ownerID int64, name, content string, authSourceID int64) (*Pub
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -321,7 +321,7 @@ func PublicKeyIsExternallyManaged(id int64) (bool, error) {
|
||||
// deleteKeysMarkedForDeletion returns true if ssh keys needs update
|
||||
func deleteKeysMarkedForDeletion(keys []string) (bool, error) {
|
||||
// Start session
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func AddDeployKey(repoID int64, name, content string, readOnly bool) (*DeployKey
|
||||
accessMode = perm.AccessModeWrite
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ import (
|
||||
|
||||
// AddPrincipalKey adds new principal to database and authorized_principals file.
|
||||
func AddPrincipalKey(ownerID int64, content string, authSourceID int64) (*PublicKey, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
|
||||
// VerifySSHKey marks a SSH key as verified
|
||||
func VerifySSHKey(ownerID int64, fingerprint, token, signature string) (string, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ type UpdateOAuth2ApplicationOptions struct {
|
||||
|
||||
// UpdateOAuth2Application updates an oauth2 application
|
||||
func UpdateOAuth2Application(opts UpdateOAuth2ApplicationOptions) (*OAuth2Application, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -265,7 +265,7 @@ func deleteOAuth2Application(ctx context.Context, id, userid int64) error {
|
||||
|
||||
// DeleteOAuth2Application deletes the application with the given id and the grants and auth codes related to it. It checks if the userid was the creator of the app.
|
||||
func DeleteOAuth2Application(id, userid int64) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ func ReadSession(key string) (*Session, error) {
|
||||
Key: key,
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -73,7 +73,7 @@ func DestroySession(key string) error {
|
||||
|
||||
// RegenerateSession regenerates a session from the old id
|
||||
func RegenerateSession(oldKey, newKey string) (*Session, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ func saveEmailHash(email string) string {
|
||||
Hash: emailHash,
|
||||
}
|
||||
// OK we're going to open a session just because I think that that might hide away any problems with postgres reporting errors
|
||||
if err := db.WithTx(func(ctx context.Context) error {
|
||||
if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
||||
has, err := db.GetEngine(ctx).Where("email = ? AND hash = ?", emailHash.Email, emailHash.Hash).Get(new(EmailHash))
|
||||
if has || err != nil {
|
||||
// Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time
|
||||
@ -150,10 +150,11 @@ func generateEmailAvatarLink(email string, size int, final bool) string {
|
||||
return DefaultAvatarLink()
|
||||
}
|
||||
|
||||
enableFederatedAvatar, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar)
|
||||
enableFederatedAvatarSetting, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar)
|
||||
enableFederatedAvatar := enableFederatedAvatarSetting.GetValueBool()
|
||||
|
||||
var err error
|
||||
if enableFederatedAvatar != nil && enableFederatedAvatar.GetValueBool() && system_model.LibravatarService != nil {
|
||||
if enableFederatedAvatar && system_model.LibravatarService != nil {
|
||||
emailHash := saveEmailHash(email)
|
||||
if final {
|
||||
// for final link, we can spend more time on slow external query
|
||||
@ -171,8 +172,10 @@ func generateEmailAvatarLink(email string, size int, final bool) string {
|
||||
return urlStr
|
||||
}
|
||||
|
||||
disableGravatar, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar)
|
||||
if disableGravatar != nil && !disableGravatar.GetValueBool() {
|
||||
disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar)
|
||||
|
||||
disableGravatar := disableGravatarSetting.GetValueBool()
|
||||
if !disableGravatar {
|
||||
// copy GravatarSourceURL, because we will modify its Path.
|
||||
avatarURLCopy := *system_model.GravatarSourceURL
|
||||
avatarURLCopy.Path = path.Join(avatarURLCopy.Path, HashEmail(email))
|
||||
|
@ -4,11 +4,16 @@
|
||||
|
||||
package db
|
||||
|
||||
import "xorm.io/builder"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// CountOrphanedObjects count subjects with have no existing refobject anymore
|
||||
func CountOrphanedObjects(subject, refobject, joinCond string) (int64, error) {
|
||||
return GetEngine(DefaultContext).Table("`"+subject+"`").
|
||||
func CountOrphanedObjects(ctx context.Context, subject, refobject, joinCond string) (int64, error) {
|
||||
return GetEngine(ctx).
|
||||
Table("`"+subject+"`").
|
||||
Join("LEFT", "`"+refobject+"`", joinCond).
|
||||
Where(builder.IsNull{"`" + refobject + "`.id"}).
|
||||
Select("COUNT(`" + subject + "`.`id`)").
|
||||
@ -16,12 +21,12 @@ func CountOrphanedObjects(subject, refobject, joinCond string) (int64, error) {
|
||||
}
|
||||
|
||||
// DeleteOrphanedObjects delete subjects with have no existing refobject anymore
|
||||
func DeleteOrphanedObjects(subject, refobject, joinCond string) error {
|
||||
func DeleteOrphanedObjects(ctx context.Context, subject, refobject, joinCond string) error {
|
||||
subQuery := builder.Select("`"+subject+"`.id").
|
||||
From("`"+subject+"`").
|
||||
Join("LEFT", "`"+refobject+"`", joinCond).
|
||||
Where(builder.IsNull{"`" + refobject + "`.id"})
|
||||
b := builder.Delete(builder.In("id", subQuery)).From("`" + subject + "`")
|
||||
_, err := GetEngine(DefaultContext).Exec(b)
|
||||
_, err := GetEngine(ctx).Exec(b)
|
||||
return err
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
@ -86,7 +87,11 @@ type Committer interface {
|
||||
}
|
||||
|
||||
// TxContext represents a transaction Context
|
||||
func TxContext() (*Context, Committer, error) {
|
||||
func TxContext(parentCtx context.Context) (*Context, Committer, error) {
|
||||
if InTransaction(parentCtx) {
|
||||
return nil, nil, ErrAlreadyInTransaction
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
if err := sess.Begin(); err != nil {
|
||||
sess.Close()
|
||||
@ -97,14 +102,24 @@ func TxContext() (*Context, Committer, error) {
|
||||
}
|
||||
|
||||
// WithTx represents executing database operations on a transaction
|
||||
// you can optionally change the context to a parent one
|
||||
func WithTx(f func(ctx context.Context) error, stdCtx ...context.Context) error {
|
||||
parentCtx := DefaultContext
|
||||
if len(stdCtx) != 0 && stdCtx[0] != nil {
|
||||
// TODO: make sure parent context has no open session
|
||||
parentCtx = stdCtx[0]
|
||||
// This function will always open a new transaction, if a transaction exist in parentCtx return an error.
|
||||
func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error {
|
||||
if InTransaction(parentCtx) {
|
||||
return ErrAlreadyInTransaction
|
||||
}
|
||||
return txWithNoCheck(parentCtx, f)
|
||||
}
|
||||
|
||||
// AutoTx represents executing database operations on a transaction, if the transaction exist,
|
||||
// this function will reuse it otherwise will create a new one and close it when finished.
|
||||
func AutoTx(parentCtx context.Context, f func(ctx context.Context) error) error {
|
||||
if InTransaction(parentCtx) {
|
||||
return f(newContext(parentCtx, GetEngine(parentCtx), true))
|
||||
}
|
||||
return txWithNoCheck(parentCtx, f)
|
||||
}
|
||||
|
||||
func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error) error {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
@ -180,3 +195,28 @@ func EstimateCount(ctx context.Context, bean interface{}) (int64, error) {
|
||||
}
|
||||
return rows, err
|
||||
}
|
||||
|
||||
// InTransaction returns true if the engine is in a transaction otherwise return false
|
||||
func InTransaction(ctx context.Context) bool {
|
||||
var e Engine
|
||||
if engined, ok := ctx.(Engined); ok {
|
||||
e = engined.Engine()
|
||||
} else {
|
||||
enginedInterface := ctx.Value(enginedContextKey)
|
||||
if enginedInterface != nil {
|
||||
e = enginedInterface.(Engined).Engine()
|
||||
}
|
||||
}
|
||||
if e == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch t := e.(type) {
|
||||
case *xorm.Engine:
|
||||
return false
|
||||
case *xorm.Session:
|
||||
return t.IsInTx()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
33
models/db/context_test.go
Normal file
33
models/db/context_test.go
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package db_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInTransaction(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
assert.False(t, db.InTransaction(db.DefaultContext))
|
||||
assert.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
||||
assert.True(t, db.InTransaction(ctx))
|
||||
return nil
|
||||
}))
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
defer committer.Close()
|
||||
assert.True(t, db.InTransaction(ctx))
|
||||
assert.Error(t, db.WithTx(ctx, func(ctx context.Context) error {
|
||||
assert.True(t, db.InTransaction(ctx))
|
||||
return nil
|
||||
}))
|
||||
}
|
@ -41,11 +41,11 @@ func TestDeleteOrphanedObjects(t *testing.T) {
|
||||
_, err = db.GetEngine(db.DefaultContext).Insert(&issues_model.PullRequest{IssueID: 1000}, &issues_model.PullRequest{IssueID: 1001}, &issues_model.PullRequest{IssueID: 1003})
|
||||
assert.NoError(t, err)
|
||||
|
||||
orphaned, err := db.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
|
||||
orphaned, err := db.CountOrphanedObjects(db.DefaultContext, "pull_request", "issue", "pull_request.issue_id=issue.id")
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 3, orphaned)
|
||||
|
||||
err = db.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
|
||||
err = db.DeleteOrphanedObjects(db.DefaultContext, "pull_request", "issue", "pull_request.issue_id=issue.id")
|
||||
assert.NoError(t, err)
|
||||
|
||||
countAfter, err := db.GetEngine(db.DefaultContext).Count(&issues_model.PullRequest{})
|
||||
|
@ -5,11 +5,14 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
var ErrAlreadyInTransaction = errors.New("database connection has already been in a transaction")
|
||||
|
||||
// ErrCancelled represents an error due to context cancellation
|
||||
type ErrCancelled struct {
|
||||
Message string
|
||||
|
@ -59,7 +59,7 @@ func TestSyncMaxResourceIndex(t *testing.T) {
|
||||
assert.EqualValues(t, 62, maxIndex)
|
||||
|
||||
// commit transaction
|
||||
err = db.WithTx(func(ctx context.Context) error {
|
||||
err = db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
||||
err = db.SyncMaxResourceIndex(ctx, "test_index", 10, 73)
|
||||
assert.NoError(t, err)
|
||||
maxIndex, err = getCurrentResourceIndex(ctx, "test_index", 10)
|
||||
@ -73,7 +73,7 @@ func TestSyncMaxResourceIndex(t *testing.T) {
|
||||
assert.EqualValues(t, 73, maxIndex)
|
||||
|
||||
// rollback transaction
|
||||
err = db.WithTx(func(ctx context.Context) error {
|
||||
err = db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
||||
err = db.SyncMaxResourceIndex(ctx, "test_index", 10, 84)
|
||||
maxIndex, err = getCurrentResourceIndex(ctx, "test_index", 10)
|
||||
assert.NoError(t, err)
|
||||
@ -102,7 +102,7 @@ func TestGetNextResourceIndex(t *testing.T) {
|
||||
assert.EqualValues(t, 2, maxIndex)
|
||||
|
||||
// commit transaction
|
||||
err = db.WithTx(func(ctx context.Context) error {
|
||||
err = db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
||||
maxIndex, err = db.GetNextResourceIndex(ctx, "test_index", 20)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 3, maxIndex)
|
||||
@ -114,7 +114,7 @@ func TestGetNextResourceIndex(t *testing.T) {
|
||||
assert.EqualValues(t, 3, maxIndex)
|
||||
|
||||
// rollback transaction
|
||||
err = db.WithTx(func(ctx context.Context) error {
|
||||
err = db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
||||
maxIndex, err = db.GetNextResourceIndex(ctx, "test_index", 20)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 4, maxIndex)
|
||||
|
@ -5,6 +5,7 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
@ -12,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
// CountBadSequences looks for broken sequences from recreate-table mistakes
|
||||
func CountBadSequences() (int64, error) {
|
||||
func CountBadSequences(_ context.Context) (int64, error) {
|
||||
if !setting.Database.UsePostgreSQL {
|
||||
return 0, nil
|
||||
}
|
||||
@ -33,7 +34,7 @@ func CountBadSequences() (int64, error) {
|
||||
}
|
||||
|
||||
// FixBadSequences fixes for broken sequences from recreate-table mistakes
|
||||
func FixBadSequences() error {
|
||||
func FixBadSequences(_ context.Context) error {
|
||||
if !setting.Database.UsePostgreSQL {
|
||||
return nil
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ func GetYamlFixturesAccess() (string, error) {
|
||||
}
|
||||
|
||||
for _, repo := range repos {
|
||||
repo.MustOwner()
|
||||
repo.MustOwner(db.DefaultContext)
|
||||
if err := access_model.RecalculateAccesses(db.DefaultContext, repo); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -544,7 +544,7 @@ func FindRenamedBranch(repoID int64, from string) (branch *RenamedBranch, exist
|
||||
|
||||
// RenameBranch rename a branch
|
||||
func RenameBranch(repo *repo_model.Repository, from, to string, gitAction func(isDefault bool) error) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ func TestRenameBranch(t *testing.T) {
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
_isDefault := false
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
defer committer.Close()
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, git_model.UpdateProtectBranch(ctx, repo1, &git_model.ProtectedBranch{
|
||||
|
@ -94,7 +94,7 @@ func GetNextCommitStatusIndex(repoID int64, sha string) (int64, error) {
|
||||
|
||||
// getNextCommitStatusIndex return the next index
|
||||
func getNextCommitStatusIndex(repoID int64, sha string) (int64, error) {
|
||||
ctx, commiter, err := db.TxContext()
|
||||
ctx, commiter, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -297,7 +297,7 @@ func NewCommitStatus(opts NewCommitStatusOptions) error {
|
||||
return fmt.Errorf("generate commit status index failed: %w", err)
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", opts.Repo.ID, opts.Creator.ID, opts.SHA, err)
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ var ErrLFSObjectNotExist = db.ErrNotExist{Resource: "LFS Meta object"}
|
||||
func NewLFSMetaObject(m *LFSMetaObject) (*LFSMetaObject, error) {
|
||||
var err error
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -185,7 +185,7 @@ func RemoveLFSMetaObjectByOid(repoID int64, oid string) (int64, error) {
|
||||
return 0, ErrLFSObjectNotExist
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -235,14 +235,14 @@ func LFSObjectAccessible(user *user_model.User, oid string) (bool, error) {
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// LFSObjectIsAssociated checks if a provided Oid is associated
|
||||
func LFSObjectIsAssociated(oid string) (bool, error) {
|
||||
return db.GetEngine(db.DefaultContext).Exist(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
|
||||
// ExistsLFSObject checks if a provided Oid exists within the DB
|
||||
func ExistsLFSObject(ctx context.Context, oid string) (bool, error) {
|
||||
return db.GetEngine(ctx).Exist(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
|
||||
}
|
||||
|
||||
// LFSAutoAssociate auto associates accessible LFSMetaObjects
|
||||
func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int64) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ func cleanPath(p string) string {
|
||||
|
||||
// CreateLFSLock creates a new lock.
|
||||
func CreateLFSLock(repo *repo_model.Repository, lock *LFSLock) (*LFSLock, error) {
|
||||
dbCtx, committer, err := db.TxContext()
|
||||
dbCtx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -137,7 +137,7 @@ func CountLFSLockByRepoID(repoID int64) (int64, error) {
|
||||
|
||||
// DeleteLFSLockByID deletes a lock by given ID.
|
||||
func DeleteLFSLockByID(id int64, repo *repo_model.Repository, u *user_model.User, force bool) (*LFSLock, error) {
|
||||
dbCtx, committer, err := db.TxContext()
|
||||
dbCtx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@ -69,13 +70,13 @@ func UpdateProtectedTag(pt *ProtectedTag) error {
|
||||
}
|
||||
|
||||
// DeleteProtectedTag deletes a protected tag by ID
|
||||
func DeleteProtectedTag(pt *ProtectedTag) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).ID(pt.ID).Delete(&ProtectedTag{})
|
||||
func DeleteProtectedTag(ctx context.Context, pt *ProtectedTag) error {
|
||||
_, err := db.GetEngine(ctx).ID(pt.ID).Delete(&ProtectedTag{})
|
||||
return err
|
||||
}
|
||||
|
||||
// IsUserAllowedModifyTag returns true if the user is allowed to modify the tag
|
||||
func IsUserAllowedModifyTag(pt *ProtectedTag, userID int64) (bool, error) {
|
||||
func IsUserAllowedModifyTag(ctx context.Context, pt *ProtectedTag, userID int64) (bool, error) {
|
||||
if base.Int64sContains(pt.AllowlistUserIDs, userID) {
|
||||
return true, nil
|
||||
}
|
||||
@ -84,7 +85,7 @@ func IsUserAllowedModifyTag(pt *ProtectedTag, userID int64) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
in, err := organization.IsUserInTeams(db.DefaultContext, userID, pt.AllowlistTeamIDs)
|
||||
in, err := organization.IsUserInTeams(ctx, userID, pt.AllowlistTeamIDs)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -92,9 +93,9 @@ func IsUserAllowedModifyTag(pt *ProtectedTag, userID int64) (bool, error) {
|
||||
}
|
||||
|
||||
// GetProtectedTags gets all protected tags of the repository
|
||||
func GetProtectedTags(repoID int64) ([]*ProtectedTag, error) {
|
||||
func GetProtectedTags(ctx context.Context, repoID int64) ([]*ProtectedTag, error) {
|
||||
tags := make([]*ProtectedTag, 0)
|
||||
return tags, db.GetEngine(db.DefaultContext).Find(&tags, &ProtectedTag{RepoID: repoID})
|
||||
return tags, db.GetEngine(ctx).Find(&tags, &ProtectedTag{RepoID: repoID})
|
||||
}
|
||||
|
||||
// GetProtectedTagByID gets the protected tag with the specific id
|
||||
@ -112,7 +113,7 @@ func GetProtectedTagByID(id int64) (*ProtectedTag, error) {
|
||||
|
||||
// IsUserAllowedToControlTag checks if a user can control the specific tag.
|
||||
// It returns true if the tag name is not protected or the user is allowed to control it.
|
||||
func IsUserAllowedToControlTag(tags []*ProtectedTag, tagName string, userID int64) (bool, error) {
|
||||
func IsUserAllowedToControlTag(ctx context.Context, tags []*ProtectedTag, tagName string, userID int64) (bool, error) {
|
||||
isAllowed := true
|
||||
for _, tag := range tags {
|
||||
err := tag.EnsureCompiledPattern()
|
||||
@ -124,7 +125,7 @@ func IsUserAllowedToControlTag(tags []*ProtectedTag, tagName string, userID int6
|
||||
continue
|
||||
}
|
||||
|
||||
isAllowed, err = IsUserAllowedModifyTag(tag, userID)
|
||||
isAllowed, err = IsUserAllowedModifyTag(ctx, tag, userID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package git_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
@ -17,29 +18,29 @@ func TestIsUserAllowed(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
pt := &git_model.ProtectedTag{}
|
||||
allowed, err := git_model.IsUserAllowedModifyTag(pt, 1)
|
||||
allowed, err := git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, allowed)
|
||||
|
||||
pt = &git_model.ProtectedTag{
|
||||
AllowlistUserIDs: []int64{1},
|
||||
}
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(pt, 1)
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, allowed)
|
||||
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(pt, 2)
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, allowed)
|
||||
|
||||
pt = &git_model.ProtectedTag{
|
||||
AllowlistTeamIDs: []int64{1},
|
||||
}
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(pt, 1)
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, allowed)
|
||||
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(pt, 2)
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, allowed)
|
||||
|
||||
@ -47,11 +48,11 @@ func TestIsUserAllowed(t *testing.T) {
|
||||
AllowlistUserIDs: []int64{1},
|
||||
AllowlistTeamIDs: []int64{1},
|
||||
}
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(pt, 1)
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, allowed)
|
||||
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(pt, 2)
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, allowed)
|
||||
}
|
||||
@ -135,7 +136,7 @@ func TestIsUserAllowedToControlTag(t *testing.T) {
|
||||
}
|
||||
|
||||
for n, c := range cases {
|
||||
isAllowed, err := git_model.IsUserAllowedToControlTag(protectedTags, c.name, c.userid)
|
||||
isAllowed, err := git_model.IsUserAllowedToControlTag(db.DefaultContext, protectedTags, c.name, c.userid)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.allowed, isAllowed, "case %d: error should match", n)
|
||||
}
|
||||
@ -157,7 +158,7 @@ func TestIsUserAllowedToControlTag(t *testing.T) {
|
||||
}
|
||||
|
||||
for n, c := range cases {
|
||||
isAllowed, err := git_model.IsUserAllowedToControlTag(protectedTags, c.name, c.userid)
|
||||
isAllowed, err := git_model.IsUserAllowedToControlTag(db.DefaultContext, protectedTags, c.name, c.userid)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.allowed, isAllowed, "case %d: error should match", n)
|
||||
}
|
||||
|
@ -48,9 +48,10 @@ func (issue *Issue) LoadAssignees(ctx context.Context) (err error) {
|
||||
// GetAssigneeIDsByIssue returns the IDs of users assigned to an issue
|
||||
// but skips joining with `user` for performance reasons.
|
||||
// User permissions must be verified elsewhere if required.
|
||||
func GetAssigneeIDsByIssue(issueID int64) ([]int64, error) {
|
||||
func GetAssigneeIDsByIssue(ctx context.Context, issueID int64) ([]int64, error) {
|
||||
userIDs := make([]int64, 0, 5)
|
||||
return userIDs, db.GetEngine(db.DefaultContext).Table("issue_assignees").
|
||||
return userIDs, db.GetEngine(ctx).
|
||||
Table("issue_assignees").
|
||||
Cols("assignee_id").
|
||||
Where("issue_id = ?", issueID).
|
||||
Distinct("assignee_id").
|
||||
@ -64,7 +65,7 @@ func IsUserAssignedToIssue(ctx context.Context, issue *Issue, user *user_model.U
|
||||
|
||||
// ToggleIssueAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it.
|
||||
func ToggleIssueAssignee(issue *Issue, doer *user_model.User, assigneeID int64) (removed bool, comment *Comment, err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
@ -151,7 +152,7 @@ func toggleUserAssignee(ctx context.Context, issue *Issue, assigneeID int64) (re
|
||||
}
|
||||
|
||||
// MakeIDsFromAPIAssigneesToAdd returns an array with all assignee IDs
|
||||
func MakeIDsFromAPIAssigneesToAdd(oneAssignee string, multipleAssignees []string) (assigneeIDs []int64, err error) {
|
||||
func MakeIDsFromAPIAssigneesToAdd(ctx context.Context, oneAssignee string, multipleAssignees []string) (assigneeIDs []int64, err error) {
|
||||
var requestAssignees []string
|
||||
|
||||
// Keeping the old assigning method for compatibility reasons
|
||||
@ -165,7 +166,7 @@ func MakeIDsFromAPIAssigneesToAdd(oneAssignee string, multipleAssignees []string
|
||||
}
|
||||
|
||||
// Get the IDs of all assignees
|
||||
assigneeIDs, err = user_model.GetUserIDsByNames(requestAssignees, false)
|
||||
assigneeIDs, err = user_model.GetUserIDsByNames(ctx, requestAssignees, false)
|
||||
|
||||
return assigneeIDs, err
|
||||
}
|
||||
|
@ -71,22 +71,22 @@ func TestMakeIDsFromAPIAssigneesToAdd(t *testing.T) {
|
||||
_ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
_ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
IDs, err := issues_model.MakeIDsFromAPIAssigneesToAdd("", []string{""})
|
||||
IDs, err := issues_model.MakeIDsFromAPIAssigneesToAdd(db.DefaultContext, "", []string{""})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []int64{}, IDs)
|
||||
|
||||
_, err = issues_model.MakeIDsFromAPIAssigneesToAdd("", []string{"none_existing_user"})
|
||||
_, err = issues_model.MakeIDsFromAPIAssigneesToAdd(db.DefaultContext, "", []string{"none_existing_user"})
|
||||
assert.Error(t, err)
|
||||
|
||||
IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd("user1", []string{"user1"})
|
||||
IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd(db.DefaultContext, "user1", []string{"user1"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []int64{1}, IDs)
|
||||
|
||||
IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd("user2", []string{""})
|
||||
IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd(db.DefaultContext, "user2", []string{""})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []int64{2}, IDs)
|
||||
|
||||
IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd("", []string{"user1", "user2"})
|
||||
IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd(db.DefaultContext, "", []string{"user1", "user2"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []int64{1, 2}, IDs)
|
||||
}
|
||||
|
@ -309,13 +309,8 @@ type PushActionContent struct {
|
||||
CommitIDs []string `json:"commit_ids"`
|
||||
}
|
||||
|
||||
// LoadIssue loads issue from database
|
||||
func (c *Comment) LoadIssue() (err error) {
|
||||
return c.LoadIssueCtx(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadIssueCtx loads issue from database
|
||||
func (c *Comment) LoadIssueCtx(ctx context.Context) (err error) {
|
||||
// LoadIssue loads the issue reference for the comment
|
||||
func (c *Comment) LoadIssue(ctx context.Context) (err error) {
|
||||
if c.Issue != nil {
|
||||
return nil
|
||||
}
|
||||
@ -350,7 +345,8 @@ func (c *Comment) AfterLoad(session *xorm.Session) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Comment) loadPoster(ctx context.Context) (err error) {
|
||||
// LoadPoster loads comment poster
|
||||
func (c *Comment) LoadPoster(ctx context.Context) (err error) {
|
||||
if c.PosterID <= 0 || c.Poster != nil {
|
||||
return nil
|
||||
}
|
||||
@ -381,7 +377,7 @@ func (c *Comment) AfterDelete() {
|
||||
|
||||
// HTMLURL formats a URL-string to the issue-comment
|
||||
func (c *Comment) HTMLURL() string {
|
||||
err := c.LoadIssue()
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
@ -410,7 +406,7 @@ func (c *Comment) HTMLURL() string {
|
||||
|
||||
// APIURL formats a API-string to the issue-comment
|
||||
func (c *Comment) APIURL() string {
|
||||
err := c.LoadIssue()
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
@ -426,7 +422,7 @@ func (c *Comment) APIURL() string {
|
||||
|
||||
// IssueURL formats a URL-string to the issue
|
||||
func (c *Comment) IssueURL() string {
|
||||
err := c.LoadIssue()
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
@ -446,7 +442,7 @@ func (c *Comment) IssueURL() string {
|
||||
|
||||
// PRURL formats a URL-string to the pull-request
|
||||
func (c *Comment) PRURL() string {
|
||||
err := c.LoadIssue()
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
@ -521,10 +517,10 @@ func (c *Comment) LoadProject() error {
|
||||
}
|
||||
|
||||
// LoadMilestone if comment.Type is CommentTypeMilestone, then load milestone
|
||||
func (c *Comment) LoadMilestone() error {
|
||||
func (c *Comment) LoadMilestone(ctx context.Context) error {
|
||||
if c.OldMilestoneID > 0 {
|
||||
var oldMilestone Milestone
|
||||
has, err := db.GetEngine(db.DefaultContext).ID(c.OldMilestoneID).Get(&oldMilestone)
|
||||
has, err := db.GetEngine(ctx).ID(c.OldMilestoneID).Get(&oldMilestone)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
@ -534,7 +530,7 @@ func (c *Comment) LoadMilestone() error {
|
||||
|
||||
if c.MilestoneID > 0 {
|
||||
var milestone Milestone
|
||||
has, err := db.GetEngine(db.DefaultContext).ID(c.MilestoneID).Get(&milestone)
|
||||
has, err := db.GetEngine(ctx).ID(c.MilestoneID).Get(&milestone)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
@ -544,19 +540,14 @@ func (c *Comment) LoadMilestone() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadPoster loads comment poster
|
||||
func (c *Comment) LoadPoster() error {
|
||||
return c.loadPoster(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadAttachments loads attachments (it never returns error, the error during `GetAttachmentsByCommentIDCtx` is ignored)
|
||||
func (c *Comment) LoadAttachments() error {
|
||||
func (c *Comment) LoadAttachments(ctx context.Context) error {
|
||||
if len(c.Attachments) > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
c.Attachments, err = repo_model.GetAttachmentsByCommentID(db.DefaultContext, c.ID)
|
||||
c.Attachments, err = repo_model.GetAttachmentsByCommentID(ctx, c.ID)
|
||||
if err != nil {
|
||||
log.Error("getAttachmentsByCommentID[%d]: %v", c.ID, err)
|
||||
}
|
||||
@ -565,7 +556,7 @@ func (c *Comment) LoadAttachments() error {
|
||||
|
||||
// UpdateAttachments update attachments by UUIDs for the comment
|
||||
func (c *Comment) UpdateAttachments(uuids []string) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -598,7 +589,7 @@ func (c *Comment) LoadAssigneeUserAndTeam() error {
|
||||
c.Assignee = user_model.NewGhostUser()
|
||||
}
|
||||
} else if c.AssigneeTeamID > 0 && c.AssigneeTeam == nil {
|
||||
if err = c.LoadIssue(); err != nil {
|
||||
if err = c.LoadIssue(db.DefaultContext); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -740,7 +731,7 @@ func (c *Comment) UnsignedLine() uint64 {
|
||||
|
||||
// CodeCommentURL returns the url to a comment in code
|
||||
func (c *Comment) CodeCommentURL() string {
|
||||
err := c.LoadIssue()
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
@ -1003,7 +994,7 @@ type CreateCommentOptions struct {
|
||||
|
||||
// CreateComment creates comment of issue or commit.
|
||||
func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1135,7 +1126,7 @@ func CountComments(opts *FindCommentsOptions) (int64, error) {
|
||||
|
||||
// UpdateComment updates information of comment.
|
||||
func UpdateComment(c *Comment, doer *user_model.User) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1145,7 +1136,7 @@ func UpdateComment(c *Comment, doer *user_model.User) error {
|
||||
if _, err := sess.ID(c.ID).AllCols().Update(c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.LoadIssueCtx(ctx); err != nil {
|
||||
if err := c.LoadIssue(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.AddCrossReferences(ctx, doer, true); err != nil {
|
||||
@ -1245,7 +1236,7 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := CommentList(comments).loadPosters(ctx); err != nil {
|
||||
if err := CommentList(comments).LoadPosters(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -1363,11 +1354,11 @@ func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullReques
|
||||
if typ != CommentTypePRScheduledToAutoMerge && typ != CommentTypePRUnScheduledToAutoMerge {
|
||||
return nil, fmt.Errorf("comment type %d cannot be used to create an auto merge comment", typ)
|
||||
}
|
||||
if err = pr.LoadIssueCtx(ctx); err != nil {
|
||||
if err = pr.LoadIssue(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = pr.LoadBaseRepoCtx(ctx); err != nil {
|
||||
if err = pr.LoadBaseRepo(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -1512,18 +1503,18 @@ func (c *Comment) GetExternalName() string { return c.OriginalAuthor }
|
||||
func (c *Comment) GetExternalID() int64 { return c.OriginalAuthorID }
|
||||
|
||||
// CountCommentTypeLabelWithEmptyLabel count label comments with empty label
|
||||
func CountCommentTypeLabelWithEmptyLabel() (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Count(new(Comment))
|
||||
func CountCommentTypeLabelWithEmptyLabel(ctx context.Context) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Count(new(Comment))
|
||||
}
|
||||
|
||||
// FixCommentTypeLabelWithEmptyLabel count label comments with empty label
|
||||
func FixCommentTypeLabelWithEmptyLabel() (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Delete(new(Comment))
|
||||
func FixCommentTypeLabelWithEmptyLabel(ctx context.Context) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Delete(new(Comment))
|
||||
}
|
||||
|
||||
// CountCommentTypeLabelWithOutsideLabels count label comments with outside label
|
||||
func CountCommentTypeLabelWithOutsideLabels() (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where("comment.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id))", CommentTypeLabel).
|
||||
func CountCommentTypeLabelWithOutsideLabels(ctx context.Context) (int64, error) {
|
||||
return db.GetEngine(ctx).Where("comment.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id))", CommentTypeLabel).
|
||||
Table("comment").
|
||||
Join("inner", "label", "label.id = comment.label_id").
|
||||
Join("inner", "issue", "issue.id = comment.issue_id ").
|
||||
@ -1532,8 +1523,8 @@ func CountCommentTypeLabelWithOutsideLabels() (int64, error) {
|
||||
}
|
||||
|
||||
// FixCommentTypeLabelWithOutsideLabels count label comments with outside label
|
||||
func FixCommentTypeLabelWithOutsideLabels() (int64, error) {
|
||||
res, err := db.GetEngine(db.DefaultContext).Exec(`DELETE FROM comment WHERE comment.id IN (
|
||||
func FixCommentTypeLabelWithOutsideLabels(ctx context.Context) (int64, error) {
|
||||
res, err := db.GetEngine(ctx).Exec(`DELETE FROM comment WHERE comment.id IN (
|
||||
SELECT il_too.id FROM (
|
||||
SELECT com.id
|
||||
FROM comment AS com
|
||||
|
@ -24,7 +24,8 @@ func (comments CommentList) getPosterIDs() []int64 {
|
||||
return posterIDs.Values()
|
||||
}
|
||||
|
||||
func (comments CommentList) loadPosters(ctx context.Context) error {
|
||||
// LoadPosters loads posters
|
||||
func (comments CommentList) LoadPosters(ctx context.Context) error {
|
||||
if len(comments) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -277,7 +278,8 @@ func (comments CommentList) Issues() IssueList {
|
||||
return issueList
|
||||
}
|
||||
|
||||
func (comments CommentList) loadIssues(ctx context.Context) error {
|
||||
// LoadIssues loads issues of comments
|
||||
func (comments CommentList) LoadIssues(ctx context.Context) error {
|
||||
if len(comments) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -382,7 +384,8 @@ func (comments CommentList) loadDependentIssues(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (comments CommentList) loadAttachments(ctx context.Context) (err error) {
|
||||
// LoadAttachments loads attachments
|
||||
func (comments CommentList) LoadAttachments(ctx context.Context) (err error) {
|
||||
if len(comments) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -476,7 +479,7 @@ func (comments CommentList) loadReviews(ctx context.Context) error { //nolint
|
||||
|
||||
// loadAttributes loads all attributes
|
||||
func (comments CommentList) loadAttributes(ctx context.Context) (err error) {
|
||||
if err = comments.loadPosters(ctx); err != nil {
|
||||
if err = comments.LoadPosters(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -496,7 +499,7 @@ func (comments CommentList) loadAttributes(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = comments.loadAttachments(ctx); err != nil {
|
||||
if err = comments.LoadAttachments(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -504,7 +507,7 @@ func (comments CommentList) loadAttributes(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = comments.loadIssues(ctx); err != nil {
|
||||
if err = comments.LoadIssues(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -520,18 +523,3 @@ func (comments CommentList) loadAttributes(ctx context.Context) (err error) {
|
||||
func (comments CommentList) LoadAttributes() error {
|
||||
return comments.loadAttributes(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadAttachments loads attachments
|
||||
func (comments CommentList) LoadAttachments() error {
|
||||
return comments.loadAttachments(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadPosters loads posters
|
||||
func (comments CommentList) LoadPosters() error {
|
||||
return comments.loadPosters(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadIssues loads issues of comments
|
||||
func (comments CommentList) LoadIssues() error {
|
||||
return comments.loadIssues(db.DefaultContext)
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ const (
|
||||
|
||||
// CreateIssueDependency creates a new dependency for an issue
|
||||
func CreateIssueDependency(user *user_model.User, issue, dep *Issue) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -170,7 +170,7 @@ func CreateIssueDependency(user *user_model.User, issue, dep *Issue) error {
|
||||
|
||||
// RemoveIssueDependency removes a dependency from an issue
|
||||
func RemoveIssueDependency(user *user_model.User, issue, dep *Issue, depType DependencyType) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -241,11 +241,7 @@ func (issue *Issue) LoadLabels(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
// LoadPoster loads poster
|
||||
func (issue *Issue) LoadPoster() error {
|
||||
return issue.loadPoster(db.DefaultContext)
|
||||
}
|
||||
|
||||
func (issue *Issue) loadPoster(ctx context.Context) (err error) {
|
||||
func (issue *Issue) LoadPoster(ctx context.Context) (err error) {
|
||||
if issue.Poster == nil {
|
||||
issue.Poster, err = user_model.GetUserByIDCtx(ctx, issue.PosterID)
|
||||
if err != nil {
|
||||
@ -261,7 +257,8 @@ func (issue *Issue) loadPoster(ctx context.Context) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (issue *Issue) loadPullRequest(ctx context.Context) (err error) {
|
||||
// LoadPullRequest loads pull request info
|
||||
func (issue *Issue) LoadPullRequest(ctx context.Context) (err error) {
|
||||
if issue.IsPull && issue.PullRequest == nil {
|
||||
issue.PullRequest, err = GetPullRequestByIssueID(ctx, issue.ID)
|
||||
if err != nil {
|
||||
@ -275,18 +272,13 @@ func (issue *Issue) loadPullRequest(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadPullRequest loads pull request info
|
||||
func (issue *Issue) LoadPullRequest() error {
|
||||
return issue.loadPullRequest(db.DefaultContext)
|
||||
}
|
||||
|
||||
func (issue *Issue) loadComments(ctx context.Context) (err error) {
|
||||
return issue.loadCommentsByType(ctx, CommentTypeUnknown)
|
||||
}
|
||||
|
||||
// LoadDiscussComments loads discuss comments
|
||||
func (issue *Issue) LoadDiscussComments() error {
|
||||
return issue.loadCommentsByType(db.DefaultContext, CommentTypeComment)
|
||||
func (issue *Issue) LoadDiscussComments(ctx context.Context) error {
|
||||
return issue.loadCommentsByType(ctx, CommentTypeComment)
|
||||
}
|
||||
|
||||
func (issue *Issue) loadCommentsByType(ctx context.Context, tp CommentType) (err error) {
|
||||
@ -357,7 +349,8 @@ func (issue *Issue) loadForeignReference(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (issue *Issue) loadMilestone(ctx context.Context) (err error) {
|
||||
// LoadMilestone load milestone of this issue.
|
||||
func (issue *Issue) LoadMilestone(ctx context.Context) (err error) {
|
||||
if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 {
|
||||
issue.Milestone, err = GetMilestoneByRepoID(ctx, issue.RepoID, issue.MilestoneID)
|
||||
if err != nil && !IsErrMilestoneNotExist(err) {
|
||||
@ -373,7 +366,7 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = issue.loadPoster(ctx); err != nil {
|
||||
if err = issue.LoadPoster(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -381,7 +374,7 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = issue.loadMilestone(ctx); err != nil {
|
||||
if err = issue.LoadMilestone(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -393,7 +386,7 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = issue.loadPullRequest(ctx); err != nil && !IsErrPullRequestNotExist(err) {
|
||||
if err = issue.LoadPullRequest(ctx); err != nil && !IsErrPullRequestNotExist(err) {
|
||||
// It is possible pull request is not yet created.
|
||||
return err
|
||||
}
|
||||
@ -425,11 +418,6 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
|
||||
return issue.loadReactions(ctx)
|
||||
}
|
||||
|
||||
// LoadMilestone load milestone of this issue.
|
||||
func (issue *Issue) LoadMilestone() error {
|
||||
return issue.loadMilestone(db.DefaultContext)
|
||||
}
|
||||
|
||||
// GetIsRead load the `IsRead` field of the issue
|
||||
func (issue *Issue) GetIsRead(userID int64) error {
|
||||
issueUser := &IssueUser{IssueID: issue.ID, UID: userID}
|
||||
@ -540,7 +528,7 @@ func clearIssueLabels(ctx context.Context, issue *Issue, doer *user_model.User)
|
||||
// ClearIssueLabels removes all issue labels as the given user.
|
||||
// Triggers appropriate WebHooks, if any.
|
||||
func ClearIssueLabels(issue *Issue, doer *user_model.User) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -548,7 +536,7 @@ func ClearIssueLabels(issue *Issue, doer *user_model.User) (err error) {
|
||||
|
||||
if err := issue.LoadRepo(ctx); err != nil {
|
||||
return err
|
||||
} else if err = issue.loadPullRequest(ctx); err != nil {
|
||||
} else if err = issue.LoadPullRequest(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -588,7 +576,7 @@ func (ts labelSorter) Swap(i, j int) {
|
||||
// ReplaceIssueLabels removes all current labels and add new labels to the issue.
|
||||
// Triggers appropriate WebHooks, if any.
|
||||
func ReplaceIssueLabels(issue *Issue, labels []*Label, doer *user_model.User) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -751,7 +739,7 @@ func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User,
|
||||
if err := issue.LoadRepo(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := issue.loadPoster(ctx); err != nil {
|
||||
if err := issue.LoadPoster(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -760,7 +748,7 @@ func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User,
|
||||
|
||||
// ChangeIssueTitle changes the title of this issue, as the given user.
|
||||
func ChangeIssueTitle(issue *Issue, doer *user_model.User, oldTitle string) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -794,7 +782,7 @@ func ChangeIssueTitle(issue *Issue, doer *user_model.User, oldTitle string) (err
|
||||
|
||||
// ChangeIssueRef changes the branch of this issue, as the given user.
|
||||
func ChangeIssueRef(issue *Issue, doer *user_model.User, oldRef string) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -844,7 +832,7 @@ func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo *
|
||||
|
||||
// UpdateIssueAttachments update attachments by UUIDs for the issue
|
||||
func UpdateIssueAttachments(issueID int64, uuids []string) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -864,7 +852,7 @@ func UpdateIssueAttachments(issueID int64, uuids []string) (err error) {
|
||||
|
||||
// ChangeIssueContent changes issue content, as the given user.
|
||||
func ChangeIssueContent(issue *Issue, doer *user_model.User, content string) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1027,7 +1015,7 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue
|
||||
return fmt.Errorf("find all labels [label_ids: %v]: %w", opts.LabelIDs, err)
|
||||
}
|
||||
|
||||
if err = opts.Issue.loadPoster(ctx); err != nil {
|
||||
if err = opts.Issue.LoadPoster(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -1069,7 +1057,7 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue
|
||||
|
||||
// NewIssue creates new issue with labels for repository.
|
||||
func NewIssue(repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1505,10 +1493,9 @@ func applySubscribedCondition(sess *xorm.Session, subscriberID int64) *xorm.Sess
|
||||
}
|
||||
|
||||
// CountIssuesByRepo map from repoID to number of issues matching the options
|
||||
func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
|
||||
e := db.GetEngine(db.DefaultContext)
|
||||
|
||||
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
func CountIssuesByRepo(ctx context.Context, opts *IssuesOptions) (map[int64]int64, error) {
|
||||
sess := db.GetEngine(ctx).
|
||||
Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
|
||||
opts.setupSessionNoLimit(sess)
|
||||
|
||||
@ -1551,10 +1538,9 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i
|
||||
}
|
||||
|
||||
// Issues returns a list of issues by given conditions.
|
||||
func Issues(opts *IssuesOptions) ([]*Issue, error) {
|
||||
e := db.GetEngine(db.DefaultContext)
|
||||
|
||||
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
func Issues(ctx context.Context, opts *IssuesOptions) ([]*Issue, error) {
|
||||
sess := db.GetEngine(ctx).
|
||||
Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
opts.setupSessionWithLimit(sess)
|
||||
|
||||
sortIssuesSession(sess, opts.SortType, opts.PriorityRepoID)
|
||||
@ -1572,11 +1558,11 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
|
||||
}
|
||||
|
||||
// CountIssues number return of issues by given conditions.
|
||||
func CountIssues(opts *IssuesOptions) (int64, error) {
|
||||
e := db.GetEngine(db.DefaultContext)
|
||||
|
||||
sess := e.Select("COUNT(issue.id) AS count").Table("issue")
|
||||
sess.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
func CountIssues(ctx context.Context, opts *IssuesOptions) (int64, error) {
|
||||
sess := db.GetEngine(ctx).
|
||||
Select("COUNT(issue.id) AS count").
|
||||
Table("issue").
|
||||
Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
opts.setupSessionNoLimit(sess)
|
||||
|
||||
return sess.Count()
|
||||
@ -1585,9 +1571,10 @@ func CountIssues(opts *IssuesOptions) (int64, error) {
|
||||
// GetParticipantsIDsByIssueID returns the IDs of all users who participated in comments of an issue,
|
||||
// but skips joining with `user` for performance reasons.
|
||||
// User permissions must be verified elsewhere if required.
|
||||
func GetParticipantsIDsByIssueID(issueID int64) ([]int64, error) {
|
||||
func GetParticipantsIDsByIssueID(ctx context.Context, issueID int64) ([]int64, error) {
|
||||
userIDs := make([]int64, 0, 5)
|
||||
return userIDs, db.GetEngine(db.DefaultContext).Table("comment").
|
||||
return userIDs, db.GetEngine(ctx).
|
||||
Table("comment").
|
||||
Cols("poster_id").
|
||||
Where("issue_id = ?", issueID).
|
||||
And("type in (?,?,?)", CommentTypeComment, CommentTypeCode, CommentTypeReview).
|
||||
@ -1986,7 +1973,7 @@ func SearchIssueIDsByKeyword(ctx context.Context, kw string, repoIDs []int64, li
|
||||
// If the issue status is changed a statusChangeComment is returned
|
||||
// similarly if the title is changed the titleChanged bool is set to true
|
||||
func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment *Comment, titleChanged bool, err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
@ -2044,7 +2031,7 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *us
|
||||
if issue.DeadlineUnix == deadlineUnix {
|
||||
return nil
|
||||
}
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -2426,8 +2413,9 @@ func (issue *Issue) GetExternalName() string { return issue.OriginalAuthor }
|
||||
func (issue *Issue) GetExternalID() int64 { return issue.OriginalAuthorID }
|
||||
|
||||
// CountOrphanedIssues count issues without a repo
|
||||
func CountOrphanedIssues() (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Table("issue").
|
||||
func CountOrphanedIssues(ctx context.Context) (int64, error) {
|
||||
return db.GetEngine(ctx).
|
||||
Table("issue").
|
||||
Join("LEFT", "repository", "issue.repo_id=repository.id").
|
||||
Where(builder.IsNull{"repository.id"}).
|
||||
Select("COUNT(`issue`.`id`)").
|
||||
@ -2435,35 +2423,31 @@ func CountOrphanedIssues() (int64, error) {
|
||||
}
|
||||
|
||||
// DeleteOrphanedIssues delete issues without a repo
|
||||
func DeleteOrphanedIssues() error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
func DeleteOrphanedIssues(ctx context.Context) error {
|
||||
var attachmentPaths []string
|
||||
err := db.AutoTx(ctx, func(ctx context.Context) error {
|
||||
var ids []int64
|
||||
|
||||
if err := db.GetEngine(ctx).Table("issue").Distinct("issue.repo_id").
|
||||
Join("LEFT", "repository", "issue.repo_id=repository.id").
|
||||
Where(builder.IsNull{"repository.id"}).GroupBy("issue.repo_id").
|
||||
Find(&ids); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range ids {
|
||||
paths, err := DeleteIssuesByRepoID(ctx, ids[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attachmentPaths = append(attachmentPaths, paths...)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
|
||||
var ids []int64
|
||||
|
||||
if err := db.GetEngine(ctx).Table("issue").Distinct("issue.repo_id").
|
||||
Join("LEFT", "repository", "issue.repo_id=repository.id").
|
||||
Where(builder.IsNull{"repository.id"}).GroupBy("issue.repo_id").
|
||||
Find(&ids); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var attachmentPaths []string
|
||||
for i := range ids {
|
||||
paths, err := DeleteIssuesByRepoID(ctx, ids[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attachmentPaths = append(attachmentPaths, paths...)
|
||||
}
|
||||
|
||||
if err := committer.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
committer.Close()
|
||||
|
||||
// Remove issue attachment files.
|
||||
for i := range attachmentPaths {
|
||||
|
@ -9,7 +9,7 @@ import "code.gitea.io/gitea/models/db"
|
||||
// RecalculateIssueIndexForRepo create issue_index for repo if not exist and
|
||||
// update it based on highest index of existing issues assigned to a repo
|
||||
func RecalculateIssueIndexForRepo(repoID int64) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -34,7 +34,8 @@ func (issues IssueList) getRepoIDs() []int64 {
|
||||
return repoIDs.Values()
|
||||
}
|
||||
|
||||
func (issues IssueList) loadRepositories(ctx context.Context) ([]*repo_model.Repository, error) {
|
||||
// LoadRepositories loads issues' all repositories
|
||||
func (issues IssueList) LoadRepositories(ctx context.Context) ([]*repo_model.Repository, error) {
|
||||
if len(issues) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@ -73,11 +74,6 @@ func (issues IssueList) loadRepositories(ctx context.Context) ([]*repo_model.Rep
|
||||
return repo_model.ValuesRepository(repoMaps), nil
|
||||
}
|
||||
|
||||
// LoadRepositories loads issues' all repositories
|
||||
func (issues IssueList) LoadRepositories() ([]*repo_model.Repository, error) {
|
||||
return issues.loadRepositories(db.DefaultContext)
|
||||
}
|
||||
|
||||
func (issues IssueList) getPosterIDs() []int64 {
|
||||
posterIDs := make(container.Set[int64], len(issues))
|
||||
for _, issue := range issues {
|
||||
@ -317,7 +313,8 @@ func (issues IssueList) getPullIssueIDs() []int64 {
|
||||
return ids
|
||||
}
|
||||
|
||||
func (issues IssueList) loadPullRequests(ctx context.Context) error {
|
||||
// LoadPullRequests loads pull requests
|
||||
func (issues IssueList) LoadPullRequests(ctx context.Context) error {
|
||||
issuesIDs := issues.getPullIssueIDs()
|
||||
if len(issuesIDs) == 0 {
|
||||
return nil
|
||||
@ -361,7 +358,8 @@ func (issues IssueList) loadPullRequests(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (issues IssueList) loadAttachments(ctx context.Context) (err error) {
|
||||
// LoadAttachments loads attachments
|
||||
func (issues IssueList) LoadAttachments(ctx context.Context) (err error) {
|
||||
if len(issues) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -513,8 +511,8 @@ func (issues IssueList) loadTotalTrackedTimes(ctx context.Context) (err error) {
|
||||
|
||||
// loadAttributes loads all attributes, expect for attachments and comments
|
||||
func (issues IssueList) loadAttributes(ctx context.Context) error {
|
||||
if _, err := issues.loadRepositories(ctx); err != nil {
|
||||
return fmt.Errorf("issue.loadAttributes: loadRepositories: %w", err)
|
||||
if _, err := issues.LoadRepositories(ctx); err != nil {
|
||||
return fmt.Errorf("issue.loadAttributes: LoadRepositories: %w", err)
|
||||
}
|
||||
|
||||
if err := issues.loadPosters(ctx); err != nil {
|
||||
@ -537,7 +535,7 @@ func (issues IssueList) loadAttributes(ctx context.Context) error {
|
||||
return fmt.Errorf("issue.loadAttributes: loadAssignees: %w", err)
|
||||
}
|
||||
|
||||
if err := issues.loadPullRequests(ctx); err != nil {
|
||||
if err := issues.LoadPullRequests(ctx); err != nil {
|
||||
return fmt.Errorf("issue.loadAttributes: loadPullRequests: %w", err)
|
||||
}
|
||||
|
||||
@ -554,24 +552,14 @@ func (issues IssueList) LoadAttributes() error {
|
||||
return issues.loadAttributes(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadAttachments loads attachments
|
||||
func (issues IssueList) LoadAttachments() error {
|
||||
return issues.loadAttachments(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadComments loads comments
|
||||
func (issues IssueList) LoadComments() error {
|
||||
return issues.loadComments(db.DefaultContext, builder.NewCond())
|
||||
func (issues IssueList) LoadComments(ctx context.Context) error {
|
||||
return issues.loadComments(ctx, builder.NewCond())
|
||||
}
|
||||
|
||||
// LoadDiscussComments loads discuss comments
|
||||
func (issues IssueList) LoadDiscussComments() error {
|
||||
return issues.loadComments(db.DefaultContext, builder.Eq{"comment.type": CommentTypeComment})
|
||||
}
|
||||
|
||||
// LoadPullRequests loads pull requests
|
||||
func (issues IssueList) LoadPullRequests() error {
|
||||
return issues.loadPullRequests(db.DefaultContext)
|
||||
func (issues IssueList) LoadDiscussComments(ctx context.Context) error {
|
||||
return issues.loadComments(ctx, builder.Eq{"comment.type": CommentTypeComment})
|
||||
}
|
||||
|
||||
// GetApprovalCounts returns a map of issue ID to slice of approval counts
|
||||
|
@ -7,6 +7,7 @@ package issues_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@ -23,7 +24,7 @@ func TestIssueList_LoadRepositories(t *testing.T) {
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}),
|
||||
}
|
||||
|
||||
repos, err := issueList.LoadRepositories()
|
||||
repos, err := issueList.LoadRepositories(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, repos, 2)
|
||||
for _, issue := range issueList {
|
||||
|
@ -40,7 +40,7 @@ func updateIssueLock(opts *IssueLockOptions, lock bool) error {
|
||||
commentType = CommentTypeUnlock
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -61,11 +61,11 @@ func (issue *Issue) projectBoardID(ctx context.Context) int64 {
|
||||
}
|
||||
|
||||
// LoadIssuesFromBoard load issues assigned to this board
|
||||
func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) {
|
||||
func LoadIssuesFromBoard(ctx context.Context, b *project_model.Board) (IssueList, error) {
|
||||
issueList := make([]*Issue, 0, 10)
|
||||
|
||||
if b.ID != 0 {
|
||||
issues, err := Issues(&IssuesOptions{
|
||||
issues, err := Issues(ctx, &IssuesOptions{
|
||||
ProjectBoardID: b.ID,
|
||||
ProjectID: b.ProjectID,
|
||||
SortType: "project-column-sorting",
|
||||
@ -77,7 +77,7 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) {
|
||||
}
|
||||
|
||||
if b.Default {
|
||||
issues, err := Issues(&IssuesOptions{
|
||||
issues, err := Issues(ctx, &IssuesOptions{
|
||||
ProjectBoardID: -1, // Issues without ProjectBoardID
|
||||
ProjectID: b.ProjectID,
|
||||
SortType: "project-column-sorting",
|
||||
@ -88,7 +88,7 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) {
|
||||
issueList = append(issueList, issues...)
|
||||
}
|
||||
|
||||
if err := IssueList(issueList).LoadComments(); err != nil {
|
||||
if err := IssueList(issueList).LoadComments(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -96,10 +96,10 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) {
|
||||
}
|
||||
|
||||
// LoadIssuesFromBoardList load issues assigned to the boards
|
||||
func LoadIssuesFromBoardList(bs project_model.BoardList) (map[int64]IssueList, error) {
|
||||
func LoadIssuesFromBoardList(ctx context.Context, bs project_model.BoardList) (map[int64]IssueList, error) {
|
||||
issuesMap := make(map[int64]IssueList, len(bs))
|
||||
for i := range bs {
|
||||
il, err := LoadIssuesFromBoard(bs[i])
|
||||
il, err := LoadIssuesFromBoard(ctx, bs[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -110,7 +110,7 @@ func LoadIssuesFromBoardList(bs project_model.BoardList) (map[int64]IssueList, e
|
||||
|
||||
// ChangeProjectAssign changes the project associated with an issue
|
||||
func ChangeProjectAssign(issue *Issue, doer *user_model.User, newProjectID int64) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -166,7 +166,7 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U
|
||||
|
||||
// MoveIssueAcrossProjectBoards move a card from one board to another
|
||||
func MoveIssueAcrossProjectBoards(issue *Issue, board *project_model.Board) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ func TestIssues(t *testing.T) {
|
||||
[]int64{}, // issues with **both** label 1 and 2, none of these issues matches, TODO: add more tests
|
||||
},
|
||||
} {
|
||||
issues, err := issues_model.Issues(&test.Opts)
|
||||
issues, err := issues_model.Issues(db.DefaultContext, &test.Opts)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, issues, len(test.ExpectedIssueIDs)) {
|
||||
for i, issue := range issues {
|
||||
@ -556,7 +556,7 @@ func TestLoadTotalTrackedTime(t *testing.T) {
|
||||
|
||||
func TestCountIssues(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
count, err := issues_model.CountIssues(&issues_model.IssuesOptions{})
|
||||
count, err := issues_model.CountIssues(db.DefaultContext, &issues_model.IssuesOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 17, count)
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ func (c *Comment) AddCrossReferences(stdCtx context.Context, doer *user_model.Us
|
||||
if c.Type != CommentTypeCode && c.Type != CommentTypeComment {
|
||||
return nil
|
||||
}
|
||||
if err := c.LoadIssueCtx(stdCtx); err != nil {
|
||||
if err := c.LoadIssue(stdCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
ctx := &crossReferencesContext{
|
||||
|
@ -131,7 +131,7 @@ func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispu
|
||||
r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo})
|
||||
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer})
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
defer committer.Close()
|
||||
|
||||
@ -174,7 +174,7 @@ func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *i
|
||||
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue})
|
||||
c := &issues_model.Comment{Type: issues_model.CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
defer committer.Close()
|
||||
err = db.Insert(ctx, c)
|
||||
|
@ -116,8 +116,8 @@ func (label *Label) CalOpenIssues() {
|
||||
}
|
||||
|
||||
// CalOpenOrgIssues calculates the open issues of a label for a specific repo
|
||||
func (label *Label) CalOpenOrgIssues(repoID, labelID int64) {
|
||||
counts, _ := CountIssuesByRepo(&IssuesOptions{
|
||||
func (label *Label) CalOpenOrgIssues(ctx context.Context, repoID, labelID int64) {
|
||||
counts, _ := CountIssuesByRepo(ctx, &IssuesOptions{
|
||||
RepoID: repoID,
|
||||
LabelIDs: []int64{labelID},
|
||||
IsClosed: util.OptionalBoolFalse,
|
||||
@ -232,7 +232,7 @@ func NewLabel(ctx context.Context, label *Label) error {
|
||||
|
||||
// NewLabels creates new labels
|
||||
func NewLabels(labels ...*Label) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -267,7 +267,7 @@ func DeleteLabel(id, labelID int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -395,9 +395,9 @@ func BuildLabelNamesIssueIDsCondition(labelNames []string) *builder.Builder {
|
||||
|
||||
// GetLabelsInRepoByIDs returns a list of labels by IDs in given repository,
|
||||
// it silently ignores label IDs that do not belong to the repository.
|
||||
func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) {
|
||||
func GetLabelsInRepoByIDs(ctx context.Context, repoID int64, labelIDs []int64) ([]*Label, error) {
|
||||
labels := make([]*Label, 0, len(labelIDs))
|
||||
return labels, db.GetEngine(db.DefaultContext).
|
||||
return labels, db.GetEngine(ctx).
|
||||
Where("repo_id = ?", repoID).
|
||||
In("id", labelIDs).
|
||||
Asc("name").
|
||||
@ -498,9 +498,9 @@ func GetLabelIDsInOrgByNames(orgID int64, labelNames []string) ([]int64, error)
|
||||
|
||||
// GetLabelsInOrgByIDs returns a list of labels by IDs in given organization,
|
||||
// it silently ignores label IDs that do not belong to the organization.
|
||||
func GetLabelsInOrgByIDs(orgID int64, labelIDs []int64) ([]*Label, error) {
|
||||
func GetLabelsInOrgByIDs(ctx context.Context, orgID int64, labelIDs []int64) ([]*Label, error) {
|
||||
labels := make([]*Label, 0, len(labelIDs))
|
||||
return labels, db.GetEngine(db.DefaultContext).
|
||||
return labels, db.GetEngine(ctx).
|
||||
Where("org_id = ?", orgID).
|
||||
In("id", labelIDs).
|
||||
Asc("name").
|
||||
@ -627,7 +627,7 @@ func NewIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -676,7 +676,7 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
|
||||
|
||||
// NewIssueLabels creates a list of issue-label relations.
|
||||
func NewIssueLabels(issue *Issue, labels []*Label, doer *user_model.User) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -746,13 +746,13 @@ func DeleteLabelsByRepoID(ctx context.Context, repoID int64) error {
|
||||
}
|
||||
|
||||
// CountOrphanedLabels return count of labels witch are broken and not accessible via ui anymore
|
||||
func CountOrphanedLabels() (int64, error) {
|
||||
noref, err := db.GetEngine(db.DefaultContext).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Count()
|
||||
func CountOrphanedLabels(ctx context.Context) (int64, error) {
|
||||
noref, err := db.GetEngine(ctx).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Count()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
norepo, err := db.GetEngine(db.DefaultContext).Table("label").
|
||||
norepo, err := db.GetEngine(ctx).Table("label").
|
||||
Where(builder.And(
|
||||
builder.Gt{"repo_id": 0},
|
||||
builder.NotIn("repo_id", builder.Select("id").From("repository")),
|
||||
@ -762,7 +762,7 @@ func CountOrphanedLabels() (int64, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
noorg, err := db.GetEngine(db.DefaultContext).Table("label").
|
||||
noorg, err := db.GetEngine(ctx).Table("label").
|
||||
Where(builder.And(
|
||||
builder.Gt{"org_id": 0},
|
||||
builder.NotIn("org_id", builder.Select("id").From("user")),
|
||||
@ -776,14 +776,14 @@ func CountOrphanedLabels() (int64, error) {
|
||||
}
|
||||
|
||||
// DeleteOrphanedLabels delete labels witch are broken and not accessible via ui anymore
|
||||
func DeleteOrphanedLabels() error {
|
||||
func DeleteOrphanedLabels(ctx context.Context) error {
|
||||
// delete labels with no reference
|
||||
if _, err := db.GetEngine(db.DefaultContext).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Delete(new(Label)); err != nil {
|
||||
if _, err := db.GetEngine(ctx).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Delete(new(Label)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// delete labels with none existing repos
|
||||
if _, err := db.GetEngine(db.DefaultContext).
|
||||
if _, err := db.GetEngine(ctx).
|
||||
Where(builder.And(
|
||||
builder.Gt{"repo_id": 0},
|
||||
builder.NotIn("repo_id", builder.Select("id").From("repository")),
|
||||
@ -793,7 +793,7 @@ func DeleteOrphanedLabels() error {
|
||||
}
|
||||
|
||||
// delete labels with none existing orgs
|
||||
if _, err := db.GetEngine(db.DefaultContext).
|
||||
if _, err := db.GetEngine(ctx).
|
||||
Where(builder.And(
|
||||
builder.Gt{"org_id": 0},
|
||||
builder.NotIn("org_id", builder.Select("id").From("user")),
|
||||
@ -806,23 +806,23 @@ func DeleteOrphanedLabels() error {
|
||||
}
|
||||
|
||||
// CountOrphanedIssueLabels return count of IssueLabels witch have no label behind anymore
|
||||
func CountOrphanedIssueLabels() (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Table("issue_label").
|
||||
func CountOrphanedIssueLabels(ctx context.Context) (int64, error) {
|
||||
return db.GetEngine(ctx).Table("issue_label").
|
||||
NotIn("label_id", builder.Select("id").From("label")).
|
||||
Count()
|
||||
}
|
||||
|
||||
// DeleteOrphanedIssueLabels delete IssueLabels witch have no label behind anymore
|
||||
func DeleteOrphanedIssueLabels() error {
|
||||
_, err := db.GetEngine(db.DefaultContext).
|
||||
func DeleteOrphanedIssueLabels(ctx context.Context) error {
|
||||
_, err := db.GetEngine(ctx).
|
||||
NotIn("label_id", builder.Select("id").From("label")).
|
||||
Delete(IssueLabel{})
|
||||
return err
|
||||
}
|
||||
|
||||
// CountIssueLabelWithOutsideLabels count label comments with outside label
|
||||
func CountIssueLabelWithOutsideLabels() (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where(builder.Expr("(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)")).
|
||||
func CountIssueLabelWithOutsideLabels(ctx context.Context) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(builder.Expr("(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)")).
|
||||
Table("issue_label").
|
||||
Join("inner", "label", "issue_label.label_id = label.id ").
|
||||
Join("inner", "issue", "issue.id = issue_label.issue_id ").
|
||||
@ -831,8 +831,8 @@ func CountIssueLabelWithOutsideLabels() (int64, error) {
|
||||
}
|
||||
|
||||
// FixIssueLabelWithOutsideLabels fix label comments with outside label
|
||||
func FixIssueLabelWithOutsideLabels() (int64, error) {
|
||||
res, err := db.GetEngine(db.DefaultContext).Exec(`DELETE FROM issue_label WHERE issue_label.id IN (
|
||||
func FixIssueLabelWithOutsideLabels(ctx context.Context) (int64, error) {
|
||||
res, err := db.GetEngine(ctx).Exec(`DELETE FROM issue_label WHERE issue_label.id IN (
|
||||
SELECT il_too.id FROM (
|
||||
SELECT il_too_too.id
|
||||
FROM issue_label AS il_too_too
|
||||
|
@ -121,7 +121,7 @@ func TestGetLabelInRepoByID(t *testing.T) {
|
||||
|
||||
func TestGetLabelsInRepoByIDs(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
labels, err := issues_model.GetLabelsInRepoByIDs(1, []int64{1, 2, unittest.NonexistentID})
|
||||
labels, err := issues_model.GetLabelsInRepoByIDs(db.DefaultContext, 1, []int64{1, 2, unittest.NonexistentID})
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, labels, 2) {
|
||||
assert.EqualValues(t, 1, labels[0].ID)
|
||||
@ -212,7 +212,7 @@ func TestGetLabelInOrgByID(t *testing.T) {
|
||||
|
||||
func TestGetLabelsInOrgByIDs(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
labels, err := issues_model.GetLabelsInOrgByIDs(3, []int64{3, 4, unittest.NonexistentID})
|
||||
labels, err := issues_model.GetLabelsInOrgByIDs(db.DefaultContext, 3, []int64{3, 4, unittest.NonexistentID})
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, labels, 2) {
|
||||
assert.EqualValues(t, 3, labels[0].ID)
|
||||
@ -370,7 +370,7 @@ func TestDeleteIssueLabel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
defer committer.Close()
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, issues_model.DeleteIssueLabel(ctx, issue, label, doer))
|
||||
|
@ -111,7 +111,7 @@ func (m *Milestone) State() api.StateType {
|
||||
|
||||
// NewMilestone creates new milestone of repository.
|
||||
func NewMilestone(m *Milestone) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -161,7 +161,7 @@ func GetMilestoneByRepoIDANDName(repoID int64, name string) (*Milestone, error)
|
||||
|
||||
// UpdateMilestone updates information of given milestone.
|
||||
func UpdateMilestone(m *Milestone, oldIsClosed bool) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -219,7 +219,7 @@ func UpdateMilestoneCounters(ctx context.Context, id int64) error {
|
||||
|
||||
// ChangeMilestoneStatusByRepoIDAndID changes a milestone open/closed status if the milestone ID is in the repo.
|
||||
func ChangeMilestoneStatusByRepoIDAndID(repoID, milestoneID int64, isClosed bool) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -246,7 +246,7 @@ func ChangeMilestoneStatusByRepoIDAndID(repoID, milestoneID int64, isClosed bool
|
||||
|
||||
// ChangeMilestoneStatus changes the milestone open/closed status.
|
||||
func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -290,7 +290,7 @@ func DeleteMilestoneByRepoID(repoID, id int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -205,8 +205,8 @@ func DeletePullsByBaseRepoID(ctx context.Context, repoID int64) error {
|
||||
}
|
||||
|
||||
// MustHeadUserName returns the HeadRepo's username if failed return blank
|
||||
func (pr *PullRequest) MustHeadUserName() string {
|
||||
if err := pr.LoadHeadRepo(); err != nil {
|
||||
func (pr *PullRequest) MustHeadUserName(ctx context.Context) string {
|
||||
if err := pr.LoadHeadRepo(ctx); err != nil {
|
||||
if !repo_model.IsErrRepoNotExist(err) {
|
||||
log.Error("LoadHeadRepo: %v", err)
|
||||
} else {
|
||||
@ -220,8 +220,9 @@ func (pr *PullRequest) MustHeadUserName() string {
|
||||
return pr.HeadRepo.OwnerName
|
||||
}
|
||||
|
||||
// LoadAttributes loads pull request attributes from database
|
||||
// Note: don't try to get Issue because will end up recursive querying.
|
||||
func (pr *PullRequest) loadAttributes(ctx context.Context) (err error) {
|
||||
func (pr *PullRequest) LoadAttributes(ctx context.Context) (err error) {
|
||||
if pr.HasMerged && pr.Merger == nil {
|
||||
pr.Merger, err = user_model.GetUserByIDCtx(ctx, pr.MergerID)
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
@ -235,13 +236,8 @@ func (pr *PullRequest) loadAttributes(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadAttributes loads pull request attributes from database
|
||||
func (pr *PullRequest) LoadAttributes() error {
|
||||
return pr.loadAttributes(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadHeadRepoCtx loads the head repository
|
||||
func (pr *PullRequest) LoadHeadRepoCtx(ctx context.Context) (err error) {
|
||||
// LoadHeadRepo loads the head repository
|
||||
func (pr *PullRequest) LoadHeadRepo(ctx context.Context) (err error) {
|
||||
if !pr.isHeadRepoLoaded && pr.HeadRepo == nil && pr.HeadRepoID > 0 {
|
||||
if pr.HeadRepoID == pr.BaseRepoID {
|
||||
if pr.BaseRepo != nil {
|
||||
@ -262,18 +258,8 @@ func (pr *PullRequest) LoadHeadRepoCtx(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadHeadRepo loads the head repository
|
||||
func (pr *PullRequest) LoadHeadRepo() error {
|
||||
return pr.LoadHeadRepoCtx(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadBaseRepo loads the target repository
|
||||
func (pr *PullRequest) LoadBaseRepo() error {
|
||||
return pr.LoadBaseRepoCtx(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadBaseRepoCtx loads the target repository
|
||||
func (pr *PullRequest) LoadBaseRepoCtx(ctx context.Context) (err error) {
|
||||
func (pr *PullRequest) LoadBaseRepo(ctx context.Context) (err error) {
|
||||
if pr.BaseRepo != nil {
|
||||
return nil
|
||||
}
|
||||
@ -296,12 +282,7 @@ func (pr *PullRequest) LoadBaseRepoCtx(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
// LoadIssue loads issue information from database
|
||||
func (pr *PullRequest) LoadIssue() (err error) {
|
||||
return pr.LoadIssueCtx(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadIssueCtx loads issue information from database
|
||||
func (pr *PullRequest) LoadIssueCtx(ctx context.Context) (err error) {
|
||||
func (pr *PullRequest) LoadIssue(ctx context.Context) (err error) {
|
||||
if pr.Issue != nil {
|
||||
return nil
|
||||
}
|
||||
@ -368,7 +349,7 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -392,7 +373,7 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error {
|
||||
break
|
||||
}
|
||||
|
||||
if err := review.loadReviewer(ctx); err != nil && !user_model.IsErrUserNotExist(err) {
|
||||
if err := review.LoadReviewer(ctx); err != nil && !user_model.IsErrUserNotExist(err) {
|
||||
log.Error("Unable to LoadReviewer[%d] for PR ID %d : %v", review.ReviewerID, pr.ID, err)
|
||||
return err
|
||||
} else if review.Reviewer == nil {
|
||||
@ -458,7 +439,7 @@ func (pr *PullRequest) SetMerged(ctx context.Context) (bool, error) {
|
||||
}
|
||||
|
||||
pr.Issue = nil
|
||||
if err := pr.LoadIssueCtx(ctx); err != nil {
|
||||
if err := pr.LoadIssue(ctx); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@ -498,7 +479,7 @@ func (pr *PullRequest) SetMerged(ctx context.Context) (bool, error) {
|
||||
|
||||
// NewPullRequest creates new pull request with labels for repository.
|
||||
func NewPullRequest(outerCtx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string, pr *PullRequest) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(outerCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -541,9 +522,9 @@ func NewPullRequest(outerCtx context.Context, repo *repo_model.Repository, issue
|
||||
|
||||
// GetUnmergedPullRequest returns a pull request that is open and has not been merged
|
||||
// by given head/base and repo/branch.
|
||||
func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch string, flow PullRequestFlow) (*PullRequest, error) {
|
||||
func GetUnmergedPullRequest(ctx context.Context, headRepoID, baseRepoID int64, headBranch, baseBranch string, flow PullRequestFlow) (*PullRequest, error) {
|
||||
pr := new(PullRequest)
|
||||
has, err := db.GetEngine(db.DefaultContext).
|
||||
has, err := db.GetEngine(ctx).
|
||||
Where("head_repo_id=? AND head_branch=? AND base_repo_id=? AND base_branch=? AND has_merged=? AND flow = ? AND issue.is_closed=?",
|
||||
headRepoID, headBranch, baseRepoID, baseBranch, false, flow, false).
|
||||
Join("INNER", "issue", "issue.id=pull_request.issue_id").
|
||||
@ -588,10 +569,10 @@ func GetPullRequestByIndex(ctx context.Context, repoID, index int64) (*PullReque
|
||||
return nil, ErrPullRequestNotExist{0, 0, 0, repoID, "", ""}
|
||||
}
|
||||
|
||||
if err = pr.loadAttributes(ctx); err != nil {
|
||||
if err = pr.LoadAttributes(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = pr.LoadIssueCtx(ctx); err != nil {
|
||||
if err = pr.LoadIssue(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -607,7 +588,7 @@ func GetPullRequestByID(ctx context.Context, id int64) (*PullRequest, error) {
|
||||
} else if !has {
|
||||
return nil, ErrPullRequestNotExist{id, 0, 0, 0, "", ""}
|
||||
}
|
||||
return pr, pr.loadAttributes(ctx)
|
||||
return pr, pr.LoadAttributes(ctx)
|
||||
}
|
||||
|
||||
// GetPullRequestByIssueIDWithNoAttributes returns pull request with no attributes loaded by given issue ID.
|
||||
@ -634,7 +615,7 @@ func GetPullRequestByIssueID(ctx context.Context, issueID int64) (*PullRequest,
|
||||
} else if !has {
|
||||
return nil, ErrPullRequestNotExist{0, issueID, 0, 0, "", ""}
|
||||
}
|
||||
return pr, pr.loadAttributes(ctx)
|
||||
return pr, pr.LoadAttributes(ctx)
|
||||
}
|
||||
|
||||
// GetAllUnmergedAgitPullRequestByPoster get all unmerged agit flow pull request
|
||||
@ -664,14 +645,15 @@ func (pr *PullRequest) UpdateCols(cols ...string) error {
|
||||
}
|
||||
|
||||
// UpdateColsIfNotMerged updates specific fields of a pull request if it has not been merged
|
||||
func (pr *PullRequest) UpdateColsIfNotMerged(cols ...string) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Where("id = ? AND has_merged = ?", pr.ID, false).Cols(cols...).Update(pr)
|
||||
func (pr *PullRequest) UpdateColsIfNotMerged(ctx context.Context, cols ...string) error {
|
||||
_, err := db.GetEngine(ctx).Where("id = ? AND has_merged = ?", pr.ID, false).Cols(cols...).Update(pr)
|
||||
return err
|
||||
}
|
||||
|
||||
// IsWorkInProgress determine if the Pull Request is a Work In Progress by its title
|
||||
// Issue must be set before this method can be called.
|
||||
func (pr *PullRequest) IsWorkInProgress() bool {
|
||||
if err := pr.LoadIssue(); err != nil {
|
||||
if err := pr.LoadIssue(db.DefaultContext); err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return false
|
||||
}
|
||||
@ -695,8 +677,8 @@ func (pr *PullRequest) IsFilesConflicted() bool {
|
||||
|
||||
// GetWorkInProgressPrefix returns the prefix used to mark the pull request as a work in progress.
|
||||
// It returns an empty string when none were found
|
||||
func (pr *PullRequest) GetWorkInProgressPrefix() string {
|
||||
if err := pr.LoadIssue(); err != nil {
|
||||
func (pr *PullRequest) GetWorkInProgressPrefix(ctx context.Context) string {
|
||||
if err := pr.LoadIssue(ctx); err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return ""
|
||||
}
|
||||
@ -739,7 +721,7 @@ func GetPullRequestsByHeadBranch(ctx context.Context, headBranch string, headRep
|
||||
|
||||
// GetBaseBranchHTMLURL returns the HTML URL of the base branch
|
||||
func (pr *PullRequest) GetBaseBranchHTMLURL() string {
|
||||
if err := pr.LoadBaseRepo(); err != nil {
|
||||
if err := pr.LoadBaseRepo(db.DefaultContext); err != nil {
|
||||
log.Error("LoadBaseRepo: %v", err)
|
||||
return ""
|
||||
}
|
||||
@ -755,7 +737,7 @@ func (pr *PullRequest) GetHeadBranchHTMLURL() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
if err := pr.LoadHeadRepo(); err != nil {
|
||||
if err := pr.LoadHeadRepo(db.DefaultContext); err != nil {
|
||||
log.Error("LoadHeadRepo: %v", err)
|
||||
return ""
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ func CanMaintainerWriteToBranch(p access_model.Permission, branch string, user *
|
||||
|
||||
for _, pr := range prs {
|
||||
if pr.AllowMaintainerEdit {
|
||||
err = pr.LoadBaseRepo()
|
||||
err = pr.LoadBaseRepo(db.DefaultContext)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
func TestPullRequest_LoadAttributes(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})
|
||||
assert.NoError(t, pr.LoadAttributes())
|
||||
assert.NoError(t, pr.LoadAttributes(db.DefaultContext))
|
||||
assert.NotNil(t, pr.Merger)
|
||||
assert.Equal(t, pr.MergerID, pr.Merger.ID)
|
||||
}
|
||||
@ -25,10 +25,10 @@ func TestPullRequest_LoadAttributes(t *testing.T) {
|
||||
func TestPullRequest_LoadIssue(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})
|
||||
assert.NoError(t, pr.LoadIssue())
|
||||
assert.NoError(t, pr.LoadIssue(db.DefaultContext))
|
||||
assert.NotNil(t, pr.Issue)
|
||||
assert.Equal(t, int64(2), pr.Issue.ID)
|
||||
assert.NoError(t, pr.LoadIssue())
|
||||
assert.NoError(t, pr.LoadIssue(db.DefaultContext))
|
||||
assert.NotNil(t, pr.Issue)
|
||||
assert.Equal(t, int64(2), pr.Issue.ID)
|
||||
}
|
||||
@ -36,10 +36,10 @@ func TestPullRequest_LoadIssue(t *testing.T) {
|
||||
func TestPullRequest_LoadBaseRepo(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})
|
||||
assert.NoError(t, pr.LoadBaseRepo())
|
||||
assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext))
|
||||
assert.NotNil(t, pr.BaseRepo)
|
||||
assert.Equal(t, pr.BaseRepoID, pr.BaseRepo.ID)
|
||||
assert.NoError(t, pr.LoadBaseRepo())
|
||||
assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext))
|
||||
assert.NotNil(t, pr.BaseRepo)
|
||||
assert.Equal(t, pr.BaseRepoID, pr.BaseRepo.ID)
|
||||
}
|
||||
@ -47,7 +47,7 @@ func TestPullRequest_LoadBaseRepo(t *testing.T) {
|
||||
func TestPullRequest_LoadHeadRepo(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})
|
||||
assert.NoError(t, pr.LoadHeadRepo())
|
||||
assert.NoError(t, pr.LoadHeadRepo(db.DefaultContext))
|
||||
assert.NotNil(t, pr.HeadRepo)
|
||||
assert.Equal(t, pr.HeadRepoID, pr.HeadRepo.ID)
|
||||
}
|
||||
@ -96,11 +96,11 @@ func TestPullRequestsOldest(t *testing.T) {
|
||||
|
||||
func TestGetUnmergedPullRequest(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
pr, err := issues_model.GetUnmergedPullRequest(1, 1, "branch2", "master", issues_model.PullRequestFlowGithub)
|
||||
pr, err := issues_model.GetUnmergedPullRequest(db.DefaultContext, 1, 1, "branch2", "master", issues_model.PullRequestFlowGithub)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(2), pr.ID)
|
||||
|
||||
_, err = issues_model.GetUnmergedPullRequest(1, 9223372036854775807, "branch1", "master", issues_model.PullRequestFlowGithub)
|
||||
_, err = issues_model.GetUnmergedPullRequest(db.DefaultContext, 1, 9223372036854775807, "branch1", "master", issues_model.PullRequestFlowGithub)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, issues_model.IsErrPullRequestNotExist(err))
|
||||
}
|
||||
@ -228,7 +228,7 @@ func TestPullRequest_IsWorkInProgress(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2})
|
||||
pr.LoadIssue()
|
||||
pr.LoadIssue(db.DefaultContext)
|
||||
|
||||
assert.False(t, pr.IsWorkInProgress())
|
||||
|
||||
@ -243,16 +243,16 @@ func TestPullRequest_GetWorkInProgressPrefixWorkInProgress(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2})
|
||||
pr.LoadIssue()
|
||||
pr.LoadIssue(db.DefaultContext)
|
||||
|
||||
assert.Empty(t, pr.GetWorkInProgressPrefix())
|
||||
assert.Empty(t, pr.GetWorkInProgressPrefix(db.DefaultContext))
|
||||
|
||||
original := pr.Issue.Title
|
||||
pr.Issue.Title = "WIP: " + original
|
||||
assert.Equal(t, "WIP:", pr.GetWorkInProgressPrefix())
|
||||
assert.Equal(t, "WIP:", pr.GetWorkInProgressPrefix(db.DefaultContext))
|
||||
|
||||
pr.Issue.Title = "[wip] " + original
|
||||
assert.Equal(t, "[wip]", pr.GetWorkInProgressPrefix())
|
||||
assert.Equal(t, "[wip]", pr.GetWorkInProgressPrefix(db.DefaultContext))
|
||||
}
|
||||
|
||||
func TestDeleteOrphanedObjects(t *testing.T) {
|
||||
@ -264,11 +264,11 @@ func TestDeleteOrphanedObjects(t *testing.T) {
|
||||
_, err = db.GetEngine(db.DefaultContext).Insert(&issues_model.PullRequest{IssueID: 1000}, &issues_model.PullRequest{IssueID: 1001}, &issues_model.PullRequest{IssueID: 1003})
|
||||
assert.NoError(t, err)
|
||||
|
||||
orphaned, err := db.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
|
||||
orphaned, err := db.CountOrphanedObjects(db.DefaultContext, "pull_request", "issue", "pull_request.issue_id=issue.id")
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 3, orphaned)
|
||||
|
||||
err = db.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
|
||||
err = db.DeleteOrphanedObjects(db.DefaultContext, "pull_request", "issue", "pull_request.issue_id=issue.id")
|
||||
assert.NoError(t, err)
|
||||
|
||||
countAfter, err := db.GetEngine(db.DefaultContext).Count(&issues_model.PullRequest{})
|
||||
|
@ -224,7 +224,7 @@ func CreateReaction(opts *ReactionOptions) (*Reaction, error) {
|
||||
return nil, ErrForbiddenIssueReaction{opts.Type}
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -154,7 +154,8 @@ func (r *Review) loadIssue(ctx context.Context) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Review) loadReviewer(ctx context.Context) (err error) {
|
||||
// LoadReviewer loads reviewer
|
||||
func (r *Review) LoadReviewer(ctx context.Context) (err error) {
|
||||
if r.ReviewerID == 0 || r.Reviewer != nil {
|
||||
return
|
||||
}
|
||||
@ -162,7 +163,8 @@ func (r *Review) loadReviewer(ctx context.Context) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Review) loadReviewerTeam(ctx context.Context) (err error) {
|
||||
// LoadReviewerTeam loads reviewer team
|
||||
func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) {
|
||||
if r.ReviewerTeamID == 0 || r.ReviewerTeam != nil {
|
||||
return
|
||||
}
|
||||
@ -171,16 +173,6 @@ func (r *Review) loadReviewerTeam(ctx context.Context) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// LoadReviewer loads reviewer
|
||||
func (r *Review) LoadReviewer() error {
|
||||
return r.loadReviewer(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadReviewerTeam loads reviewer team
|
||||
func (r *Review) LoadReviewerTeam() error {
|
||||
return r.loadReviewerTeam(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadAttributes loads all attributes except CodeComments
|
||||
func (r *Review) LoadAttributes(ctx context.Context) (err error) {
|
||||
if err = r.loadIssue(ctx); err != nil {
|
||||
@ -189,10 +181,10 @@ func (r *Review) LoadAttributes(ctx context.Context) (err error) {
|
||||
if err = r.LoadCodeComments(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
if err = r.loadReviewer(ctx); err != nil {
|
||||
if err = r.LoadReviewer(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
if err = r.loadReviewerTeam(ctx); err != nil {
|
||||
if err = r.LoadReviewerTeam(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
return err
|
||||
@ -374,7 +366,7 @@ func IsContentEmptyErr(err error) bool {
|
||||
|
||||
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
|
||||
func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool, attachmentUUIDs []string) (*Review, *Comment, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -622,7 +614,7 @@ func DismissReview(review *Review, isDismiss bool) (err error) {
|
||||
|
||||
// InsertReviews inserts review and review comments
|
||||
func InsertReviews(reviews []*Review) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -664,7 +656,7 @@ func InsertReviews(reviews []*Review) error {
|
||||
|
||||
// AddReviewRequest add a review request from one reviewer
|
||||
func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -719,7 +711,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment,
|
||||
|
||||
// RemoveReviewRequest remove a review request from one reviewer
|
||||
func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -772,7 +764,7 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Commen
|
||||
|
||||
// AddTeamReviewRequest add a review request from one team
|
||||
func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_model.User) (*Comment, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -831,7 +823,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_
|
||||
|
||||
// RemoveTeamReviewRequest remove a review request from one team
|
||||
func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_model.User) (*Comment, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -949,7 +941,7 @@ func CanMarkConversation(issue *Issue, doer *user_model.User) (permResult bool,
|
||||
|
||||
// DeleteReview delete a review and it's code comments
|
||||
func DeleteReview(r *Review) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
||||
|
||||
allReviews, err := issues_model.GetReviewersByIssueID(issue.ID)
|
||||
for _, reviewer := range allReviews {
|
||||
assert.NoError(t, reviewer.LoadReviewer())
|
||||
assert.NoError(t, reviewer.LoadReviewer(db.DefaultContext))
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, allReviews, 3) {
|
||||
|
@ -261,7 +261,7 @@ func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss
|
||||
|
||||
// CancelStopwatch removes the given stopwatch and logs it into issue's timeline.
|
||||
func CancelStopwatch(user *user_model.User, issue *Issue) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ func GetTrackedSeconds(ctx context.Context, opts FindTrackedTimesOptions) (track
|
||||
|
||||
// AddTime will add the given time (in seconds) to the issue
|
||||
func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -220,7 +220,7 @@ func TotalTimes(options *FindTrackedTimesOptions) (map[*user_model.User]string,
|
||||
|
||||
// DeleteIssueUserTimes deletes times for issue
|
||||
func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -257,7 +257,7 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error {
|
||||
|
||||
// DeleteTime delete a specific Time
|
||||
func DeleteTime(t *TrackedTime) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ func InsertMilestones(ms ...*issues_model.Milestone) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -42,7 +42,7 @@ func InsertMilestones(ms ...*issues_model.Milestone) (err error) {
|
||||
|
||||
// InsertIssues insert issues to database
|
||||
func InsertIssues(issues ...*issues_model.Issue) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -105,7 +105,7 @@ func InsertIssueComments(comments []*issues_model.Comment) error {
|
||||
issueIDs.Add(comment.IssueID)
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -137,7 +137,7 @@ func InsertIssueComments(comments []*issues_model.Comment) error {
|
||||
|
||||
// InsertPullRequests inserted pull requests
|
||||
func InsertPullRequests(prs ...*issues_model.PullRequest) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -157,7 +157,7 @@ func InsertPullRequests(prs ...*issues_model.PullRequest) error {
|
||||
|
||||
// InsertReleases migrates release
|
||||
func InsertReleases(rels ...*repo_model.Release) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@ -23,6 +24,7 @@ import (
|
||||
"code.gitea.io/gitea/models/migrations/v1_7"
|
||||
"code.gitea.io/gitea/models/migrations/v1_8"
|
||||
"code.gitea.io/gitea/models/migrations/v1_9"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
@ -437,6 +439,8 @@ var migrations = []Migration{
|
||||
NewMigration("Alter package_version.metadata_json to LONGTEXT", v1_19.AlterPackageVersionMetadataToLongText),
|
||||
// v233 -> v234
|
||||
NewMigration("Add header_authorization_encrypted column to webhook table", v1_19.AddHeaderAuthorizationEncryptedColWebhook),
|
||||
// v234 -> v235
|
||||
NewMigration("Add package cleanup rule table", v1_19.CreatePackageCleanupRuleTable),
|
||||
}
|
||||
|
||||
// GetCurrentDBVersion returns the current db version
|
||||
@ -527,6 +531,13 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t
|
||||
return nil
|
||||
}
|
||||
|
||||
// Some migration tasks depend on the git command
|
||||
if git.DefaultContext == nil {
|
||||
if err = git.InitSimple(context.Background()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate
|
||||
for i, m := range migrations[v-minDBVersion:] {
|
||||
log.Info("Migration[%d]: %s", v+int64(i), m.Description())
|
||||
|
29
models/migrations/v1_19/v234.go
Normal file
29
models/migrations/v1_19/v234.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package v1_19 //nolint
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func CreatePackageCleanupRuleTable(x *xorm.Engine) error {
|
||||
type PackageCleanupRule struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Enabled bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
||||
OwnerID int64 `xorm:"UNIQUE(s) INDEX NOT NULL DEFAULT 0"`
|
||||
Type string `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||
KeepCount int `xorm:"NOT NULL DEFAULT 0"`
|
||||
KeepPattern string `xorm:"NOT NULL DEFAULT ''"`
|
||||
RemoveDays int `xorm:"NOT NULL DEFAULT 0"`
|
||||
RemovePattern string `xorm:"NOT NULL DEFAULT ''"`
|
||||
MatchFullName bool `xorm:"NOT NULL DEFAULT false"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL DEFAULT 0"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL DEFAULT 0"`
|
||||
}
|
||||
|
||||
return x.Sync2(new(PackageCleanupRule))
|
||||
}
|
@ -99,7 +99,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error {
|
||||
|
||||
// RemoveOrgUser removes user from given organization.
|
||||
func RemoveOrgUser(orgID, userID int64) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ func addAllRepositories(ctx context.Context, t *organization.Team) error {
|
||||
|
||||
// AddAllRepositories adds all repositories to the team
|
||||
func AddAllRepositories(t *organization.Team) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -95,7 +95,7 @@ func RemoveAllRepositories(t *organization.Team) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -219,7 +219,7 @@ func RemoveRepository(t *organization.Team, repoID int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -263,7 +263,7 @@ func NewTeam(t *organization.Team) (err error) {
|
||||
return organization.ErrTeamAlreadyExist{OrgID: t.OrgID, Name: t.LowerName}
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -308,7 +308,7 @@ func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err
|
||||
t.Description = t.Description[:255]
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -375,7 +375,7 @@ func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err
|
||||
// DeleteTeam deletes given team.
|
||||
// It's caller's responsibility to assign organization ID.
|
||||
func DeleteTeam(t *organization.Team) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -460,7 +460,7 @@ func AddTeamMember(team *organization.Team, userID int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -598,7 +598,7 @@ func removeTeamMember(ctx context.Context, team *organization.Team, userID int64
|
||||
|
||||
// RemoveTeamMember removes member from given team of given organization.
|
||||
func RemoveTeamMember(team *organization.Team, userID int64) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ func TestDeleteTeam(t *testing.T) {
|
||||
// check that team members don't have "leftover" access to repos
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
||||
accessMode, err := access_model.AccessLevel(user, repo)
|
||||
accessMode, err := access_model.AccessLevel(db.DefaultContext, user, repo)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, accessMode < perm.AccessModeWrite)
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
|
||||
org.NumMembers = 1
|
||||
org.Type = user_model.UserTypeOrganization
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -458,8 +458,9 @@ func CountOrgs(opts FindOrgOptions) (int64, error) {
|
||||
|
||||
// HasOrgOrUserVisible tells if the given user can see the given org or user
|
||||
func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User) bool {
|
||||
// Not SignedUser
|
||||
if user == nil {
|
||||
// If user is nil, it's an anonymous user/request.
|
||||
// The Ghost user is handled like an anonymous user.
|
||||
if user == nil || user.IsGhost() {
|
||||
return orgOrUser.Visibility == structs.VisibleTypePublic
|
||||
}
|
||||
|
||||
@ -564,7 +565,7 @@ func AddOrgUser(orgID, uid int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ func getUnitsByTeamID(ctx context.Context, teamID int64) (units []*TeamUnit, err
|
||||
|
||||
// UpdateTeamUnits updates a teams's units
|
||||
func UpdateTeamUnits(team *Team, units []TeamUnit) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -45,6 +45,21 @@ const (
|
||||
TypeVagrant Type = "vagrant"
|
||||
)
|
||||
|
||||
var TypeList = []Type{
|
||||
TypeComposer,
|
||||
TypeConan,
|
||||
TypeContainer,
|
||||
TypeGeneric,
|
||||
TypeHelm,
|
||||
TypeMaven,
|
||||
TypeNpm,
|
||||
TypeNuGet,
|
||||
TypePub,
|
||||
TypePyPI,
|
||||
TypeRubyGems,
|
||||
TypeVagrant,
|
||||
}
|
||||
|
||||
// Name gets the name of the package type
|
||||
func (pt Type) Name() string {
|
||||
switch pt {
|
||||
|
@ -62,6 +62,13 @@ func GetBlobByID(ctx context.Context, blobID int64) (*PackageBlob, error) {
|
||||
return pb, nil
|
||||
}
|
||||
|
||||
// ExistPackageBlobWithSHA returns if a package blob exists with the provided sha
|
||||
func ExistPackageBlobWithSHA(ctx context.Context, blobSha256 string) (bool, error) {
|
||||
return db.GetEngine(ctx).Exist(&PackageBlob{
|
||||
HashSHA256: blobSha256,
|
||||
})
|
||||
}
|
||||
|
||||
// FindExpiredUnreferencedBlobs gets all blobs without associated files older than the specific duration
|
||||
func FindExpiredUnreferencedBlobs(ctx context.Context, olderThan time.Duration) ([]*PackageBlob, error) {
|
||||
pbs := make([]*PackageBlob, 0, 10)
|
||||
|
110
models/packages/package_cleanup_rule.go
Normal file
110
models/packages/package_cleanup_rule.go
Normal file
@ -0,0 +1,110 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package packages
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
var ErrPackageCleanupRuleNotExist = errors.New("Package blob does not exist")
|
||||
|
||||
func init() {
|
||||
db.RegisterModel(new(PackageCleanupRule))
|
||||
}
|
||||
|
||||
// PackageCleanupRule represents a rule which describes when to clean up package versions
|
||||
type PackageCleanupRule struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Enabled bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
||||
OwnerID int64 `xorm:"UNIQUE(s) INDEX NOT NULL DEFAULT 0"`
|
||||
Type Type `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||
KeepCount int `xorm:"NOT NULL DEFAULT 0"`
|
||||
KeepPattern string `xorm:"NOT NULL DEFAULT ''"`
|
||||
KeepPatternMatcher *regexp.Regexp `xorm:"-"`
|
||||
RemoveDays int `xorm:"NOT NULL DEFAULT 0"`
|
||||
RemovePattern string `xorm:"NOT NULL DEFAULT ''"`
|
||||
RemovePatternMatcher *regexp.Regexp `xorm:"-"`
|
||||
MatchFullName bool `xorm:"NOT NULL DEFAULT false"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL DEFAULT 0"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL DEFAULT 0"`
|
||||
}
|
||||
|
||||
func (pcr *PackageCleanupRule) CompiledPattern() error {
|
||||
if pcr.KeepPatternMatcher != nil || pcr.RemovePatternMatcher != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if pcr.KeepPattern != "" {
|
||||
var err error
|
||||
pcr.KeepPatternMatcher, err = regexp.Compile(fmt.Sprintf(`(?i)\A%s\z`, pcr.KeepPattern))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if pcr.RemovePattern != "" {
|
||||
var err error
|
||||
pcr.RemovePatternMatcher, err = regexp.Compile(fmt.Sprintf(`(?i)\A%s\z`, pcr.RemovePattern))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func InsertCleanupRule(ctx context.Context, pcr *PackageCleanupRule) (*PackageCleanupRule, error) {
|
||||
return pcr, db.Insert(ctx, pcr)
|
||||
}
|
||||
|
||||
func GetCleanupRuleByID(ctx context.Context, id int64) (*PackageCleanupRule, error) {
|
||||
pcr := &PackageCleanupRule{}
|
||||
|
||||
has, err := db.GetEngine(ctx).ID(id).Get(pcr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !has {
|
||||
return nil, ErrPackageCleanupRuleNotExist
|
||||
}
|
||||
return pcr, nil
|
||||
}
|
||||
|
||||
func UpdateCleanupRule(ctx context.Context, pcr *PackageCleanupRule) error {
|
||||
_, err := db.GetEngine(ctx).ID(pcr.ID).AllCols().Update(pcr)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetCleanupRulesByOwner(ctx context.Context, ownerID int64) ([]*PackageCleanupRule, error) {
|
||||
pcrs := make([]*PackageCleanupRule, 0, 10)
|
||||
return pcrs, db.GetEngine(ctx).Where("owner_id = ?", ownerID).Find(&pcrs)
|
||||
}
|
||||
|
||||
func DeleteCleanupRuleByID(ctx context.Context, ruleID int64) error {
|
||||
_, err := db.GetEngine(ctx).ID(ruleID).Delete(&PackageCleanupRule{})
|
||||
return err
|
||||
}
|
||||
|
||||
func HasOwnerCleanupRuleForPackageType(ctx context.Context, ownerID int64, packageType Type) (bool, error) {
|
||||
return db.GetEngine(ctx).
|
||||
Where("owner_id = ? AND type = ?", ownerID, packageType).
|
||||
Exist(&PackageCleanupRule{})
|
||||
}
|
||||
|
||||
func IterateEnabledCleanupRules(ctx context.Context, callback func(context.Context, *PackageCleanupRule) error) error {
|
||||
return db.Iterate(
|
||||
ctx,
|
||||
builder.Eq{"enabled": true},
|
||||
callback,
|
||||
)
|
||||
}
|
@ -320,6 +320,15 @@ func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*P
|
||||
return pvs, count, err
|
||||
}
|
||||
|
||||
// ExistVersion checks if a version matching the search options exist
|
||||
func ExistVersion(ctx context.Context, opts *PackageSearchOptions) (bool, error) {
|
||||
return db.GetEngine(ctx).
|
||||
Where(opts.toConds()).
|
||||
Table("package_version").
|
||||
Join("INNER", "package", "package.id = package_version.package_id").
|
||||
Exist(new(PackageVersion))
|
||||
}
|
||||
|
||||
// CountVersions counts all versions of packages matching the search options
|
||||
func CountVersions(ctx context.Context, opts *PackageSearchOptions) (int64, error) {
|
||||
return db.GetEngine(ctx).
|
||||
|
@ -36,34 +36,34 @@ func TestAccessLevel(t *testing.T) {
|
||||
// org. owned private repo
|
||||
repo24 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24})
|
||||
|
||||
level, err := access_model.AccessLevel(user2, repo1)
|
||||
level, err := access_model.AccessLevel(db.DefaultContext, user2, repo1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, perm_model.AccessModeOwner, level)
|
||||
|
||||
level, err = access_model.AccessLevel(user2, repo3)
|
||||
level, err = access_model.AccessLevel(db.DefaultContext, user2, repo3)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, perm_model.AccessModeOwner, level)
|
||||
|
||||
level, err = access_model.AccessLevel(user5, repo1)
|
||||
level, err = access_model.AccessLevel(db.DefaultContext, user5, repo1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, perm_model.AccessModeRead, level)
|
||||
|
||||
level, err = access_model.AccessLevel(user5, repo3)
|
||||
level, err = access_model.AccessLevel(db.DefaultContext, user5, repo3)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, perm_model.AccessModeNone, level)
|
||||
|
||||
// restricted user has no access to a public repo
|
||||
level, err = access_model.AccessLevel(user29, repo1)
|
||||
level, err = access_model.AccessLevel(db.DefaultContext, user29, repo1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, perm_model.AccessModeNone, level)
|
||||
|
||||
// ... unless he's a collaborator
|
||||
level, err = access_model.AccessLevel(user29, repo4)
|
||||
level, err = access_model.AccessLevel(db.DefaultContext, user29, repo4)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, perm_model.AccessModeWrite, level)
|
||||
|
||||
// ... or a team member
|
||||
level, err = access_model.AccessLevel(user29, repo24)
|
||||
level, err = access_model.AccessLevel(db.DefaultContext, user29, repo24)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, perm_model.AccessModeRead, level)
|
||||
}
|
||||
|
@ -326,17 +326,13 @@ func IsUserRepoAdmin(ctx context.Context, repo *repo_model.Repository, user *use
|
||||
|
||||
// AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the
|
||||
// user does not have access.
|
||||
func AccessLevel(user *user_model.User, repo *repo_model.Repository) (perm_model.AccessMode, error) { //nolint
|
||||
return AccessLevelUnit(user, repo, unit.TypeCode)
|
||||
func AccessLevel(ctx context.Context, user *user_model.User, repo *repo_model.Repository) (perm_model.AccessMode, error) { //nolint
|
||||
return AccessLevelUnit(ctx, user, repo, unit.TypeCode)
|
||||
}
|
||||
|
||||
// AccessLevelUnit returns the Access a user has to a repository's. Will return NoneAccess if the
|
||||
// user does not have access.
|
||||
func AccessLevelUnit(user *user_model.User, repo *repo_model.Repository, unitType unit.Type) (perm_model.AccessMode, error) { //nolint
|
||||
return accessLevelUnit(db.DefaultContext, user, repo, unitType)
|
||||
}
|
||||
|
||||
func accessLevelUnit(ctx context.Context, user *user_model.User, repo *repo_model.Repository, unitType unit.Type) (perm_model.AccessMode, error) {
|
||||
func AccessLevelUnit(ctx context.Context, user *user_model.User, repo *repo_model.Repository, unitType unit.Type) (perm_model.AccessMode, error) { //nolint
|
||||
perm, err := GetUserRepoPermission(ctx, repo, user)
|
||||
if err != nil {
|
||||
return perm_model.AccessModeNone, err
|
||||
@ -346,7 +342,7 @@ func accessLevelUnit(ctx context.Context, user *user_model.User, repo *repo_mode
|
||||
|
||||
// HasAccessUnit returns true if user has testMode to the unit of the repository
|
||||
func HasAccessUnit(ctx context.Context, user *user_model.User, repo *repo_model.Repository, unitType unit.Type, testMode perm_model.AccessMode) (bool, error) {
|
||||
mode, err := accessLevelUnit(ctx, user, repo, unitType)
|
||||
mode, err := AccessLevelUnit(ctx, user, repo, unitType)
|
||||
return testMode <= mode, err
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ func NewBoard(board *Board) error {
|
||||
|
||||
// DeleteBoardByID removes all issues references to the project board.
|
||||
func DeleteBoardByID(boardID int64) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ func (p *Project) NumOpenIssues() int {
|
||||
|
||||
// MoveIssuesOnProjectBoard moves or keeps issues in a column and sorts them inside that column
|
||||
func MoveIssuesOnProjectBoard(board *Board, sortedIssueIDs map[int64]int64) error {
|
||||
return db.WithTx(func(ctx context.Context) error {
|
||||
return db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
||||
sess := db.GetEngine(ctx)
|
||||
|
||||
issueIDs := make([]int64, 0, len(sortedIssueIDs))
|
||||
|
@ -180,7 +180,7 @@ func NewProject(p *Project) error {
|
||||
return errors.New("project type is not valid")
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -248,7 +248,7 @@ func updateRepositoryProjectCount(ctx context.Context, repoID int64) error {
|
||||
|
||||
// ChangeProjectStatusByRepoIDAndID toggles a project between opened and closed
|
||||
func ChangeProjectStatusByRepoIDAndID(repoID, projectID int64, isClosed bool) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -272,7 +272,7 @@ func ChangeProjectStatusByRepoIDAndID(repoID, projectID int64, isClosed bool) er
|
||||
|
||||
// ChangeProjectStatus toggle a project between opened and closed
|
||||
func ChangeProjectStatus(p *Project, isClosed bool) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -301,7 +301,7 @@ func changeProjectStatus(ctx context.Context, p *Project, isClosed bool) error {
|
||||
|
||||
// DeleteProjectByID deletes a project from a repository.
|
||||
func DeleteProjectByID(id int64) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ func Init() error {
|
||||
// DeleteRepository deletes a repository for a user or organization.
|
||||
// make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock)
|
||||
func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -569,7 +569,7 @@ func UpdateRepoStats(ctx context.Context, id int64) error {
|
||||
}
|
||||
|
||||
func updateUserStarNumbers(users []user_model.User) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -7,11 +7,14 @@ package repo
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
@ -44,6 +47,28 @@ func (archiver *RepoArchiver) RelativePath() string {
|
||||
return fmt.Sprintf("%d/%s/%s.%s", archiver.RepoID, archiver.CommitID[:2], archiver.CommitID, archiver.Type.String())
|
||||
}
|
||||
|
||||
// repoArchiverForRelativePath takes a relativePath created from (archiver *RepoArchiver) RelativePath() and creates a shell repoArchiver struct representing it
|
||||
func repoArchiverForRelativePath(relativePath string) (*RepoArchiver, error) {
|
||||
parts := strings.SplitN(relativePath, "/", 3)
|
||||
if len(parts) != 3 {
|
||||
return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument}
|
||||
}
|
||||
repoID, err := strconv.ParseInt(parts[0], 10, 64)
|
||||
if err != nil {
|
||||
return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument}
|
||||
}
|
||||
nameExts := strings.SplitN(parts[2], ".", 2)
|
||||
if len(nameExts) != 2 {
|
||||
return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument}
|
||||
}
|
||||
|
||||
return &RepoArchiver{
|
||||
RepoID: repoID,
|
||||
CommitID: parts[1] + nameExts[0],
|
||||
Type: git.ToArchiveType(nameExts[1]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
var delRepoArchiver = new(RepoArchiver)
|
||||
|
||||
// DeleteRepoArchiver delete archiver
|
||||
@ -65,6 +90,17 @@ func GetRepoArchiver(ctx context.Context, repoID int64, tp git.ArchiveType, comm
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ExistsRepoArchiverWithStoragePath checks if there is a RepoArchiver for a given storage path
|
||||
func ExistsRepoArchiverWithStoragePath(ctx context.Context, storagePath string) (bool, error) {
|
||||
// We need to invert the path provided func (archiver *RepoArchiver) RelativePath() above
|
||||
archiver, err := repoArchiverForRelativePath(storagePath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return db.GetEngine(ctx).Exist(archiver)
|
||||
}
|
||||
|
||||
// AddRepoArchiver adds an archiver
|
||||
func AddRepoArchiver(ctx context.Context, archiver *RepoArchiver) error {
|
||||
_, err := db.GetEngine(ctx).Insert(archiver)
|
||||
|
@ -122,9 +122,9 @@ func GetAttachmentsByUUIDs(ctx context.Context, uuids []string) ([]*Attachment,
|
||||
return attachments, db.GetEngine(ctx).In("uuid", uuids).Find(&attachments)
|
||||
}
|
||||
|
||||
// ExistAttachmentsByUUID returns true if attachment is exist by given UUID
|
||||
func ExistAttachmentsByUUID(uuid string) (bool, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where("`uuid`=?", uuid).Exist(new(Attachment))
|
||||
// ExistAttachmentsByUUID returns true if attachment exists with the given UUID
|
||||
func ExistAttachmentsByUUID(ctx context.Context, uuid string) (bool, error) {
|
||||
return db.GetEngine(ctx).Where("`uuid`=?", uuid).Exist(new(Attachment))
|
||||
}
|
||||
|
||||
// GetAttachmentsByIssueID returns all attachments of an issue.
|
||||
@ -226,20 +226,20 @@ func UpdateAttachment(ctx context.Context, atta *Attachment) error {
|
||||
}
|
||||
|
||||
// DeleteAttachmentsByRelease deletes all attachments associated with the given release.
|
||||
func DeleteAttachmentsByRelease(releaseID int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Where("release_id = ?", releaseID).Delete(&Attachment{})
|
||||
func DeleteAttachmentsByRelease(ctx context.Context, releaseID int64) error {
|
||||
_, err := db.GetEngine(ctx).Where("release_id = ?", releaseID).Delete(&Attachment{})
|
||||
return err
|
||||
}
|
||||
|
||||
// CountOrphanedAttachments returns the number of bad attachments
|
||||
func CountOrphanedAttachments() (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))").
|
||||
func CountOrphanedAttachments(ctx context.Context) (int64, error) {
|
||||
return db.GetEngine(ctx).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))").
|
||||
Count(new(Attachment))
|
||||
}
|
||||
|
||||
// DeleteOrphanedAttachments delete all bad attachments
|
||||
func DeleteOrphanedAttachments() error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))").
|
||||
func DeleteOrphanedAttachments(ctx context.Context) error {
|
||||
_, err := db.GetEngine(ctx).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))").
|
||||
Delete(new(Attachment))
|
||||
return err
|
||||
}
|
||||
|
@ -24,6 +24,13 @@ func (repo *Repository) CustomAvatarRelativePath() string {
|
||||
return repo.Avatar
|
||||
}
|
||||
|
||||
// ExistsWithAvatarAtStoragePath returns true if there is a user with this Avatar
|
||||
func ExistsWithAvatarAtStoragePath(ctx context.Context, storagePath string) (bool, error) {
|
||||
// See func (repo *Repository) CustomAvatarRelativePath()
|
||||
// repo.Avatar is used directly as the storage path - therefore we can check for existence directly using the path
|
||||
return db.GetEngine(ctx).Where("`avatar`=?", storagePath).Exist(new(Repository))
|
||||
}
|
||||
|
||||
// RelAvatarLink returns a relative link to the repository's avatar.
|
||||
func (repo *Repository) RelAvatarLink() string {
|
||||
return repo.relAvatarLink(db.DefaultContext)
|
||||
|
@ -138,7 +138,7 @@ func ChangeCollaborationAccessModeCtx(ctx context.Context, repo *Repository, uid
|
||||
|
||||
// ChangeCollaborationAccessMode sets new access mode for the collaboration.
|
||||
func ChangeCollaborationAccessMode(repo *Repository, uid int64, mode perm.AccessMode) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ func GetTopLanguageStats(repo *Repository, limit int) (LanguageStatList, error)
|
||||
|
||||
// UpdateLanguageStats updates the language statistics for repository
|
||||
func UpdateLanguageStats(repo *Repository, commitID string, stats map[string]int64) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -182,7 +182,7 @@ func UpdateLanguageStats(repo *Repository, commitID string, stats map[string]int
|
||||
|
||||
// CopyLanguageStat Copy originalRepo language stat information to destRepo (use for forked repo)
|
||||
func CopyLanguageStat(originalRepo, destRepo *Repository) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -120,9 +120,9 @@ func GetPushMirrorsByRepoID(ctx context.Context, repoID int64, listOptions db.Li
|
||||
}
|
||||
|
||||
// GetPushMirrorsSyncedOnCommit returns push-mirrors for this repo that should be updated by new commits
|
||||
func GetPushMirrorsSyncedOnCommit(repoID int64) ([]*PushMirror, error) {
|
||||
func GetPushMirrorsSyncedOnCommit(ctx context.Context, repoID int64) ([]*PushMirror, error) {
|
||||
mirrors := make([]*PushMirror, 0, 10)
|
||||
return mirrors, db.GetEngine(db.DefaultContext).
|
||||
return mirrors, db.GetEngine(ctx).
|
||||
Where("repo_id=? AND sync_on_commit=?", repoID, true).
|
||||
Find(&mirrors)
|
||||
}
|
||||
|
@ -90,7 +90,8 @@ func init() {
|
||||
db.RegisterModel(new(Release))
|
||||
}
|
||||
|
||||
func (r *Release) loadAttributes(ctx context.Context) error {
|
||||
// LoadAttributes load repo and publisher attributes for a release
|
||||
func (r *Release) LoadAttributes(ctx context.Context) error {
|
||||
var err error
|
||||
if r.Repo == nil {
|
||||
r.Repo, err = GetRepositoryByIDCtx(ctx, r.RepoID)
|
||||
@ -111,11 +112,6 @@ func (r *Release) loadAttributes(ctx context.Context) error {
|
||||
return GetReleaseAttachments(ctx, r)
|
||||
}
|
||||
|
||||
// LoadAttributes load repo and publisher attributes for a release
|
||||
func (r *Release) LoadAttributes() error {
|
||||
return r.loadAttributes(db.DefaultContext)
|
||||
}
|
||||
|
||||
// APIURL the api url for a release. release must have attributes loaded
|
||||
func (r *Release) APIURL() string {
|
||||
return r.Repo.APIURL() + "/releases/" + strconv.FormatInt(r.ID, 10)
|
||||
@ -241,8 +237,8 @@ func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
|
||||
}
|
||||
|
||||
// GetReleasesByRepoID returns a list of releases of repository.
|
||||
func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions) ([]*Release, error) {
|
||||
sess := db.GetEngine(db.DefaultContext).
|
||||
func GetReleasesByRepoID(ctx context.Context, repoID int64, opts FindReleasesOptions) ([]*Release, error) {
|
||||
sess := db.GetEngine(ctx).
|
||||
Desc("created_unix", "id").
|
||||
Where(opts.toConds(repoID))
|
||||
|
||||
@ -381,8 +377,8 @@ func SortReleases(rels []*Release) {
|
||||
}
|
||||
|
||||
// DeleteReleaseByID deletes a release from database by given ID.
|
||||
func DeleteReleaseByID(id int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).ID(id).Delete(new(Release))
|
||||
func DeleteReleaseByID(ctx context.Context, id int64) error {
|
||||
_, err := db.GetEngine(ctx).ID(id).Delete(new(Release))
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -236,14 +236,6 @@ func (repo *Repository) AfterLoad() {
|
||||
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
|
||||
}
|
||||
|
||||
// MustOwner always returns a valid *user_model.User object to avoid
|
||||
// conceptually impossible error handling.
|
||||
// It creates a fake object that contains error details
|
||||
// when error occurs.
|
||||
func (repo *Repository) MustOwner() *user_model.User {
|
||||
return repo.mustOwner(db.DefaultContext)
|
||||
}
|
||||
|
||||
// LoadAttributes loads attributes of the repository.
|
||||
func (repo *Repository) LoadAttributes(ctx context.Context) error {
|
||||
// Load owner
|
||||
@ -403,7 +395,11 @@ func (repo *Repository) GetOwner(ctx context.Context) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (repo *Repository) mustOwner(ctx context.Context) *user_model.User {
|
||||
// MustOwner always returns a valid *user_model.User object to avoid
|
||||
// conceptually impossible error handling.
|
||||
// It creates a fake object that contains error details
|
||||
// when error occurs.
|
||||
func (repo *Repository) MustOwner(ctx context.Context) *user_model.User {
|
||||
if err := repo.GetOwner(ctx); err != nil {
|
||||
return &user_model.User{
|
||||
Name: "error",
|
||||
@ -438,7 +434,7 @@ func (repo *Repository) ComposeMetas() map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
repo.MustOwner()
|
||||
repo.MustOwner(db.DefaultContext)
|
||||
if repo.Owner.IsOrganization() {
|
||||
teams := make([]string, 0, 5)
|
||||
_ = db.GetEngine(db.DefaultContext).Table("team_repo").
|
||||
@ -792,13 +788,13 @@ func UpdateRepoIssueNumbers(ctx context.Context, repoID int64, isPull, isClosed
|
||||
}
|
||||
|
||||
// CountNullArchivedRepository counts the number of repositories with is_archived is null
|
||||
func CountNullArchivedRepository() (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Count(new(Repository))
|
||||
func CountNullArchivedRepository(ctx context.Context) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(builder.IsNull{"is_archived"}).Count(new(Repository))
|
||||
}
|
||||
|
||||
// FixNullArchivedRepository sets is_archived to false where it is null
|
||||
func FixNullArchivedRepository() (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Cols("is_archived").NoAutoTime().Update(&Repository{
|
||||
func FixNullArchivedRepository(ctx context.Context) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(builder.IsNull{"is_archived"}).Cols("is_archived").NoAutoTime().Update(&Repository{
|
||||
IsArchived: false,
|
||||
})
|
||||
}
|
||||
|
@ -518,14 +518,13 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
|
||||
|
||||
// SearchRepository returns repositories based on search options,
|
||||
// it returns results in given range and number of total results.
|
||||
func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
func SearchRepository(ctx context.Context, opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
cond := SearchRepositoryCondition(opts)
|
||||
return SearchRepositoryByCondition(opts, cond, true)
|
||||
return SearchRepositoryByCondition(ctx, opts, cond, true)
|
||||
}
|
||||
|
||||
// SearchRepositoryByCondition search repositories by condition
|
||||
func SearchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) {
|
||||
ctx := db.DefaultContext
|
||||
func SearchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) {
|
||||
sess, count, err := searchRepositoryByCondition(ctx, opts, cond)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
@ -652,9 +651,9 @@ func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) bu
|
||||
|
||||
// SearchRepositoryByName takes keyword and part of repository name to search,
|
||||
// it returns results in given range and number of total results.
|
||||
func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
func SearchRepositoryByName(ctx context.Context, opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
opts.IncludeDescription = false
|
||||
return SearchRepository(opts)
|
||||
return SearchRepository(ctx, opts)
|
||||
}
|
||||
|
||||
// SearchRepositoryIDs takes keyword and part of repository name to search,
|
||||
|
@ -20,7 +20,7 @@ func TestSearchRepository(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// test search public repository on explore page
|
||||
repos, count, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
|
||||
repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
@ -35,7 +35,7 @@ func TestSearchRepository(t *testing.T) {
|
||||
}
|
||||
assert.Equal(t, int64(1), count)
|
||||
|
||||
repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
|
||||
repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
@ -49,7 +49,7 @@ func TestSearchRepository(t *testing.T) {
|
||||
assert.Len(t, repos, 2)
|
||||
|
||||
// test search private repository on explore page
|
||||
repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
|
||||
repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
@ -65,7 +65,7 @@ func TestSearchRepository(t *testing.T) {
|
||||
}
|
||||
assert.Equal(t, int64(1), count)
|
||||
|
||||
repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
|
||||
repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
@ -80,14 +80,14 @@ func TestSearchRepository(t *testing.T) {
|
||||
assert.Len(t, repos, 3)
|
||||
|
||||
// Test non existing owner
|
||||
repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID})
|
||||
repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, repos)
|
||||
assert.Equal(t, int64(0), count)
|
||||
|
||||
// Test search within description
|
||||
repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{
|
||||
repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
@ -104,7 +104,7 @@ func TestSearchRepository(t *testing.T) {
|
||||
assert.Equal(t, int64(1), count)
|
||||
|
||||
// Test NOT search within description
|
||||
repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{
|
||||
repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
@ -277,7 +277,7 @@ func TestSearchRepository(t *testing.T) {
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
repos, count, err := repo_model.SearchRepositoryByName(testCase.opts)
|
||||
repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, testCase.opts)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(testCase.count), count)
|
||||
@ -377,7 +377,7 @@ func TestSearchRepositoryByTopicName(t *testing.T) {
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
_, count, err := repo_model.SearchRepositoryByName(testCase.opts)
|
||||
_, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, testCase.opts)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(testCase.count), count)
|
||||
})
|
||||
|
@ -241,7 +241,7 @@ func UpdateRepoUnit(unit *RepoUnit) error {
|
||||
|
||||
// UpdateRepositoryUnits updates a repository's units
|
||||
func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes []unit.Type) (err error) {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ func init() {
|
||||
|
||||
// StarRepo or unstar repository.
|
||||
func StarRepo(userID, repoID int64, star bool) error {
|
||||
ctx, committer, err := db.TxContext()
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user