mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-18 21:42:56 +02:00
merge main
This commit is contained in:
commit
335375fd76
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@ _test
|
|||||||
|
|
||||||
# IntelliJ
|
# IntelliJ
|
||||||
.idea
|
.idea
|
||||||
|
.run
|
||||||
|
|
||||||
# IntelliJ Gateway
|
# IntelliJ Gateway
|
||||||
.uuid
|
.uuid
|
||||||
|
22
assets/go-licenses.json
generated
22
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
@ -54,8 +54,10 @@ func runACME(listenAddr string, m http.Handler) error {
|
|||||||
altTLSALPNPort = p
|
altTLSALPNPort = p
|
||||||
}
|
}
|
||||||
|
|
||||||
magic := &certmagic.Default
|
// FIXME: this path is not right, it uses "AppWorkPath" incorrectly, and writes the data into "AppWorkPath/https"
|
||||||
magic.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
|
// Ideally it should migrate to AppDataPath write to "AppDataPath/https"
|
||||||
|
certmagic.Default.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
|
||||||
|
magic := certmagic.NewDefault()
|
||||||
// Try to use private CA root if provided, otherwise defaults to system's trust
|
// Try to use private CA root if provided, otherwise defaults to system's trust
|
||||||
var certPool *x509.CertPool
|
var certPool *x509.CertPool
|
||||||
if setting.AcmeCARoot != "" {
|
if setting.AcmeCARoot != "" {
|
||||||
|
@ -78,8 +78,9 @@ RUN_USER = ; git
|
|||||||
;; Set the domain for the server
|
;; Set the domain for the server
|
||||||
;DOMAIN = localhost
|
;DOMAIN = localhost
|
||||||
;;
|
;;
|
||||||
;; Overwrite the automatically generated public URL. Necessary for proxies and docker.
|
;; The AppURL used by Gitea to generate absolute links, defaults to "{PROTOCOL}://{DOMAIN}:{HTTP_PORT}/".
|
||||||
;ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
|
;; Most users should set it to the real website URL of their Gitea instance.
|
||||||
|
;ROOT_URL =
|
||||||
;;
|
;;
|
||||||
;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy.
|
;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy.
|
||||||
;; DO NOT USE IT IN PRODUCTION!!!
|
;; DO NOT USE IT IN PRODUCTION!!!
|
||||||
@ -103,8 +104,8 @@ RUN_USER = ; git
|
|||||||
;REDIRECT_OTHER_PORT = false
|
;REDIRECT_OTHER_PORT = false
|
||||||
;PORT_TO_REDIRECT = 80
|
;PORT_TO_REDIRECT = 80
|
||||||
;;
|
;;
|
||||||
;; expect PROXY protocol header on connections to https redirector.
|
;; expect PROXY protocol header on connections to https redirector, defaults to USE_PROXY_PROTOCOL
|
||||||
;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s
|
;REDIRECTOR_USE_PROXY_PROTOCOL =
|
||||||
;; Minimum and maximum supported TLS versions
|
;; Minimum and maximum supported TLS versions
|
||||||
;SSL_MIN_VERSION=TLSv1.2
|
;SSL_MIN_VERSION=TLSv1.2
|
||||||
;SSL_MAX_VERSION=
|
;SSL_MAX_VERSION=
|
||||||
@ -128,13 +129,14 @@ RUN_USER = ; git
|
|||||||
;; most cases you do not need to change the default value. Alter it only if
|
;; 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. For different protocol, the default
|
;; your SSH server node is not the same as HTTP node. For different protocol, the default
|
||||||
;; values are different. If `PROTOCOL` is `http+unix`, the default value is `http://unix/`.
|
;; values are different. If `PROTOCOL` is `http+unix`, the default value is `http://unix/`.
|
||||||
;; If `PROTOCOL` is `fcgi` or `fcgi+unix`, the default value is `%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/`.
|
;; If `PROTOCOL` is `fcgi` or `fcgi+unix`, the default value is `{PROTOCOL}://{HTTP_ADDR}:{HTTP_PORT}/`.
|
||||||
;; If listen on `0.0.0.0`, the default value is `%(PROTOCOL)s://localhost:%(HTTP_PORT)s/`, Otherwise the default
|
;; If listen on `0.0.0.0`, the default value is `{PROTOCOL}://localhost:{HTTP_PORT}/`.
|
||||||
;; value is `%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/`.
|
;; Otherwise the default value is `{PROTOCOL}://{HTTP_ADDR}:{HTTP_PORT}/`.
|
||||||
;LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
|
;; Most users don't need (and shouldn't) set this value.
|
||||||
|
;LOCAL_ROOT_URL =
|
||||||
;;
|
;;
|
||||||
;; When making local connections pass the PROXY protocol header.
|
;; When making local connections pass the PROXY protocol header, defaults to USE_PROXY_PROTOCOL
|
||||||
;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s
|
;LOCAL_USE_PROXY_PROTOCOL =
|
||||||
;;
|
;;
|
||||||
;; Disable SSH feature when not available
|
;; Disable SSH feature when not available
|
||||||
;DISABLE_SSH = false
|
;DISABLE_SSH = false
|
||||||
@ -146,13 +148,17 @@ RUN_USER = ; git
|
|||||||
;SSH_SERVER_USE_PROXY_PROTOCOL = false
|
;SSH_SERVER_USE_PROXY_PROTOCOL = false
|
||||||
;;
|
;;
|
||||||
;; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER.
|
;; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER.
|
||||||
;BUILTIN_SSH_SERVER_USER = %(RUN_USER)s
|
;BUILTIN_SSH_SERVER_USER =
|
||||||
;;
|
;;
|
||||||
;; Domain name to be exposed in clone URL
|
;; Domain name to be exposed in clone URL, defaults to DOMAIN or the domain part of ROOT_URL
|
||||||
;SSH_DOMAIN = %(DOMAIN)s
|
;SSH_DOMAIN =
|
||||||
;;
|
;;
|
||||||
;; SSH username displayed in clone URLs.
|
;; SSH username displayed in clone URLs. It defaults to BUILTIN_SSH_SERVER_USER or RUN_USER.
|
||||||
;SSH_USER = %(BUILTIN_SSH_SERVER_USER)s
|
;; If it is set to "(DOER_USERNAME)", it will use current signed-in user's username.
|
||||||
|
;; This option is only for some advanced users who have configured their SSH reverse-proxy
|
||||||
|
;; and need to use different usernames for git SSH clone.
|
||||||
|
;; Most users should just leave it blank.
|
||||||
|
;SSH_USER =
|
||||||
;;
|
;;
|
||||||
;; The network interface the builtin SSH server should listen on
|
;; The network interface the builtin SSH server should listen on
|
||||||
;SSH_LISTEN_HOST =
|
;SSH_LISTEN_HOST =
|
||||||
@ -160,8 +166,8 @@ RUN_USER = ; git
|
|||||||
;; Port number to be exposed in clone URL
|
;; Port number to be exposed in clone URL
|
||||||
;SSH_PORT = 22
|
;SSH_PORT = 22
|
||||||
;;
|
;;
|
||||||
;; The port number the builtin SSH server should listen on
|
;; The port number the builtin SSH server should listen on, defaults to SSH_PORT
|
||||||
;SSH_LISTEN_PORT = %(SSH_PORT)s
|
;SSH_LISTEN_PORT =
|
||||||
;;
|
;;
|
||||||
;; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
|
;; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
|
||||||
;SSH_ROOT_PATH =
|
;SSH_ROOT_PATH =
|
||||||
@ -188,7 +194,7 @@ RUN_USER = ; git
|
|||||||
;;
|
;;
|
||||||
;; For the built-in SSH server, choose the keypair to offer as the host key
|
;; 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
|
;; 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)s
|
;; relative paths are made absolute relative to the APP_DATA_PATH
|
||||||
;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa
|
;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa
|
||||||
;;
|
;;
|
||||||
;; Directory to create temporary files in when testing public keys using ssh-keygen,
|
;; Directory to create temporary files in when testing public keys using ssh-keygen,
|
||||||
@ -582,7 +588,7 @@ ENABLED = true
|
|||||||
[log]
|
[log]
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Root path for the log files - defaults to %(GITEA_WORK_DIR)/log
|
;; Root path for the log files - defaults to "{AppWorkPath}/log"
|
||||||
;ROOT_PATH =
|
;ROOT_PATH =
|
||||||
;;
|
;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@ -682,8 +688,8 @@ LEVEL = Info
|
|||||||
;; The path of git executable. If empty, Gitea searches through the PATH environment.
|
;; The path of git executable. If empty, Gitea searches through the PATH environment.
|
||||||
;PATH =
|
;PATH =
|
||||||
;;
|
;;
|
||||||
;; The HOME directory for Git
|
;; The HOME directory for Git, defaults to "{APP_DATA_PATH}/home"
|
||||||
;HOME_PATH = %(APP_DATA_PATH)s/home
|
;HOME_PATH =
|
||||||
;;
|
;;
|
||||||
;; Disables highlight of added and removed changes
|
;; Disables highlight of added and removed changes
|
||||||
;DISABLE_DIFF_HIGHLIGHT = false
|
;DISABLE_DIFF_HIGHLIGHT = false
|
||||||
@ -946,8 +952,8 @@ LEVEL = Info
|
|||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;[repository]
|
;[repository]
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)s/gitea-repositories.
|
;; Root path for storing all repository data. By default, it is set to "{APP_DATA_PATH}/gitea-repositories".
|
||||||
;; A relative path is interpreted as _`AppWorkPath`_/%(ROOT)s
|
;; A relative path is interpreted as "{AppWorkPath}/{ROOT}" (use AppWorkPath as base path).
|
||||||
;ROOT =
|
;ROOT =
|
||||||
;;
|
;;
|
||||||
;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available.
|
;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available.
|
||||||
@ -1506,7 +1512,8 @@ LEVEL = Info
|
|||||||
;TYPE = persistable-channel
|
;TYPE = persistable-channel
|
||||||
;;
|
;;
|
||||||
;; data-dir for storing persistable queues and level queues, individual queues will default to `queues/common` meaning the queue is shared.
|
;; data-dir for storing persistable queues and level queues, individual queues will default to `queues/common` meaning the queue is shared.
|
||||||
;DATADIR = queues/ ; Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
|
;; Relative paths will be made absolute against "APP_DATA_PATH"
|
||||||
|
;DATADIR = queues/
|
||||||
;;
|
;;
|
||||||
;; Default queue length before a channel queue will block
|
;; Default queue length before a channel queue will block
|
||||||
;LENGTH = 100000
|
;LENGTH = 100000
|
||||||
|
37
go.mod
37
go.mod
@ -24,10 +24,10 @@ require (
|
|||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1
|
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
||||||
github.com/ProtonMail/go-crypto v1.0.0
|
github.com/ProtonMail/go-crypto v1.1.4
|
||||||
github.com/PuerkitoBio/goquery v1.10.0
|
github.com/PuerkitoBio/goquery v1.10.0
|
||||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3
|
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3
|
||||||
github.com/alecthomas/chroma/v2 v2.14.0
|
github.com/alecthomas/chroma/v2 v2.15.0
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.42
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.42
|
||||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.27.3
|
github.com/aws/aws-sdk-go-v2/service/codecommit v1.27.3
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||||
@ -54,8 +54,8 @@ require (
|
|||||||
github.com/go-chi/cors v1.2.1
|
github.com/go-chi/cors v1.2.1
|
||||||
github.com/go-co-op/gocron v1.37.0
|
github.com/go-co-op/gocron v1.37.0
|
||||||
github.com/go-enry/go-enry/v2 v2.9.1
|
github.com/go-enry/go-enry/v2 v2.9.1
|
||||||
github.com/go-git/go-billy/v5 v5.6.0
|
github.com/go-git/go-billy/v5 v5.6.1
|
||||||
github.com/go-git/go-git/v5 v5.12.0
|
github.com/go-git/go-git/v5 v5.13.1
|
||||||
github.com/go-ldap/ldap/v3 v3.4.8
|
github.com/go-ldap/ldap/v3 v3.4.8
|
||||||
github.com/go-redsync/redsync/v4 v4.13.0
|
github.com/go-redsync/redsync/v4 v4.13.0
|
||||||
github.com/go-sql-driver/mysql v1.8.1
|
github.com/go-sql-driver/mysql v1.8.1
|
||||||
@ -71,7 +71,6 @@ require (
|
|||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/feeds v1.2.0
|
github.com/gorilla/feeds v1.2.0
|
||||||
github.com/gorilla/sessions v1.4.0
|
github.com/gorilla/sessions v1.4.0
|
||||||
github.com/h2non/gock v1.2.0
|
|
||||||
github.com/hashicorp/go-version v1.7.0
|
github.com/hashicorp/go-version v1.7.0
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||||
github.com/huandu/xstrings v1.5.0
|
github.com/huandu/xstrings v1.5.0
|
||||||
@ -107,28 +106,28 @@ require (
|
|||||||
github.com/sassoftware/go-rpmutils v0.4.0
|
github.com/sassoftware/go-rpmutils v0.4.0
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
|
||||||
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92
|
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/syndtr/goleveldb v1.0.0
|
github.com/syndtr/goleveldb v1.0.0
|
||||||
github.com/tstranex/u2f v1.0.0
|
github.com/tstranex/u2f v1.0.0
|
||||||
github.com/ulikunitz/xz v0.5.12
|
github.com/ulikunitz/xz v0.5.12
|
||||||
github.com/urfave/cli/v2 v2.27.5
|
github.com/urfave/cli/v2 v2.27.5
|
||||||
github.com/wneessen/go-mail v0.5.2
|
github.com/wneessen/go-mail v0.5.2
|
||||||
github.com/xanzy/go-gitlab v0.112.0
|
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
github.com/yohcop/openid-go v1.0.1
|
github.com/yohcop/openid-go v1.0.1
|
||||||
github.com/yuin/goldmark v1.7.8
|
github.com/yuin/goldmark v1.7.8
|
||||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||||
github.com/yuin/goldmark-meta v1.1.0
|
github.com/yuin/goldmark-meta v1.1.0
|
||||||
golang.org/x/crypto v0.31.0
|
gitlab.com/gitlab-org/api/client-go v0.119.0
|
||||||
|
golang.org/x/crypto v0.32.0
|
||||||
golang.org/x/image v0.21.0
|
golang.org/x/image v0.21.0
|
||||||
golang.org/x/net v0.33.0
|
golang.org/x/net v0.34.0
|
||||||
golang.org/x/oauth2 v0.23.0
|
golang.org/x/oauth2 v0.24.0
|
||||||
golang.org/x/sync v0.10.0
|
golang.org/x/sync v0.10.0
|
||||||
golang.org/x/sys v0.28.0
|
golang.org/x/sys v0.29.0
|
||||||
golang.org/x/text v0.21.0
|
golang.org/x/text v0.21.0
|
||||||
golang.org/x/tools v0.26.0
|
golang.org/x/tools v0.29.0
|
||||||
google.golang.org/grpc v1.67.1
|
google.golang.org/grpc v1.67.1
|
||||||
google.golang.org/protobuf v1.35.1
|
google.golang.org/protobuf v1.36.0
|
||||||
gopkg.in/ini.v1 v1.67.0
|
gopkg.in/ini.v1 v1.67.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
mvdan.cc/xurls/v2 v2.5.0
|
mvdan.cc/xurls/v2 v2.5.0
|
||||||
@ -187,7 +186,7 @@ require (
|
|||||||
github.com/couchbase/gomemcached v0.3.2 // indirect
|
github.com/couchbase/gomemcached v0.3.2 // indirect
|
||||||
github.com/couchbase/goutils v0.1.2 // indirect
|
github.com/couchbase/goutils v0.1.2 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.3.4 // indirect
|
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/davidmz/go-pageant v1.0.2 // indirect
|
github.com/davidmz/go-pageant v1.0.2 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
@ -220,7 +219,7 @@ require (
|
|||||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||||
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect
|
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/btree v1.1.3 // indirect
|
github.com/google/btree v1.1.3 // indirect
|
||||||
@ -230,7 +229,6 @@ require (
|
|||||||
github.com/gorilla/handlers v1.5.2 // indirect
|
github.com/gorilla/handlers v1.5.2 // indirect
|
||||||
github.com/gorilla/mux v1.8.1 // indirect
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
|
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
@ -255,6 +253,7 @@ require (
|
|||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
|
github.com/mmcloughlin/avo v0.6.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
||||||
@ -266,7 +265,7 @@ require (
|
|||||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
github.com/pjbgf/sha1cd v0.3.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common v0.60.1 // indirect
|
github.com/prometheus/common v0.60.1 // indirect
|
||||||
@ -306,8 +305,8 @@ require (
|
|||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
|
||||||
golang.org/x/mod v0.21.0 // indirect
|
golang.org/x/mod v0.22.0 // indirect
|
||||||
golang.org/x/time v0.7.0 // indirect
|
golang.org/x/time v0.8.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
100
go.sum
100
go.sum
@ -71,8 +71,8 @@ github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSC
|
|||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
|
github.com/ProtonMail/go-crypto v1.1.4 h1:G5U5asvD5N/6/36oIw3k2bOfBn5XVcZrb7PBjzzKKoE=
|
||||||
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
github.com/ProtonMail/go-crypto v1.1.4/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||||
github.com/PuerkitoBio/goquery v1.10.0 h1:6fiXdLuUvYs2OJSvNRqlNPoBm6YABE226xrbavY5Wv4=
|
github.com/PuerkitoBio/goquery v1.10.0 h1:6fiXdLuUvYs2OJSvNRqlNPoBm6YABE226xrbavY5Wv4=
|
||||||
github.com/PuerkitoBio/goquery v1.10.0/go.mod h1:TjZZl68Q3eGHNBA8CWaxAN7rOU1EbDz3CWuolcO5Yu4=
|
github.com/PuerkitoBio/goquery v1.10.0/go.mod h1:TjZZl68Q3eGHNBA8CWaxAN7rOU1EbDz3CWuolcO5Yu4=
|
||||||
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||||
@ -81,11 +81,11 @@ github.com/RoaringBitmap/roaring v1.9.4 h1:yhEIoH4YezLYT04s1nHehNO64EKFTop/wBhxv
|
|||||||
github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
|
github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
|
||||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3 h1:BP0HiyNT3AQEYi+if3wkRcIdQFHtsw6xX3Kx0glckgA=
|
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3 h1:BP0HiyNT3AQEYi+if3wkRcIdQFHtsw6xX3Kx0glckgA=
|
||||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3/go.mod h1:hMNtySovKkn2gdDuLqnqveP+mfhUSaBdoBcr2I7Zt0E=
|
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3/go.mod h1:hMNtySovKkn2gdDuLqnqveP+mfhUSaBdoBcr2I7Zt0E=
|
||||||
github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
|
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||||
github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||||
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
|
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
|
||||||
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
|
github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
|
||||||
github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
|
github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
|
||||||
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
||||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||||
@ -188,7 +188,6 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
|||||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||||
github.com/buildkite/terminal-to-html/v3 v3.16.3 h1:IGuJjboHjuMLWOGsKZKNxbbn41emOLiHzXPmQZk31fk=
|
github.com/buildkite/terminal-to-html/v3 v3.16.3 h1:IGuJjboHjuMLWOGsKZKNxbbn41emOLiHzXPmQZk31fk=
|
||||||
github.com/buildkite/terminal-to-html/v3 v3.16.3/go.mod h1:r/J7cC9c3EzBzP3/wDz0RJLPwv5PUAMp+KF2w+ntMc0=
|
github.com/buildkite/terminal-to-html/v3 v3.16.3/go.mod h1:r/J7cC9c3EzBzP3/wDz0RJLPwv5PUAMp+KF2w+ntMc0=
|
||||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
|
||||||
github.com/caddyserver/certmagic v0.21.4 h1:e7VobB8rffHv8ZZpSiZtEwnLDHUwLVYLWzWSa1FfKI0=
|
github.com/caddyserver/certmagic v0.21.4 h1:e7VobB8rffHv8ZZpSiZtEwnLDHUwLVYLWzWSa1FfKI0=
|
||||||
github.com/caddyserver/certmagic v0.21.4/go.mod h1:swUXjQ1T9ZtMv95qj7/InJvWLXURU85r+CfG0T+ZbDE=
|
github.com/caddyserver/certmagic v0.21.4/go.mod h1:swUXjQ1T9ZtMv95qj7/InJvWLXURU85r+CfG0T+ZbDE=
|
||||||
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
||||||
@ -205,7 +204,6 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA
|
|||||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
|
||||||
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
|
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
|
||||||
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
@ -223,8 +221,8 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc
|
|||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cyphar/filepath-securejoin v0.3.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8=
|
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
|
||||||
github.com/cyphar/filepath-securejoin v0.3.4/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM=
|
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
@ -254,8 +252,8 @@ github.com/dvyukov/go-fuzz v0.0.0-20210429054444-fca39067bc72/go.mod h1:11Gm+ccJ
|
|||||||
github.com/editorconfig/editorconfig-core-go/v2 v2.6.2 h1:dKG8sc7n321deIVRcQtwlMNoBEra7j0qQ8RwxO8RN0w=
|
github.com/editorconfig/editorconfig-core-go/v2 v2.6.2 h1:dKG8sc7n321deIVRcQtwlMNoBEra7j0qQ8RwxO8RN0w=
|
||||||
github.com/editorconfig/editorconfig-core-go/v2 v2.6.2/go.mod h1:7dvD3GCm7eBw53xZ/lsiq72LqobdMg3ITbMBxnmJmqY=
|
github.com/editorconfig/editorconfig-core-go/v2 v2.6.2/go.mod h1:7dvD3GCm7eBw53xZ/lsiq72LqobdMg3ITbMBxnmJmqY=
|
||||||
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ=
|
||||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64=
|
||||||
github.com/emersion/go-imap v1.2.1 h1:+s9ZjMEjOB8NzZMVTM3cCenz2JrQIGGo5j1df19WjTA=
|
github.com/emersion/go-imap v1.2.1 h1:+s9ZjMEjOB8NzZMVTM3cCenz2JrQIGGo5j1df19WjTA=
|
||||||
github.com/emersion/go-imap v1.2.1/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
|
github.com/emersion/go-imap v1.2.1/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
|
||||||
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
|
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
|
||||||
@ -313,12 +311,12 @@ github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5Hql
|
|||||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
|
github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA=
|
||||||
github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
|
github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||||
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
|
github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
|
||||||
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
|
github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
|
||||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
|
github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
|
||||||
@ -385,8 +383,8 @@ github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei
|
|||||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||||
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 h1:HKlyj6in2JV6wVkmQ4XmG/EIm+SCYlPZ+V4GWit7Z+I=
|
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 h1:HKlyj6in2JV6wVkmQ4XmG/EIm+SCYlPZ+V4GWit7Z+I=
|
||||||
github.com/golang/geo v0.0.0-20230421003525-6adc56603217/go.mod h1:8wI0hitZ3a1IxZfeH3/5I97CI8i5cLGsYe7xNhQGs9U=
|
github.com/golang/geo v0.0.0-20230421003525-6adc56603217/go.mod h1:8wI0hitZ3a1IxZfeH3/5I97CI8i5cLGsYe7xNhQGs9U=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
@ -452,10 +450,6 @@ github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z
|
|||||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
|
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
|
||||||
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
|
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
|
||||||
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
|
|
||||||
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
|
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
@ -585,6 +579,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
|
|||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
|
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
|
||||||
|
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@ -599,8 +595,6 @@ github.com/msteinert/pam v1.2.0 h1:mYfjlvN2KYs2Pb9G6nb/1f/nPfAttT/Jee5Sq9r3bGE=
|
|||||||
github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0=
|
github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
|
|
||||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
|
||||||
github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek=
|
github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek=
|
||||||
github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o=
|
github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o=
|
||||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||||
@ -637,8 +631,8 @@ github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG
|
|||||||
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
github.com/pjbgf/sha1cd v0.3.1 h1:Dh2GYdpJnO84lIw0LJwTFXjcNbasP/bklicSznyAaPI=
|
||||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
github.com/pjbgf/sha1cd v0.3.1/go.mod h1:Y8t7jSB/dEI/lQE04A1HVKteqjj9bX5O4+Cex0TCu8s=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
@ -743,8 +737,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
|
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
|
||||||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
|
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
|
||||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
@ -772,8 +766,6 @@ github.com/wneessen/go-mail v0.5.2 h1:MZKwgHJoRboLJ+EHMLuHpZc95wo+u1xViL/4XSswDT
|
|||||||
github.com/wneessen/go-mail v0.5.2/go.mod h1:kRroJvEq2hOSEPFRiKjN7Csrz0G1w+RpiGR3b6yo+Ck=
|
github.com/wneessen/go-mail v0.5.2/go.mod h1:kRroJvEq2hOSEPFRiKjN7Csrz0G1w+RpiGR3b6yo+Ck=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/xanzy/go-gitlab v0.112.0 h1:6Z0cqEooCvBMfBIHw+CgO4AKGRV8na/9781xOb0+DKw=
|
|
||||||
github.com/xanzy/go-gitlab v0.112.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY=
|
|
||||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
@ -808,6 +800,8 @@ github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
|
|||||||
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
|
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
|
||||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||||
|
gitlab.com/gitlab-org/api/client-go v0.119.0 h1:YBZyx9XUTtEDBBYtY36cZWz6JmT7om/8HPSk37IS95g=
|
||||||
|
gitlab.com/gitlab-org/api/client-go v0.119.0/go.mod h1:ygHmS3AU3TpvK+AC6DYO1QuAxLlv6yxYK+/Votr/WFQ=
|
||||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||||
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
||||||
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
||||||
@ -829,16 +823,14 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
|
||||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||||
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
|
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
|
||||||
@ -852,8 +844,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@ -865,20 +857,18 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
|
||||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -916,8 +906,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -927,14 +915,12 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|||||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
|
||||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
@ -942,15 +928,13 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
|||||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||||
golang.org/x/text v0.3.0/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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
@ -958,8 +942,8 @@ golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|||||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
@ -970,8 +954,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@ -986,8 +970,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
|
|||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
|
||||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
@ -154,7 +154,7 @@ func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) {
|
func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) {
|
||||||
if run.Event == webhook_module.HookEventPullRequest || run.Event == webhook_module.HookEventPullRequestSync {
|
if run.Event.IsPullRequest() {
|
||||||
var payload api.PullRequestPayload
|
var payload api.PullRequestPayload
|
||||||
if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil {
|
if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
"github.com/keybase/go-crypto/openpgp/packet"
|
"github.com/keybase/go-crypto/openpgp/packet"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCheckArmoredGPGKeyString(t *testing.T) {
|
func TestCheckArmoredGPGKeyString(t *testing.T) {
|
||||||
@ -107,9 +108,8 @@ MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg==
|
|||||||
=i9b7
|
=i9b7
|
||||||
-----END PGP PUBLIC KEY BLOCK-----`
|
-----END PGP PUBLIC KEY BLOCK-----`
|
||||||
keys, err := checkArmoredGPGKeyString(testGPGArmor)
|
keys, err := checkArmoredGPGKeyString(testGPGArmor)
|
||||||
if !assert.NotEmpty(t, keys) {
|
require.NotEmpty(t, keys)
|
||||||
return
|
|
||||||
}
|
|
||||||
ekey := keys[0]
|
ekey := keys[0]
|
||||||
assert.NoError(t, err, "Could not parse a valid GPG armored key", ekey)
|
assert.NoError(t, err, "Could not parse a valid GPG armored key", ekey)
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
_ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys
|
_ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDumpDatabase(t *testing.T) {
|
func TestDumpDatabase(t *testing.T) {
|
||||||
@ -62,9 +63,7 @@ func TestPrimaryKeys(t *testing.T) {
|
|||||||
// Import "code.gitea.io/gitea/cmd" to make sure each db.RegisterModel in init functions has been called.
|
// Import "code.gitea.io/gitea/cmd" to make sure each db.RegisterModel in init functions has been called.
|
||||||
|
|
||||||
beans, err := db.NamesToBean()
|
beans, err := db.NamesToBean()
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
whitelist := map[string]string{
|
whitelist := map[string]string{
|
||||||
"the_table_name_to_skip_checking": "Write a note here to explain why",
|
"the_table_name_to_skip_checking": "Write a note here to explain why",
|
||||||
@ -79,8 +78,6 @@ func TestPrimaryKeys(t *testing.T) {
|
|||||||
t.Logf("ignore %q because %q", table.Name, why)
|
t.Logf("ignore %q because %q", table.Name, why)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(table.PrimaryKeys) == 0 {
|
assert.NotEmpty(t, table.PrimaryKeys, "table %q has no primary key", table.Name)
|
||||||
t.Errorf("table %q has no primary key", table.Name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,23 +46,6 @@ func (err ErrIssueNotExist) Unwrap() error {
|
|||||||
return util.ErrNotExist
|
return util.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrIssueIsClosed represents a "IssueIsClosed" kind of error.
|
|
||||||
type ErrIssueIsClosed struct {
|
|
||||||
ID int64
|
|
||||||
RepoID int64
|
|
||||||
Index int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrIssueIsClosed checks if an error is a ErrIssueNotExist.
|
|
||||||
func IsErrIssueIsClosed(err error) bool {
|
|
||||||
_, ok := err.(ErrIssueIsClosed)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrIssueIsClosed) Error() string {
|
|
||||||
return fmt.Sprintf("issue is closed [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNewIssueInsert is used when the INSERT statement in newIssue fails
|
// ErrNewIssueInsert is used when the INSERT statement in newIssue fails
|
||||||
type ErrNewIssueInsert struct {
|
type ErrNewIssueInsert struct {
|
||||||
OriginalError error
|
OriginalError error
|
||||||
@ -78,22 +61,6 @@ func (err ErrNewIssueInsert) Error() string {
|
|||||||
return err.OriginalError.Error()
|
return err.OriginalError.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrIssueWasClosed is used when close a closed issue
|
|
||||||
type ErrIssueWasClosed struct {
|
|
||||||
ID int64
|
|
||||||
Index int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrIssueWasClosed checks if an error is a ErrIssueWasClosed.
|
|
||||||
func IsErrIssueWasClosed(err error) bool {
|
|
||||||
_, ok := err.(ErrIssueWasClosed)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrIssueWasClosed) Error() string {
|
|
||||||
return fmt.Sprintf("Issue [%d] %d was already closed", err.ID, err.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
var ErrIssueAlreadyChanged = util.NewInvalidArgumentErrorf("the issue is already changed")
|
var ErrIssueAlreadyChanged = util.NewInvalidArgumentErrorf("the issue is already changed")
|
||||||
|
|
||||||
// Issue represents an issue or pull request of repository.
|
// Issue represents an issue or pull request of repository.
|
||||||
|
@ -28,38 +28,40 @@ import (
|
|||||||
|
|
||||||
// UpdateIssueCols updates cols of issue
|
// UpdateIssueCols updates cols of issue
|
||||||
func UpdateIssueCols(ctx context.Context, issue *Issue, cols ...string) error {
|
func UpdateIssueCols(ctx context.Context, issue *Issue, cols ...string) error {
|
||||||
if _, err := db.GetEngine(ctx).ID(issue.ID).Cols(cols...).Update(issue); err != nil {
|
_, err := db.GetEngine(ctx).ID(issue.ID).Cols(cols...).Update(issue)
|
||||||
return err
|
return err
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isClosed, isMergePull bool) (*Comment, error) {
|
// ErrIssueIsClosed is used when close a closed issue
|
||||||
// Reload the issue
|
type ErrIssueIsClosed struct {
|
||||||
currentIssue, err := GetIssueByID(ctx, issue.ID)
|
ID int64
|
||||||
if err != nil {
|
RepoID int64
|
||||||
return nil, err
|
Index int64
|
||||||
}
|
IsPull bool
|
||||||
|
|
||||||
// Nothing should be performed if current status is same as target status
|
|
||||||
if currentIssue.IsClosed == isClosed {
|
|
||||||
if !issue.IsPull {
|
|
||||||
return nil, ErrIssueWasClosed{
|
|
||||||
ID: issue.ID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, ErrPullWasClosed{
|
|
||||||
ID: issue.ID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue.IsClosed = isClosed
|
|
||||||
return doChangeIssueStatus(ctx, issue, doer, isMergePull)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isMergePull bool) (*Comment, error) {
|
// IsErrIssueIsClosed checks if an error is a ErrIssueIsClosed.
|
||||||
|
func IsErrIssueIsClosed(err error) bool {
|
||||||
|
_, ok := err.(ErrIssueIsClosed)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrIssueIsClosed) Error() string {
|
||||||
|
return fmt.Sprintf("%s [id: %d, repo_id: %d, index: %d] is already closed", util.Iif(err.IsPull, "Pull Request", "Issue"), err.ID, err.RepoID, err.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetIssueAsClosed(ctx context.Context, issue *Issue, doer *user_model.User, isMergePull bool) (*Comment, error) {
|
||||||
|
if issue.IsClosed {
|
||||||
|
return nil, ErrIssueIsClosed{
|
||||||
|
ID: issue.ID,
|
||||||
|
RepoID: issue.RepoID,
|
||||||
|
Index: issue.Index,
|
||||||
|
IsPull: issue.IsPull,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for open dependencies
|
// Check for open dependencies
|
||||||
if issue.IsClosed && issue.Repo.IsDependenciesEnabled(ctx) {
|
if issue.Repo.IsDependenciesEnabled(ctx) {
|
||||||
// only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies
|
// only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies
|
||||||
noDeps, err := IssueNoDependenciesLeft(ctx, issue)
|
noDeps, err := IssueNoDependenciesLeft(ctx, issue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -71,16 +73,63 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.IsClosed {
|
issue.IsClosed = true
|
||||||
issue.ClosedUnix = timeutil.TimeStampNow()
|
issue.ClosedUnix = timeutil.TimeStampNow()
|
||||||
} else {
|
|
||||||
issue.ClosedUnix = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := UpdateIssueCols(ctx, issue, "is_closed", "closed_unix"); err != nil {
|
if cnt, err := db.GetEngine(ctx).ID(issue.ID).Cols("is_closed", "closed_unix").
|
||||||
|
Where("is_closed = ?", false).
|
||||||
|
Update(issue); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else if cnt != 1 {
|
||||||
|
return nil, ErrIssueAlreadyChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return updateIssueNumbers(ctx, issue, doer, util.Iif(isMergePull, CommentTypeMergePull, CommentTypeClose))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrIssueIsOpen is used when reopen an opened issue
|
||||||
|
type ErrIssueIsOpen struct {
|
||||||
|
ID int64
|
||||||
|
RepoID int64
|
||||||
|
IsPull bool
|
||||||
|
Index int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrIssueIsOpen checks if an error is a ErrIssueIsOpen.
|
||||||
|
func IsErrIssueIsOpen(err error) bool {
|
||||||
|
_, ok := err.(ErrIssueIsOpen)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrIssueIsOpen) Error() string {
|
||||||
|
return fmt.Sprintf("%s [id: %d, repo_id: %d, index: %d] is already open", util.Iif(err.IsPull, "Pull Request", "Issue"), err.ID, err.RepoID, err.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIssueAsReopen(ctx context.Context, issue *Issue, doer *user_model.User) (*Comment, error) {
|
||||||
|
if !issue.IsClosed {
|
||||||
|
return nil, ErrIssueIsOpen{
|
||||||
|
ID: issue.ID,
|
||||||
|
RepoID: issue.RepoID,
|
||||||
|
Index: issue.Index,
|
||||||
|
IsPull: issue.IsPull,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue.IsClosed = false
|
||||||
|
issue.ClosedUnix = 0
|
||||||
|
|
||||||
|
if cnt, err := db.GetEngine(ctx).ID(issue.ID).Cols("is_closed", "closed_unix").
|
||||||
|
Where("is_closed = ?", true).
|
||||||
|
Update(issue); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if cnt != 1 {
|
||||||
|
return nil, ErrIssueAlreadyChanged
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateIssueNumbers(ctx, issue, doer, CommentTypeReopen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateIssueNumbers(ctx context.Context, issue *Issue, doer *user_model.User, cmtType CommentType) (*Comment, error) {
|
||||||
// Update issue count of labels
|
// Update issue count of labels
|
||||||
if err := issue.LoadLabels(ctx); err != nil {
|
if err := issue.LoadLabels(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -103,14 +152,6 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// New action comment
|
|
||||||
cmtType := CommentTypeClose
|
|
||||||
if !issue.IsClosed {
|
|
||||||
cmtType = CommentTypeReopen
|
|
||||||
} else if isMergePull {
|
|
||||||
cmtType = CommentTypeMergePull
|
|
||||||
}
|
|
||||||
|
|
||||||
return CreateComment(ctx, &CreateCommentOptions{
|
return CreateComment(ctx, &CreateCommentOptions{
|
||||||
Type: cmtType,
|
Type: cmtType,
|
||||||
Doer: doer,
|
Doer: doer,
|
||||||
@ -134,7 +175,7 @@ func CloseIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Comm
|
|||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
comment, err := ChangeIssueStatus(ctx, issue, doer, true, false)
|
comment, err := SetIssueAsClosed(ctx, issue, doer, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -159,7 +200,7 @@ func ReopenIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Com
|
|||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
comment, err := ChangeIssueStatus(ctx, issue, doer, false, false)
|
comment, err := setIssueAsReopen(ctx, issue, doer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -80,22 +80,6 @@ func (err ErrPullRequestAlreadyExists) Unwrap() error {
|
|||||||
return util.ErrAlreadyExist
|
return util.ErrAlreadyExist
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrPullWasClosed is used close a closed pull request
|
|
||||||
type ErrPullWasClosed struct {
|
|
||||||
ID int64
|
|
||||||
Index int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrPullWasClosed checks if an error is a ErrErrPullWasClosed.
|
|
||||||
func IsErrPullWasClosed(err error) bool {
|
|
||||||
_, ok := err.(ErrPullWasClosed)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrPullWasClosed) Error() string {
|
|
||||||
return fmt.Sprintf("Pull request [%d] %d was already closed", err.ID, err.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PullRequestType defines pull request type
|
// PullRequestType defines pull request type
|
||||||
type PullRequestType int
|
type PullRequestType int
|
||||||
|
|
||||||
@ -301,7 +285,7 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
reviews, err := GetReviewsByIssueID(ctx, pr.Issue.ID)
|
reviews, _, err := GetReviewsByIssueID(ctx, pr.Issue.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -320,7 +304,7 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error {
|
|||||||
|
|
||||||
// LoadRequestedReviewersTeams loads the requested reviewers teams.
|
// LoadRequestedReviewersTeams loads the requested reviewers teams.
|
||||||
func (pr *PullRequest) LoadRequestedReviewersTeams(ctx context.Context) error {
|
func (pr *PullRequest) LoadRequestedReviewersTeams(ctx context.Context) error {
|
||||||
reviews, err := GetReviewsByIssueID(ctx, pr.Issue.ID)
|
reviews, _, err := GetReviewsByIssueID(ctx, pr.Issue.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -166,6 +166,23 @@ func (prs PullRequestList) getRepositoryIDs() []int64 {
|
|||||||
return repoIDs.Values()
|
return repoIDs.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (prs PullRequestList) SetBaseRepo(baseRepo *repo_model.Repository) {
|
||||||
|
for _, pr := range prs {
|
||||||
|
if pr.BaseRepo == nil {
|
||||||
|
pr.BaseRepo = baseRepo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (prs PullRequestList) SetHeadRepo(headRepo *repo_model.Repository) {
|
||||||
|
for _, pr := range prs {
|
||||||
|
if pr.HeadRepo == nil {
|
||||||
|
pr.HeadRepo = headRepo
|
||||||
|
pr.isHeadRepoLoaded = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (prs PullRequestList) LoadRepositories(ctx context.Context) error {
|
func (prs PullRequestList) LoadRepositories(ctx context.Context) error {
|
||||||
repoIDs := prs.getRepositoryIDs()
|
repoIDs := prs.getRepositoryIDs()
|
||||||
reposMap := make(map[int64]*repo_model.Repository, len(repoIDs))
|
reposMap := make(map[int64]*repo_model.Repository, len(repoIDs))
|
||||||
|
@ -5,6 +5,8 @@ package issues
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"slices"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
organization_model "code.gitea.io/gitea/models/organization"
|
organization_model "code.gitea.io/gitea/models/organization"
|
||||||
@ -153,43 +155,60 @@ func CountReviews(ctx context.Context, opts FindReviewOptions) (int64, error) {
|
|||||||
return db.GetEngine(ctx).Where(opts.toCond()).Count(&Review{})
|
return db.GetEngine(ctx).Where(opts.toCond()).Count(&Review{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request
|
|
||||||
func GetReviewersFromOriginalAuthorsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) {
|
|
||||||
reviews := make([]*Review, 0, 10)
|
|
||||||
|
|
||||||
// Get latest review of each reviewer, sorted in order they were made
|
|
||||||
if err := db.GetEngine(ctx).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id <> 0 GROUP BY issue_id, original_author_id) ORDER BY review.updated_unix ASC",
|
|
||||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest).
|
|
||||||
Find(&reviews); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return reviews, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
|
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
|
||||||
func GetReviewsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) {
|
// The first returned parameter is the latest review of each individual reviewer or team
|
||||||
|
// The second returned parameter is the latest review of each original author which is migrated from other systems
|
||||||
|
// The reviews are sorted by updated time
|
||||||
|
func GetReviewsByIssueID(ctx context.Context, issueID int64) (latestReviews, migratedOriginalReviews ReviewList, err error) {
|
||||||
reviews := make([]*Review, 0, 10)
|
reviews := make([]*Review, 0, 10)
|
||||||
|
|
||||||
sess := db.GetEngine(ctx)
|
// Get all reviews for the issue id
|
||||||
|
if err := db.GetEngine(ctx).Where("issue_id=?", issueID).OrderBy("updated_unix ASC").Find(&reviews); err != nil {
|
||||||
// Get latest review of each reviewer, sorted in order they were made
|
return nil, nil, err
|
||||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND dismissed = ? AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC",
|
|
||||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, false).
|
|
||||||
Find(&reviews); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filter them in memory to get the latest review of each reviewer
|
||||||
|
// Since the reviews should not be too many for one issue, less than 100 commonly, it's acceptable to do this in memory
|
||||||
|
// And since there are too less indexes in review table, it will be very slow to filter in the database
|
||||||
|
reviewersMap := make(map[int64][]*Review) // key is reviewer id
|
||||||
|
originalReviewersMap := make(map[int64][]*Review) // key is original author id
|
||||||
|
reviewTeamsMap := make(map[int64][]*Review) // key is reviewer team id
|
||||||
|
countedReivewTypes := []ReviewType{ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest}
|
||||||
|
for _, review := range reviews {
|
||||||
|
if review.ReviewerTeamID == 0 && slices.Contains(countedReivewTypes, review.Type) && !review.Dismissed {
|
||||||
|
if review.OriginalAuthorID != 0 {
|
||||||
|
originalReviewersMap[review.OriginalAuthorID] = append(originalReviewersMap[review.OriginalAuthorID], review)
|
||||||
|
} else {
|
||||||
|
reviewersMap[review.ReviewerID] = append(reviewersMap[review.ReviewerID], review)
|
||||||
|
}
|
||||||
|
} else if review.ReviewerTeamID != 0 && review.OriginalAuthorID == 0 {
|
||||||
|
reviewTeamsMap[review.ReviewerTeamID] = append(reviewTeamsMap[review.ReviewerTeamID], review)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
individualReviews := make([]*Review, 0, 10)
|
||||||
|
for _, reviews := range reviewersMap {
|
||||||
|
individualReviews = append(individualReviews, reviews[len(reviews)-1])
|
||||||
|
}
|
||||||
|
sort.Slice(individualReviews, func(i, j int) bool {
|
||||||
|
return individualReviews[i].UpdatedUnix < individualReviews[j].UpdatedUnix
|
||||||
|
})
|
||||||
|
|
||||||
|
originalReviews := make([]*Review, 0, 10)
|
||||||
|
for _, reviews := range originalReviewersMap {
|
||||||
|
originalReviews = append(originalReviews, reviews[len(reviews)-1])
|
||||||
|
}
|
||||||
|
sort.Slice(originalReviews, func(i, j int) bool {
|
||||||
|
return originalReviews[i].UpdatedUnix < originalReviews[j].UpdatedUnix
|
||||||
|
})
|
||||||
|
|
||||||
teamReviewRequests := make([]*Review, 0, 5)
|
teamReviewRequests := make([]*Review, 0, 5)
|
||||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id <> 0 AND original_author_id = 0 GROUP BY issue_id, reviewer_team_id) ORDER BY review.updated_unix ASC",
|
for _, reviews := range reviewTeamsMap {
|
||||||
issueID).
|
teamReviewRequests = append(teamReviewRequests, reviews[len(reviews)-1])
|
||||||
Find(&teamReviewRequests); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
sort.Slice(teamReviewRequests, func(i, j int) bool {
|
||||||
|
return teamReviewRequests[i].UpdatedUnix < teamReviewRequests[j].UpdatedUnix
|
||||||
|
})
|
||||||
|
|
||||||
if len(teamReviewRequests) > 0 {
|
return append(individualReviews, teamReviewRequests...), originalReviews, nil
|
||||||
reviews = append(reviews, teamReviewRequests...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return reviews, nil
|
|
||||||
}
|
}
|
||||||
|
@ -162,8 +162,9 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
allReviews, err := issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID)
|
allReviews, migratedReviews, err := issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, migratedReviews)
|
||||||
for _, review := range allReviews {
|
for _, review := range allReviews {
|
||||||
assert.NoError(t, review.LoadReviewer(db.DefaultContext))
|
assert.NoError(t, review.LoadReviewer(db.DefaultContext))
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/migrations/v1_21"
|
"code.gitea.io/gitea/models/migrations/v1_21"
|
||||||
"code.gitea.io/gitea/models/migrations/v1_22"
|
"code.gitea.io/gitea/models/migrations/v1_22"
|
||||||
"code.gitea.io/gitea/models/migrations/v1_23"
|
"code.gitea.io/gitea/models/migrations/v1_23"
|
||||||
|
"code.gitea.io/gitea/models/migrations/v1_24"
|
||||||
"code.gitea.io/gitea/models/migrations/v1_6"
|
"code.gitea.io/gitea/models/migrations/v1_6"
|
||||||
"code.gitea.io/gitea/models/migrations/v1_7"
|
"code.gitea.io/gitea/models/migrations/v1_7"
|
||||||
"code.gitea.io/gitea/models/migrations/v1_8"
|
"code.gitea.io/gitea/models/migrations/v1_8"
|
||||||
@ -369,6 +370,9 @@ func prepareMigrationTasks() []*migration {
|
|||||||
newMigration(309, "Improve Notification table indices", v1_23.ImproveNotificationTableIndices),
|
newMigration(309, "Improve Notification table indices", v1_23.ImproveNotificationTableIndices),
|
||||||
newMigration(310, "Add Priority to ProtectedBranch", v1_23.AddPriorityToProtectedBranch),
|
newMigration(310, "Add Priority to ProtectedBranch", v1_23.AddPriorityToProtectedBranch),
|
||||||
newMigration(311, "Add TimeEstimate to Issue table", v1_23.AddTimeEstimateColumnToIssueTable),
|
newMigration(311, "Add TimeEstimate to Issue table", v1_23.AddTimeEstimateColumnToIssueTable),
|
||||||
|
|
||||||
|
// Gitea 1.23.0-rc0 ends at migration ID number 311 (database version 312)
|
||||||
|
newMigration(312, "Add DeleteBranchAfterMerge to AutoMerge", v1_24.AddDeleteBranchAfterMergeForAutoMerge),
|
||||||
}
|
}
|
||||||
return preparedMigrations
|
return preparedMigrations
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) {
|
|||||||
return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err)
|
return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := giturl.Parse(remoteURL)
|
u, err := giturl.ParseGitURL(remoteURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
21
models/migrations/v1_24/v312.go
Normal file
21
models/migrations/v1_24/v312.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_24 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pullAutoMerge struct {
|
||||||
|
DeleteBranchAfterMerge bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// TableName return database table name for xorm
|
||||||
|
func (pullAutoMerge) TableName() string {
|
||||||
|
return "pull_auto_merge"
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddDeleteBranchAfterMergeForAutoMerge(x *xorm.Engine) error {
|
||||||
|
return x.Sync(new(pullAutoMerge))
|
||||||
|
}
|
@ -16,6 +16,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUser_IsOwnedBy(t *testing.T) {
|
func TestUser_IsOwnedBy(t *testing.T) {
|
||||||
@ -180,9 +181,8 @@ func TestRestrictedUserOrgMembers(t *testing.T) {
|
|||||||
ID: 29,
|
ID: 29,
|
||||||
IsRestricted: true,
|
IsRestricted: true,
|
||||||
})
|
})
|
||||||
if !assert.True(t, restrictedUser.IsRestricted) {
|
// ensure fixtures return restricted user
|
||||||
return // ensure fixtures return restricted user
|
require.True(t, restrictedUser.IsRestricted)
|
||||||
}
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -21,6 +21,7 @@ type AutoMerge struct {
|
|||||||
Doer *user_model.User `xorm:"-"`
|
Doer *user_model.User `xorm:"-"`
|
||||||
MergeStyle repo_model.MergeStyle `xorm:"varchar(30)"`
|
MergeStyle repo_model.MergeStyle `xorm:"varchar(30)"`
|
||||||
Message string `xorm:"LONGTEXT"`
|
Message string `xorm:"LONGTEXT"`
|
||||||
|
DeleteBranchAfterMerge bool
|
||||||
CreatedUnix timeutil.TimeStamp `xorm:"created"`
|
CreatedUnix timeutil.TimeStamp `xorm:"created"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ func IsErrAlreadyScheduledToAutoMerge(err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ScheduleAutoMerge schedules a pull request to be merged when all checks succeed
|
// ScheduleAutoMerge schedules a pull request to be merged when all checks succeed
|
||||||
func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pullID int64, style repo_model.MergeStyle, message string) error {
|
func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pullID int64, style repo_model.MergeStyle, message string, deleteBranchAfterMerge bool) error {
|
||||||
// Check if we already have a merge scheduled for that pull request
|
// Check if we already have a merge scheduled for that pull request
|
||||||
if exists, _, err := GetScheduledMergeByPullID(ctx, pullID); err != nil {
|
if exists, _, err := GetScheduledMergeByPullID(ctx, pullID); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -62,6 +63,7 @@ func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pullID int64,
|
|||||||
PullID: pullID,
|
PullID: pullID,
|
||||||
MergeStyle: style,
|
MergeStyle: style,
|
||||||
Message: message,
|
Message: message,
|
||||||
|
DeleteBranchAfterMerge: deleteBranchAfterMerge,
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
giturl "code.gitea.io/gitea/modules/git/url"
|
||||||
"code.gitea.io/gitea/modules/httplib"
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
@ -279,6 +280,8 @@ func (repo *Repository) IsBroken() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarkAsBrokenEmpty marks the repo as broken and empty
|
// MarkAsBrokenEmpty marks the repo as broken and empty
|
||||||
|
// FIXME: the status "broken" and "is_empty" were abused,
|
||||||
|
// The code always set them together, no way to distinguish whether a repo is really "empty" or "broken"
|
||||||
func (repo *Repository) MarkAsBrokenEmpty() {
|
func (repo *Repository) MarkAsBrokenEmpty() {
|
||||||
repo.Status = RepositoryBroken
|
repo.Status = RepositoryBroken
|
||||||
repo.IsEmpty = true
|
repo.IsEmpty = true
|
||||||
@ -635,14 +638,26 @@ type CloneLink struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
|
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
|
||||||
func ComposeHTTPSCloneURL(owner, repo string) string {
|
func ComposeHTTPSCloneURL(ctx context.Context, owner, repo string) string {
|
||||||
return fmt.Sprintf("%s%s/%s.git", setting.AppURL, url.PathEscape(owner), url.PathEscape(repo))
|
return fmt.Sprintf("%s%s/%s.git", httplib.GuessCurrentAppURL(ctx), url.PathEscape(owner), url.PathEscape(repo))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ComposeSSHCloneURL(ownerName, repoName string) string {
|
func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) string {
|
||||||
sshUser := setting.SSH.User
|
sshUser := setting.SSH.User
|
||||||
sshDomain := setting.SSH.Domain
|
sshDomain := setting.SSH.Domain
|
||||||
|
|
||||||
|
if sshUser == "(DOER_USERNAME)" {
|
||||||
|
// Some users use SSH reverse-proxy and need to use the current signed-in username as the SSH user
|
||||||
|
// to make the SSH reverse-proxy could prepare the user's public keys ahead.
|
||||||
|
// For most cases we have the correct "doer", then use it as the SSH user.
|
||||||
|
// If we can't get the doer, then use the built-in SSH user.
|
||||||
|
if doer != nil {
|
||||||
|
sshUser = doer.Name
|
||||||
|
} else {
|
||||||
|
sshUser = setting.SSH.BuiltinServerUser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// non-standard port, it must use full URI
|
// non-standard port, it must use full URI
|
||||||
if setting.SSH.Port != 22 {
|
if setting.SSH.Port != 22 {
|
||||||
sshHost := net.JoinHostPort(sshDomain, strconv.Itoa(setting.SSH.Port))
|
sshHost := net.JoinHostPort(sshDomain, strconv.Itoa(setting.SSH.Port))
|
||||||
@ -660,21 +675,20 @@ func ComposeSSHCloneURL(ownerName, repoName string) string {
|
|||||||
return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
|
return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
|
func (repo *Repository) cloneLink(ctx context.Context, doer *user_model.User, repoPathName string) *CloneLink {
|
||||||
repoName := repo.Name
|
|
||||||
if isWiki {
|
|
||||||
repoName += ".wiki"
|
|
||||||
}
|
|
||||||
|
|
||||||
cl := new(CloneLink)
|
cl := new(CloneLink)
|
||||||
cl.SSH = ComposeSSHCloneURL(repo.OwnerName, repoName)
|
cl.SSH = ComposeSSHCloneURL(doer, repo.OwnerName, repoPathName)
|
||||||
cl.HTTPS = ComposeHTTPSCloneURL(repo.OwnerName, repoName)
|
cl.HTTPS = ComposeHTTPSCloneURL(ctx, repo.OwnerName, repoPathName)
|
||||||
return cl
|
return cl
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloneLink returns clone URLs of repository.
|
// CloneLink returns clone URLs of repository.
|
||||||
func (repo *Repository) CloneLink() (cl *CloneLink) {
|
func (repo *Repository) CloneLink(ctx context.Context, doer *user_model.User) (cl *CloneLink) {
|
||||||
return repo.cloneLink(false)
|
return repo.cloneLink(ctx, doer, repo.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *Repository) CloneLinkGeneral(ctx context.Context) (cl *CloneLink) {
|
||||||
|
return repo.cloneLink(ctx, nil /* no doer, use a general git user */, repo.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOriginalURLHostname returns the hostname of a URL or the URL
|
// GetOriginalURLHostname returns the hostname of a URL or the URL
|
||||||
@ -770,47 +784,25 @@ func GetRepositoryByName(ctx context.Context, ownerID int64, name string) (*Repo
|
|||||||
return &repo, err
|
return &repo, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRepositoryURLPathSegments returns segments (owner, reponame) extracted from a url
|
|
||||||
func getRepositoryURLPathSegments(repoURL string) []string {
|
|
||||||
if strings.HasPrefix(repoURL, setting.AppURL) {
|
|
||||||
return strings.Split(strings.TrimPrefix(repoURL, setting.AppURL), "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
sshURLVariants := [4]string{
|
|
||||||
setting.SSH.Domain + ":",
|
|
||||||
setting.SSH.User + "@" + setting.SSH.Domain + ":",
|
|
||||||
"git+ssh://" + setting.SSH.Domain + "/",
|
|
||||||
"git+ssh://" + setting.SSH.User + "@" + setting.SSH.Domain + "/",
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, sshURL := range sshURLVariants {
|
|
||||||
if strings.HasPrefix(repoURL, sshURL) {
|
|
||||||
return strings.Split(strings.TrimPrefix(repoURL, sshURL), "/")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRepositoryByURL returns the repository by given url
|
// GetRepositoryByURL returns the repository by given url
|
||||||
func GetRepositoryByURL(ctx context.Context, repoURL string) (*Repository, error) {
|
func GetRepositoryByURL(ctx context.Context, repoURL string) (*Repository, error) {
|
||||||
// possible urls for git:
|
ret, err := giturl.ParseRepositoryURL(ctx, repoURL)
|
||||||
// https://my.domain/sub-path/<owner>/<repo>.git
|
if err != nil || ret.OwnerName == "" {
|
||||||
// https://my.domain/sub-path/<owner>/<repo>
|
|
||||||
// git+ssh://user@my.domain/<owner>/<repo>.git
|
|
||||||
// git+ssh://user@my.domain/<owner>/<repo>
|
|
||||||
// user@my.domain:<owner>/<repo>.git
|
|
||||||
// user@my.domain:<owner>/<repo>
|
|
||||||
|
|
||||||
pathSegments := getRepositoryURLPathSegments(repoURL)
|
|
||||||
|
|
||||||
if len(pathSegments) != 2 {
|
|
||||||
return nil, fmt.Errorf("unknown or malformed repository URL")
|
return nil, fmt.Errorf("unknown or malformed repository URL")
|
||||||
}
|
}
|
||||||
|
return GetRepositoryByOwnerAndName(ctx, ret.OwnerName, ret.RepoName)
|
||||||
|
}
|
||||||
|
|
||||||
ownerName := pathSegments[0]
|
// GetRepositoryByURLRelax also accepts an SSH clone URL without user part
|
||||||
repoName := strings.TrimSuffix(pathSegments[1], ".git")
|
func GetRepositoryByURLRelax(ctx context.Context, repoURL string) (*Repository, error) {
|
||||||
return GetRepositoryByOwnerAndName(ctx, ownerName, repoName)
|
if !strings.Contains(repoURL, "://") && !strings.Contains(repoURL, "@") {
|
||||||
|
// convert "example.com:owner/repo" to "@example.com:owner/repo"
|
||||||
|
p1, p2, p3 := strings.Index(repoURL, "."), strings.Index(repoURL, ":"), strings.Index(repoURL, "/")
|
||||||
|
if 0 < p1 && p1 < p2 && p2 < p3 {
|
||||||
|
repoURL = "@" + repoURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GetRepositoryByURL(ctx, repoURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepositoryByID returns the repository by given id if exists.
|
// GetRepositoryByID returns the repository by given id if exists.
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/test"
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -132,60 +133,43 @@ func TestGetRepositoryByURL(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("InvalidPath", func(t *testing.T) {
|
t.Run("InvalidPath", func(t *testing.T) {
|
||||||
repo, err := GetRepositoryByURL(db.DefaultContext, "something")
|
repo, err := GetRepositoryByURL(db.DefaultContext, "something")
|
||||||
|
|
||||||
assert.Nil(t, repo)
|
assert.Nil(t, repo)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ValidHttpURL", func(t *testing.T) {
|
testRepo2 := func(t *testing.T, url string) {
|
||||||
test := func(t *testing.T, url string) {
|
|
||||||
repo, err := GetRepositoryByURL(db.DefaultContext, url)
|
repo, err := GetRepositoryByURL(db.DefaultContext, url)
|
||||||
|
require.NoError(t, err)
|
||||||
assert.NotNil(t, repo)
|
assert.EqualValues(t, 2, repo.ID)
|
||||||
assert.NoError(t, err)
|
assert.EqualValues(t, 2, repo.OwnerID)
|
||||||
|
|
||||||
assert.Equal(t, int64(2), repo.ID)
|
|
||||||
assert.Equal(t, int64(2), repo.OwnerID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test(t, "https://try.gitea.io/user2/repo2")
|
t.Run("ValidHttpURL", func(t *testing.T) {
|
||||||
test(t, "https://try.gitea.io/user2/repo2.git")
|
testRepo2(t, "https://try.gitea.io/user2/repo2")
|
||||||
|
testRepo2(t, "https://try.gitea.io/user2/repo2.git")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ValidGitSshURL", func(t *testing.T) {
|
t.Run("ValidGitSshURL", func(t *testing.T) {
|
||||||
test := func(t *testing.T, url string) {
|
testRepo2(t, "git+ssh://sshuser@try.gitea.io/user2/repo2")
|
||||||
repo, err := GetRepositoryByURL(db.DefaultContext, url)
|
testRepo2(t, "git+ssh://sshuser@try.gitea.io/user2/repo2.git")
|
||||||
|
|
||||||
assert.NotNil(t, repo)
|
testRepo2(t, "git+ssh://try.gitea.io/user2/repo2")
|
||||||
assert.NoError(t, err)
|
testRepo2(t, "git+ssh://try.gitea.io/user2/repo2.git")
|
||||||
|
|
||||||
assert.Equal(t, int64(2), repo.ID)
|
|
||||||
assert.Equal(t, int64(2), repo.OwnerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
test(t, "git+ssh://sshuser@try.gitea.io/user2/repo2")
|
|
||||||
test(t, "git+ssh://sshuser@try.gitea.io/user2/repo2.git")
|
|
||||||
|
|
||||||
test(t, "git+ssh://try.gitea.io/user2/repo2")
|
|
||||||
test(t, "git+ssh://try.gitea.io/user2/repo2.git")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ValidImplicitSshURL", func(t *testing.T) {
|
t.Run("ValidImplicitSshURL", func(t *testing.T) {
|
||||||
test := func(t *testing.T, url string) {
|
testRepo2(t, "sshuser@try.gitea.io:user2/repo2")
|
||||||
repo, err := GetRepositoryByURL(db.DefaultContext, url)
|
testRepo2(t, "sshuser@try.gitea.io:user2/repo2.git")
|
||||||
|
|
||||||
assert.NotNil(t, repo)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
|
testRelax := func(t *testing.T, url string) {
|
||||||
|
repo, err := GetRepositoryByURLRelax(db.DefaultContext, url)
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, int64(2), repo.ID)
|
assert.Equal(t, int64(2), repo.ID)
|
||||||
assert.Equal(t, int64(2), repo.OwnerID)
|
assert.Equal(t, int64(2), repo.OwnerID)
|
||||||
}
|
}
|
||||||
|
// TODO: it doesn't seem to be common git ssh URL, should we really support this?
|
||||||
test(t, "sshuser@try.gitea.io:user2/repo2")
|
testRelax(t, "try.gitea.io:user2/repo2")
|
||||||
test(t, "sshuser@try.gitea.io:user2/repo2.git")
|
testRelax(t, "try.gitea.io:user2/repo2.git")
|
||||||
|
|
||||||
test(t, "try.gitea.io:user2/repo2")
|
|
||||||
test(t, "try.gitea.io:user2/repo2.git")
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,23 +183,30 @@ func TestComposeSSHCloneURL(t *testing.T) {
|
|||||||
setting.SSH.Domain = "domain"
|
setting.SSH.Domain = "domain"
|
||||||
setting.SSH.Port = 22
|
setting.SSH.Port = 22
|
||||||
setting.Repository.UseCompatSSHURI = false
|
setting.Repository.UseCompatSSHURI = false
|
||||||
assert.Equal(t, "git@domain:user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
assert.Equal(t, "git@domain:user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
|
||||||
setting.Repository.UseCompatSSHURI = true
|
setting.Repository.UseCompatSSHURI = true
|
||||||
assert.Equal(t, "ssh://git@domain/user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
assert.Equal(t, "ssh://git@domain/user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
|
||||||
// test SSH_DOMAIN while use non-standard SSH port
|
// test SSH_DOMAIN while use non-standard SSH port
|
||||||
setting.SSH.Port = 123
|
setting.SSH.Port = 123
|
||||||
setting.Repository.UseCompatSSHURI = false
|
setting.Repository.UseCompatSSHURI = false
|
||||||
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
|
||||||
setting.Repository.UseCompatSSHURI = true
|
setting.Repository.UseCompatSSHURI = true
|
||||||
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
|
||||||
|
|
||||||
// test IPv6 SSH_DOMAIN
|
// test IPv6 SSH_DOMAIN
|
||||||
setting.Repository.UseCompatSSHURI = false
|
setting.Repository.UseCompatSSHURI = false
|
||||||
setting.SSH.Domain = "::1"
|
setting.SSH.Domain = "::1"
|
||||||
setting.SSH.Port = 22
|
setting.SSH.Port = 22
|
||||||
assert.Equal(t, "git@[::1]:user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
assert.Equal(t, "git@[::1]:user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
|
||||||
setting.SSH.Port = 123
|
setting.SSH.Port = 123
|
||||||
assert.Equal(t, "ssh://git@[::1]:123/user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
assert.Equal(t, "ssh://git@[::1]:123/user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
|
||||||
|
|
||||||
|
setting.SSH.User = "(DOER_USERNAME)"
|
||||||
|
setting.SSH.Domain = "domain"
|
||||||
|
setting.SSH.Port = 22
|
||||||
|
assert.Equal(t, "doer@domain:user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
|
||||||
|
setting.SSH.Port = 123
|
||||||
|
assert.Equal(t, "ssh://doer@domain:123/user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsUsableRepoName(t *testing.T) {
|
func TestIsUsableRepoName(t *testing.T) {
|
||||||
|
@ -46,6 +46,12 @@ func UpdateRepositoryCols(ctx context.Context, repo *Repository, cols ...string)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateRepositoryColsNoAutoTime updates repository's columns and but applies time change automatically
|
||||||
|
func UpdateRepositoryColsNoAutoTime(ctx context.Context, repo *Repository, cols ...string) error {
|
||||||
|
_, err := db.GetEngine(ctx).ID(repo.ID).Cols(cols...).NoAutoTime().Update(repo)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// ErrReachLimitOfRepo represents a "ReachLimitOfRepo" kind of error.
|
// ErrReachLimitOfRepo represents a "ReachLimitOfRepo" kind of error.
|
||||||
type ErrReachLimitOfRepo struct {
|
type ErrReachLimitOfRepo struct {
|
||||||
Limit int
|
Limit int
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@ -72,8 +73,8 @@ func (err ErrWikiInvalidFileName) Unwrap() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WikiCloneLink returns clone URLs of repository wiki.
|
// WikiCloneLink returns clone URLs of repository wiki.
|
||||||
func (repo *Repository) WikiCloneLink() *CloneLink {
|
func (repo *Repository) WikiCloneLink(ctx context.Context, doer *user_model.User) *CloneLink {
|
||||||
return repo.cloneLink(true)
|
return repo.cloneLink(ctx, doer, repo.Name+".wiki")
|
||||||
}
|
}
|
||||||
|
|
||||||
// WikiPath returns wiki data path by given user and repository name.
|
// WikiPath returns wiki data path by given user and repository name.
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
package repo_test
|
package repo_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ func TestRepository_WikiCloneLink(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
cloneLink := repo.WikiCloneLink()
|
cloneLink := repo.WikiCloneLink(context.Background(), nil)
|
||||||
assert.Equal(t, "ssh://sshuser@try.gitea.io:3000/user2/repo1.wiki.git", cloneLink.SSH)
|
assert.Equal(t, "ssh://sshuser@try.gitea.io:3000/user2/repo1.wiki.git", cloneLink.SSH)
|
||||||
assert.Equal(t, "https://try.gitea.io/user2/repo1.wiki.git", cloneLink.HTTPS)
|
assert.Equal(t, "https://try.gitea.io/user2/repo1.wiki.git", cloneLink.HTTPS)
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,7 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
|
|||||||
|
|
||||||
setting.IsInTesting = true
|
setting.IsInTesting = true
|
||||||
setting.AppURL = "https://try.gitea.io/"
|
setting.AppURL = "https://try.gitea.io/"
|
||||||
|
setting.Domain = "try.gitea.io"
|
||||||
setting.RunUser = "runuser"
|
setting.RunUser = "runuser"
|
||||||
setting.SSH.User = "sshuser"
|
setting.SSH.User = "sshuser"
|
||||||
setting.SSH.BuiltinServerUser = "builtinuser"
|
setting.SSH.BuiltinServerUser = "builtinuser"
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetUserOpenIDs(t *testing.T) {
|
func TestGetUserOpenIDs(t *testing.T) {
|
||||||
@ -34,30 +35,23 @@ func TestGetUserOpenIDs(t *testing.T) {
|
|||||||
func TestToggleUserOpenIDVisibility(t *testing.T) {
|
func TestToggleUserOpenIDVisibility(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
oids, err := user_model.GetUserOpenIDs(db.DefaultContext, int64(2))
|
oids, err := user_model.GetUserOpenIDs(db.DefaultContext, int64(2))
|
||||||
if !assert.NoError(t, err) || !assert.Len(t, oids, 1) {
|
require.NoError(t, err)
|
||||||
return
|
require.Len(t, oids, 1)
|
||||||
}
|
|
||||||
assert.True(t, oids[0].Show)
|
assert.True(t, oids[0].Show)
|
||||||
|
|
||||||
err = user_model.ToggleUserOpenIDVisibility(db.DefaultContext, oids[0].ID)
|
err = user_model.ToggleUserOpenIDVisibility(db.DefaultContext, oids[0].ID)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
oids, err = user_model.GetUserOpenIDs(db.DefaultContext, int64(2))
|
oids, err = user_model.GetUserOpenIDs(db.DefaultContext, int64(2))
|
||||||
if !assert.NoError(t, err) || !assert.Len(t, oids, 1) {
|
require.NoError(t, err)
|
||||||
return
|
require.Len(t, oids, 1)
|
||||||
}
|
|
||||||
assert.False(t, oids[0].Show)
|
assert.False(t, oids[0].Show)
|
||||||
err = user_model.ToggleUserOpenIDVisibility(db.DefaultContext, oids[0].ID)
|
err = user_model.ToggleUserOpenIDVisibility(db.DefaultContext, oids[0].ID)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
oids, err = user_model.GetUserOpenIDs(db.DefaultContext, int64(2))
|
oids, err = user_model.GetUserOpenIDs(db.DefaultContext, int64(2))
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
if assert.Len(t, oids, 1) {
|
if assert.Len(t, oids, 1) {
|
||||||
assert.True(t, oids[0].Show)
|
assert.True(t, oids[0].Show)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
|
|
||||||
package analyze
|
package analyze
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
func TestIsVendor(t *testing.T) {
|
func TestIsVendor(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -33,9 +37,8 @@ func TestIsVendor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.path, func(t *testing.T) {
|
t.Run(tt.path, func(t *testing.T) {
|
||||||
if got := IsVendor(tt.path); got != tt.want {
|
got := IsVendor(tt.path)
|
||||||
t.Errorf("IsVendor() = %v, want %v", got, tt.want)
|
assert.Equal(t, tt.want, got)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ package openid
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testDiscoveredInfo struct{}
|
type testDiscoveredInfo struct{}
|
||||||
@ -29,21 +32,17 @@ func TestTimedDiscoveryCache(t *testing.T) {
|
|||||||
dc.Put("foo", &testDiscoveredInfo{}) // openid.opEndpoint: "a", openid.opLocalID: "b", openid.claimedID: "c"})
|
dc.Put("foo", &testDiscoveredInfo{}) // openid.opEndpoint: "a", openid.opLocalID: "b", openid.claimedID: "c"})
|
||||||
|
|
||||||
// Make sure we can retrieve them
|
// Make sure we can retrieve them
|
||||||
if di := dc.Get("foo"); di == nil {
|
di := dc.Get("foo")
|
||||||
t.Errorf("Expected a result, got nil")
|
require.NotNil(t, di)
|
||||||
} else if di.OpEndpoint() != "opEndpoint" || di.OpLocalID() != "opLocalID" || di.ClaimedID() != "claimedID" {
|
assert.Equal(t, "opEndpoint", di.OpEndpoint())
|
||||||
t.Errorf("Expected opEndpoint opLocalID claimedID, got %v %v %v", di.OpEndpoint(), di.OpLocalID(), di.ClaimedID())
|
assert.Equal(t, "opLocalID", di.OpLocalID())
|
||||||
}
|
assert.Equal(t, "claimedID", di.ClaimedID())
|
||||||
|
|
||||||
// Attempt to get a non-existent value
|
// Attempt to get a non-existent value
|
||||||
if di := dc.Get("bar"); di != nil {
|
assert.Nil(t, dc.Get("bar"))
|
||||||
t.Errorf("Expected nil, got %v", di)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sleep one second and try retrieve again
|
// Sleep one second and try retrieve again
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
if di := dc.Get("foo"); di != nil {
|
assert.Nil(t, dc.Get("foo"))
|
||||||
t.Errorf("Expected a nil, got a result")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -15,5 +15,5 @@ func TestPamAuth(t *testing.T) {
|
|||||||
result, err := Auth("gitea", "user1", "false-pwd")
|
result, err := Auth("gitea", "user1", "false-pwd")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.EqualError(t, err, "Authentication failure")
|
assert.EqualError(t, err, "Authentication failure")
|
||||||
assert.Len(t, result)
|
assert.Empty(t, result)
|
||||||
}
|
}
|
||||||
|
@ -4,46 +4,57 @@
|
|||||||
package pwn
|
package pwn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/h2non/gock"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
var client = New(WithHTTP(&http.Client{
|
type mockTransport struct{}
|
||||||
Timeout: time.Second * 2,
|
|
||||||
}))
|
func (mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
if req.URL.Host != "api.pwnedpasswords.com" {
|
||||||
|
return nil, errors.New("unsupported host")
|
||||||
|
}
|
||||||
|
respMap := map[string]string{
|
||||||
|
"/range/5c1d8": "EAF2F254732680E8AC339B84F3266ECCBB5:1\r\nFC446EB88938834178CB9322C1EE273C2A7:2",
|
||||||
|
"/range/ba189": "FD4CB34F0378BCB15D23F6FFD28F0775C9E:3\r\nFDF342FCD8C3611DAE4D76E8A992A3E4169:4",
|
||||||
|
"/range/a1733": "C4CE0F1F0062B27B9E2F41AF0C08218017C:1\r\nFC446EB88938834178CB9322C1EE273C2A7:2\r\nFE81480327C992FE62065A827429DD1318B:0",
|
||||||
|
"/range/5617b": "FD4CB34F0378BCB15D23F6FFD28F0775C9E:3\r\nFDF342FCD8C3611DAE4D76E8A992A3E4169:4\r\nFE81480327C992FE62065A827429DD1318B:0",
|
||||||
|
"/range/79082": "FDF342FCD8C3611DAE4D76E8A992A3E4169:4\r\nFE81480327C992FE62065A827429DD1318B:0\r\nAFEF386F56EB0B4BE314E07696E5E6E6536:0",
|
||||||
|
}
|
||||||
|
if resp, ok := respMap[req.URL.Path]; ok {
|
||||||
|
return &http.Response{Request: req, Body: io.NopCloser(strings.NewReader(resp))}, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("unsupported path")
|
||||||
|
}
|
||||||
|
|
||||||
func TestPassword(t *testing.T) {
|
func TestPassword(t *testing.T) {
|
||||||
defer gock.Off()
|
client := New(WithHTTP(&http.Client{Transport: mockTransport{}}))
|
||||||
|
|
||||||
count, err := client.CheckPassword("", false)
|
count, err := client.CheckPassword("", false)
|
||||||
assert.ErrorIs(t, err, ErrEmptyPassword, "blank input should return ErrEmptyPassword")
|
assert.ErrorIs(t, err, ErrEmptyPassword, "blank input should return ErrEmptyPassword")
|
||||||
assert.Equal(t, -1, count)
|
assert.Equal(t, -1, count)
|
||||||
|
|
||||||
gock.New("https://api.pwnedpasswords.com").Get("/range/5c1d8").Times(1).Reply(200).BodyString("EAF2F254732680E8AC339B84F3266ECCBB5:1\r\nFC446EB88938834178CB9322C1EE273C2A7:2")
|
|
||||||
count, err = client.CheckPassword("pwned", false)
|
count, err = client.CheckPassword("pwned", false)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, count)
|
assert.Equal(t, 1, count)
|
||||||
|
|
||||||
gock.New("https://api.pwnedpasswords.com").Get("/range/ba189").Times(1).Reply(200).BodyString("FD4CB34F0378BCB15D23F6FFD28F0775C9E:3\r\nFDF342FCD8C3611DAE4D76E8A992A3E4169:4")
|
|
||||||
count, err = client.CheckPassword("notpwned", false)
|
count, err = client.CheckPassword("notpwned", false)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 0, count)
|
assert.Equal(t, 0, count)
|
||||||
|
|
||||||
gock.New("https://api.pwnedpasswords.com").Get("/range/a1733").Times(1).Reply(200).BodyString("C4CE0F1F0062B27B9E2F41AF0C08218017C:1\r\nFC446EB88938834178CB9322C1EE273C2A7:2\r\nFE81480327C992FE62065A827429DD1318B:0")
|
|
||||||
count, err = client.CheckPassword("paddedpwned", true)
|
count, err = client.CheckPassword("paddedpwned", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, count)
|
assert.Equal(t, 1, count)
|
||||||
|
|
||||||
gock.New("https://api.pwnedpasswords.com").Get("/range/5617b").Times(1).Reply(200).BodyString("FD4CB34F0378BCB15D23F6FFD28F0775C9E:3\r\nFDF342FCD8C3611DAE4D76E8A992A3E4169:4\r\nFE81480327C992FE62065A827429DD1318B:0")
|
|
||||||
count, err = client.CheckPassword("paddednotpwned", true)
|
count, err = client.CheckPassword("paddednotpwned", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 0, count)
|
assert.Equal(t, 0, count)
|
||||||
|
|
||||||
gock.New("https://api.pwnedpasswords.com").Get("/range/79082").Times(1).Reply(200).BodyString("FDF342FCD8C3611DAE4D76E8A992A3E4169:4\r\nFE81480327C992FE62065A827429DD1318B:0\r\nAFEF386F56EB0B4BE314E07696E5E6E6536:0")
|
|
||||||
count, err = client.CheckPassword("paddednotpwnedzero", true)
|
count, err = client.CheckPassword("paddednotpwnedzero", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 0, count)
|
assert.Equal(t, 0, count)
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package emoji
|
package emoji
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -22,32 +21,18 @@ func TestLookup(t *testing.T) {
|
|||||||
c := FromAlias(":beer:")
|
c := FromAlias(":beer:")
|
||||||
d := FromAlias("beer")
|
d := FromAlias("beer")
|
||||||
|
|
||||||
if !reflect.DeepEqual(a, b) {
|
assert.Equal(t, a, b)
|
||||||
t.Errorf("a and b should equal")
|
assert.Equal(t, b, c)
|
||||||
}
|
assert.Equal(t, c, d)
|
||||||
if !reflect.DeepEqual(b, c) {
|
assert.Equal(t, a, d)
|
||||||
t.Errorf("b and c should equal")
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(c, d) {
|
|
||||||
t.Errorf("c and d should equal")
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(a, d) {
|
|
||||||
t.Errorf("a and d should equal")
|
|
||||||
}
|
|
||||||
|
|
||||||
m := FromCode("\U0001f44d")
|
m := FromCode("\U0001f44d")
|
||||||
n := FromAlias(":thumbsup:")
|
n := FromAlias(":thumbsup:")
|
||||||
o := FromAlias("+1")
|
o := FromAlias("+1")
|
||||||
|
|
||||||
if !reflect.DeepEqual(m, n) {
|
assert.Equal(t, m, n)
|
||||||
t.Errorf("m and n should equal")
|
assert.Equal(t, m, o)
|
||||||
}
|
assert.Equal(t, n, o)
|
||||||
if !reflect.DeepEqual(n, o) {
|
|
||||||
t.Errorf("n and o should equal")
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(m, o) {
|
|
||||||
t.Errorf("m and o should equal")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReplacers(t *testing.T) {
|
func TestReplacers(t *testing.T) {
|
||||||
@ -61,9 +46,7 @@ func TestReplacers(t *testing.T) {
|
|||||||
|
|
||||||
for i, x := range tests {
|
for i, x := range tests {
|
||||||
s := x.f(x.v)
|
s := x.f(x.v)
|
||||||
if s != x.exp {
|
assert.Equalf(t, x.exp, s, "test %d `%s` expected `%s`, got: `%s`", i, x.v, x.exp, s)
|
||||||
t.Errorf("test %d `%s` expected `%s`, got: `%s`", i, x.v, x.exp, s)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ package eventsource
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_wrapNewlines(t *testing.T) {
|
func Test_wrapNewlines(t *testing.T) {
|
||||||
@ -38,16 +41,10 @@ func Test_wrapNewlines(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
w := &bytes.Buffer{}
|
w := &bytes.Buffer{}
|
||||||
gotSum, err := wrapNewlines(w, []byte(tt.prefix), []byte(tt.value))
|
gotSum, err := wrapNewlines(w, []byte(tt.prefix), []byte(tt.value))
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
t.Errorf("wrapNewlines() error = %v", err)
|
|
||||||
return
|
assert.EqualValues(t, len(tt.output), gotSum)
|
||||||
}
|
assert.Equal(t, tt.output, w.String())
|
||||||
if gotSum != int64(len(tt.output)) {
|
|
||||||
t.Errorf("wrapNewlines() = %v, want %v", gotSum, int64(len(tt.output)))
|
|
||||||
}
|
|
||||||
if gotW := w.String(); gotW != tt.output {
|
|
||||||
t.Errorf("wrapNewlines() = %v, want %v", gotW, tt.output)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,7 @@ func TestBlob_Data(t *testing.T) {
|
|||||||
output := "file2\n"
|
output := "file2\n"
|
||||||
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
|
||||||
repo, err := openRepositoryWithDefaultContext(bareRepo1Path)
|
repo, err := openRepositoryWithDefaultContext(bareRepo1Path)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
defer repo.Close()
|
defer repo.Close()
|
||||||
|
|
||||||
testBlob, err := repo.GetBlob("6c493ff740f9380390d5c9ddef4af18697ac9375")
|
testBlob, err := repo.GetBlob("6c493ff740f9380390d5c9ddef4af18697ac9375")
|
||||||
|
@ -7,5 +7,5 @@ package git
|
|||||||
type CommitInfo struct {
|
type CommitInfo struct {
|
||||||
Entry *TreeEntry
|
Entry *TreeEntry
|
||||||
Commit *Commit
|
Commit *Commit
|
||||||
SubModuleFile *CommitSubModuleFile
|
SubmoduleFile *CommitSubmoduleFile
|
||||||
}
|
}
|
||||||
|
@ -85,8 +85,8 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
|
|||||||
} else if subModule != nil {
|
} else if subModule != nil {
|
||||||
subModuleURL = subModule.URL
|
subModuleURL = subModule.URL
|
||||||
}
|
}
|
||||||
subModuleFile := NewCommitSubModuleFile(subModuleURL, entry.ID.String())
|
subModuleFile := NewCommitSubmoduleFile(subModuleURL, entry.ID.String())
|
||||||
commitsInfo[i].SubModuleFile = subModuleFile
|
commitsInfo[i].SubmoduleFile = subModuleFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,8 +79,8 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
|
|||||||
} else if subModule != nil {
|
} else if subModule != nil {
|
||||||
subModuleURL = subModule.URL
|
subModuleURL = subModule.URL
|
||||||
}
|
}
|
||||||
subModuleFile := NewCommitSubModuleFile(subModuleURL, entry.ID.String())
|
subModuleFile := NewCommitSubmoduleFile(subModuleURL, entry.ID.String())
|
||||||
commitsInfo[i].SubModuleFile = subModuleFile
|
commitsInfo[i].SubmoduleFile = subModuleFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommitsCountSha256(t *testing.T) {
|
func TestCommitsCountSha256(t *testing.T) {
|
||||||
@ -94,9 +95,7 @@ signed commit`
|
|||||||
|
|
||||||
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
|
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if !assert.NotNil(t, commitFromReader) {
|
require.NotNil(t, commitFromReader)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.EqualValues(t, sha, commitFromReader.ID)
|
assert.EqualValues(t, sha, commitFromReader.ID)
|
||||||
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
|
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
package git
|
package git
|
||||||
|
|
||||||
|
type SubmoduleWebLink struct {
|
||||||
|
RepoWebLink, CommitWebLink string
|
||||||
|
}
|
||||||
|
|
||||||
// GetSubModules get all the submodules of current revision git tree
|
// GetSubModules get all the submodules of current revision git tree
|
||||||
func (c *Commit) GetSubModules() (*ObjectCache[*SubModule], error) {
|
func (c *Commit) GetSubModules() (*ObjectCache[*SubModule], error) {
|
||||||
if c.submoduleCache != nil {
|
if c.submoduleCache != nil {
|
||||||
|
@ -5,107 +5,50 @@
|
|||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"context"
|
||||||
"net"
|
|
||||||
"net/url"
|
giturl "code.gitea.io/gitea/modules/git/url"
|
||||||
"path"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var scpSyntax = regexp.MustCompile(`^([a-zA-Z0-9_]+@)?([a-zA-Z0-9._-]+):(.*)$`)
|
// CommitSubmoduleFile represents a file with submodule type.
|
||||||
|
type CommitSubmoduleFile struct {
|
||||||
// CommitSubModuleFile represents a file with submodule type.
|
|
||||||
type CommitSubModuleFile struct {
|
|
||||||
refURL string
|
refURL string
|
||||||
|
parsedURL *giturl.RepositoryURL
|
||||||
|
parsed bool
|
||||||
refID string
|
refID string
|
||||||
|
repoLink string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommitSubModuleFile create a new submodule file
|
// NewCommitSubmoduleFile create a new submodule file
|
||||||
func NewCommitSubModuleFile(refURL, refID string) *CommitSubModuleFile {
|
func NewCommitSubmoduleFile(refURL, refID string) *CommitSubmoduleFile {
|
||||||
return &CommitSubModuleFile{
|
return &CommitSubmoduleFile{refURL: refURL, refID: refID}
|
||||||
refURL: refURL,
|
|
||||||
refID: refID,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string {
|
func (sf *CommitSubmoduleFile) RefID() string {
|
||||||
if refURL == "" {
|
return sf.refID // this function is only used in templates
|
||||||
return ""
|
}
|
||||||
|
|
||||||
|
// SubmoduleWebLink tries to make some web links for a submodule, it also works on "nil" receiver
|
||||||
|
func (sf *CommitSubmoduleFile) SubmoduleWebLink(ctx context.Context, optCommitID ...string) *SubmoduleWebLink {
|
||||||
|
if sf == nil {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
if !sf.parsed {
|
||||||
refURI := strings.TrimSuffix(refURL, ".git")
|
sf.parsed = true
|
||||||
|
parsedURL, err := giturl.ParseRepositoryURL(ctx, sf.refURL)
|
||||||
prefixURL, _ := url.Parse(urlPrefix)
|
|
||||||
urlPrefixHostname, _, err := net.SplitHostPort(prefixURL.Host)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
urlPrefixHostname = prefixURL.Host
|
return nil
|
||||||
}
|
}
|
||||||
|
sf.parsedURL = parsedURL
|
||||||
urlPrefix = strings.TrimSuffix(urlPrefix, "/")
|
sf.repoLink = giturl.MakeRepositoryWebLink(sf.parsedURL)
|
||||||
|
|
||||||
// FIXME: Need to consider branch - which will require changes in modules/git/commit.go:GetSubModules
|
|
||||||
// Relative url prefix check (according to git submodule documentation)
|
|
||||||
if strings.HasPrefix(refURI, "./") || strings.HasPrefix(refURI, "../") {
|
|
||||||
return urlPrefix + path.Clean(path.Join("/", repoFullName, refURI))
|
|
||||||
}
|
}
|
||||||
|
var commitLink string
|
||||||
if !strings.Contains(refURI, "://") {
|
if len(optCommitID) == 2 {
|
||||||
// scp style syntax which contains *no* port number after the : (and is not parsed by net/url)
|
commitLink = sf.repoLink + "/compare/" + optCommitID[0] + "..." + optCommitID[1]
|
||||||
// ex: git@try.gitea.io:go-gitea/gitea
|
} else if len(optCommitID) == 1 {
|
||||||
match := scpSyntax.FindAllStringSubmatch(refURI, -1)
|
commitLink = sf.repoLink + "/commit/" + optCommitID[0]
|
||||||
if len(match) > 0 {
|
} else {
|
||||||
m := match[0]
|
commitLink = sf.repoLink + "/commit/" + sf.refID
|
||||||
refHostname := m[2]
|
|
||||||
pth := m[3]
|
|
||||||
|
|
||||||
if !strings.HasPrefix(pth, "/") {
|
|
||||||
pth = "/" + pth
|
|
||||||
}
|
}
|
||||||
|
return &SubmoduleWebLink{RepoWebLink: sf.repoLink, CommitWebLink: commitLink}
|
||||||
if urlPrefixHostname == refHostname || refHostname == sshDomain {
|
|
||||||
return urlPrefix + path.Clean(path.Join("/", pth))
|
|
||||||
}
|
|
||||||
return "http://" + refHostname + pth
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ref, err := url.Parse(refURI)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
refHostname, _, err := net.SplitHostPort(ref.Host)
|
|
||||||
if err != nil {
|
|
||||||
refHostname = ref.Host
|
|
||||||
}
|
|
||||||
|
|
||||||
supportedSchemes := []string{"http", "https", "git", "ssh", "git+ssh"}
|
|
||||||
|
|
||||||
for _, scheme := range supportedSchemes {
|
|
||||||
if ref.Scheme == scheme {
|
|
||||||
if ref.Scheme == "http" || ref.Scheme == "https" {
|
|
||||||
if len(ref.User.Username()) > 0 {
|
|
||||||
return ref.Scheme + "://" + fmt.Sprintf("%v", ref.User) + "@" + ref.Host + ref.Path
|
|
||||||
}
|
|
||||||
return ref.Scheme + "://" + ref.Host + ref.Path
|
|
||||||
} else if urlPrefixHostname == refHostname || refHostname == sshDomain {
|
|
||||||
return urlPrefix + path.Clean(path.Join("/", ref.Path))
|
|
||||||
}
|
|
||||||
return "http://" + refHostname + ref.Path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// RefURL guesses and returns reference URL.
|
|
||||||
// FIXME: template passes AppURL as urlPrefix, it needs to figure out the correct approach (no hard-coded AppURL anymore)
|
|
||||||
func (sf *CommitSubModuleFile) RefURL(urlPrefix, repoFullName, sshDomain string) string {
|
|
||||||
return getRefURL(sf.refURL, urlPrefix, repoFullName, sshDomain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RefID returns reference ID.
|
|
||||||
func (sf *CommitSubModuleFile) RefID() string {
|
|
||||||
return sf.refID
|
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,30 @@
|
|||||||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommitSubModuleFileGetRefURL(t *testing.T) {
|
func TestCommitSubmoduleLink(t *testing.T) {
|
||||||
kases := []struct {
|
sf := NewCommitSubmoduleFile("git@github.com:user/repo.git", "aaaa")
|
||||||
refURL string
|
|
||||||
prefixURL string
|
|
||||||
parentPath string
|
|
||||||
SSHDomain string
|
|
||||||
expect string
|
|
||||||
}{
|
|
||||||
{"git://github.com/user1/repo1", "/", "user1/repo2", "", "http://github.com/user1/repo1"},
|
|
||||||
{"https://localhost/user1/repo1.git", "/", "user1/repo2", "", "https://localhost/user1/repo1"},
|
|
||||||
{"http://localhost/user1/repo1.git", "/", "owner/reponame", "", "http://localhost/user1/repo1"},
|
|
||||||
{"git@github.com:user1/repo1.git", "/", "owner/reponame", "", "http://github.com/user1/repo1"},
|
|
||||||
{"ssh://git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "zefie/lge_g6_kernel", "", "http://git.zefie.net/zefie/lge_g6_kernel_scripts"},
|
|
||||||
{"git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "zefie/lge_g6_kernel", "", "http://git.zefie.net/2222/zefie/lge_g6_kernel_scripts"},
|
|
||||||
{"git@try.gitea.io:go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "", "https://try.gitea.io/go-gitea/gitea"},
|
|
||||||
{"ssh://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "", "https://try.gitea.io/go-gitea/gitea"},
|
|
||||||
{"git://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "", "https://try.gitea.io/go-gitea/gitea"},
|
|
||||||
{"ssh://git@127.0.0.1:9999/go-gitea/gitea", "https://127.0.0.1:3000/", "go-gitea/sdk", "", "https://127.0.0.1:3000/go-gitea/gitea"},
|
|
||||||
{"https://gitea.com:3000/user1/repo1.git", "https://127.0.0.1:3000/", "user/repo2", "", "https://gitea.com:3000/user1/repo1"},
|
|
||||||
{"https://example.gitea.com/gitea/user1/repo1.git", "https://example.gitea.com/gitea/", "", "user/repo2", "https://example.gitea.com/gitea/user1/repo1"},
|
|
||||||
{"https://username:password@github.com/username/repository.git", "/", "username/repository2", "", "https://username:password@github.com/username/repository"},
|
|
||||||
{"somethingbad", "https://127.0.0.1:3000/go-gitea/gitea", "/", "", ""},
|
|
||||||
{"git@localhost:user/repo", "https://localhost/", "user2/repo1", "", "https://localhost/user/repo"},
|
|
||||||
{"../path/to/repo.git/", "https://localhost/", "user/repo2", "", "https://localhost/user/path/to/repo.git"},
|
|
||||||
{"ssh://git@ssh.gitea.io:2222/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "ssh.gitea.io", "https://try.gitea.io/go-gitea/gitea"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, kase := range kases {
|
wl := sf.SubmoduleWebLink(context.Background())
|
||||||
assert.EqualValues(t, kase.expect, getRefURL(kase.refURL, kase.prefixURL, kase.parentPath, kase.SSHDomain))
|
assert.Equal(t, "https://github.com/user/repo", wl.RepoWebLink)
|
||||||
}
|
assert.Equal(t, "https://github.com/user/repo/commit/aaaa", wl.CommitWebLink)
|
||||||
|
|
||||||
|
wl = sf.SubmoduleWebLink(context.Background(), "1111")
|
||||||
|
assert.Equal(t, "https://github.com/user/repo", wl.RepoWebLink)
|
||||||
|
assert.Equal(t, "https://github.com/user/repo/commit/1111", wl.CommitWebLink)
|
||||||
|
|
||||||
|
wl = sf.SubmoduleWebLink(context.Background(), "1111", "2222")
|
||||||
|
assert.Equal(t, "https://github.com/user/repo", wl.RepoWebLink)
|
||||||
|
assert.Equal(t, "https://github.com/user/repo/compare/1111...2222", wl.CommitWebLink)
|
||||||
|
|
||||||
|
wl = (*CommitSubmoduleFile)(nil).SubmoduleWebLink(context.Background())
|
||||||
|
assert.Nil(t, wl)
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommitsCount(t *testing.T) {
|
func TestCommitsCount(t *testing.T) {
|
||||||
@ -91,9 +92,7 @@ empty commit`
|
|||||||
|
|
||||||
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
|
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if !assert.NotNil(t, commitFromReader) {
|
require.NotNil(t, commitFromReader)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.EqualValues(t, sha, commitFromReader.ID)
|
assert.EqualValues(t, sha, commitFromReader.ID)
|
||||||
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
|
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
@ -159,9 +158,7 @@ ISO-8859-1`
|
|||||||
|
|
||||||
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
|
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if !assert.NotNil(t, commitFromReader) {
|
require.NotNil(t, commitFromReader)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.EqualValues(t, sha, commitFromReader.ID)
|
assert.EqualValues(t, sha, commitFromReader.ID)
|
||||||
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
|
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ func GetRemoteURL(ctx context.Context, repoPath, remoteName string) (*giturl.Git
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return giturl.Parse(addr)
|
return giturl.ParseGitURL(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error.
|
// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error.
|
||||||
@ -79,6 +79,15 @@ func (err *ErrInvalidCloneAddr) Unwrap() error {
|
|||||||
return util.ErrInvalidArgument
|
return util.ErrInvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsRemoteNotExistError checks the prefix of the error message to see whether a remote does not exist.
|
||||||
|
func IsRemoteNotExistError(err error) bool {
|
||||||
|
// see: https://github.com/go-gitea/gitea/issues/32889#issuecomment-2571848216
|
||||||
|
// Should not add space in the end, sometimes git will add a `:`
|
||||||
|
prefix1 := "exit status 128 - fatal: No such remote" // git < 2.30
|
||||||
|
prefix2 := "exit status 2 - error: No such remote" // git >= 2.30
|
||||||
|
return strings.HasPrefix(err.Error(), prefix1) || strings.HasPrefix(err.Error(), prefix2)
|
||||||
|
}
|
||||||
|
|
||||||
// ParseRemoteAddr checks if given remote address is valid,
|
// ParseRemoteAddr checks if given remote address is valid,
|
||||||
// and returns composed URL with needed username and password.
|
// and returns composed URL with needed username and password.
|
||||||
func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, error) {
|
func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, error) {
|
||||||
|
@ -10,20 +10,18 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRepository_GetLanguageStats(t *testing.T) {
|
func TestRepository_GetLanguageStats(t *testing.T) {
|
||||||
repoPath := filepath.Join(testReposDir, "language_stats_repo")
|
repoPath := filepath.Join(testReposDir, "language_stats_repo")
|
||||||
gitRepo, err := openRepositoryWithDefaultContext(repoPath)
|
gitRepo, err := openRepositoryWithDefaultContext(repoPath)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
defer gitRepo.Close()
|
defer gitRepo.Close()
|
||||||
|
|
||||||
stats, err := gitRepo.GetLanguageStats("8fee858da5796dfb37704761701bb8e800ad9ef3")
|
stats, err := gitRepo.GetLanguageStats("8fee858da5796dfb37704761701bb8e800ad9ef3")
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.EqualValues(t, map[string]int64{
|
assert.EqualValues(t, map[string]int64{
|
||||||
"Python": 134,
|
"Python": 134,
|
||||||
|
@ -182,7 +182,6 @@ func TestRepository_GetAnnotatedTag(t *testing.T) {
|
|||||||
|
|
||||||
// Annotated tag's name should fail
|
// Annotated tag's name should fail
|
||||||
tag3, err := bareRepo1.GetAnnotatedTag(aTagName)
|
tag3, err := bareRepo1.GetAnnotatedTag(aTagName)
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Errorf(t, err, "Length must be 40: %d", len(aTagName))
|
assert.Errorf(t, err, "Length must be 40: %d", len(aTagName))
|
||||||
assert.Nil(t, tag3)
|
assert.Nil(t, tag3)
|
||||||
|
|
||||||
|
@ -4,9 +4,15 @@
|
|||||||
package url
|
package url
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
stdurl "net/url"
|
stdurl "net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrWrongURLFormat represents an error with wrong url format
|
// ErrWrongURLFormat represents an error with wrong url format
|
||||||
@ -21,7 +27,7 @@ func (err ErrWrongURLFormat) Error() string {
|
|||||||
// GitURL represents a git URL
|
// GitURL represents a git URL
|
||||||
type GitURL struct {
|
type GitURL struct {
|
||||||
*stdurl.URL
|
*stdurl.URL
|
||||||
extraMark int // 0 no extra 1 scp 2 file path with no prefix
|
extraMark int // 0: standard URL with scheme, 1: scp short syntax (no scheme), 2: file path with no prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the URL's string
|
// String returns the URL's string
|
||||||
@ -38,8 +44,11 @@ func (u *GitURL) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parse all kinds of git URL
|
// ParseGitURL parse all kinds of git URL:
|
||||||
func Parse(remote string) (*GitURL, error) {
|
// * Full URL: http://git@host/path, http://git@host:port/path
|
||||||
|
// * SCP short syntax: git@host:/path
|
||||||
|
// * File path: /dir/repo/path
|
||||||
|
func ParseGitURL(remote string) (*GitURL, error) {
|
||||||
if strings.Contains(remote, "://") {
|
if strings.Contains(remote, "://") {
|
||||||
u, err := stdurl.Parse(remote)
|
u, err := stdurl.Parse(remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -87,3 +96,86 @@ func Parse(remote string) (*GitURL, error) {
|
|||||||
extraMark: 2,
|
extraMark: 2,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RepositoryURL struct {
|
||||||
|
GitURL *GitURL
|
||||||
|
|
||||||
|
// if the URL belongs to current Gitea instance, then the below fields have values
|
||||||
|
OwnerName string
|
||||||
|
RepoName string
|
||||||
|
RemainingPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseRepositoryURL tries to parse a Git URL and extract the owner/repository name if it belongs to current Gitea instance.
|
||||||
|
func ParseRepositoryURL(ctx context.Context, repoURL string) (*RepositoryURL, error) {
|
||||||
|
// possible urls for git:
|
||||||
|
// https://my.domain/sub-path/<owner>/<repo>[.git]
|
||||||
|
// git+ssh://user@my.domain/<owner>/<repo>[.git]
|
||||||
|
// ssh://user@my.domain/<owner>/<repo>[.git]
|
||||||
|
// user@my.domain:<owner>/<repo>[.git]
|
||||||
|
parsed, err := ParseGitURL(repoURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := &RepositoryURL{}
|
||||||
|
ret.GitURL = parsed
|
||||||
|
|
||||||
|
fillPathParts := func(s string) {
|
||||||
|
s = strings.TrimPrefix(s, "/")
|
||||||
|
fields := strings.SplitN(s, "/", 3)
|
||||||
|
if len(fields) >= 2 {
|
||||||
|
ret.OwnerName = fields[0]
|
||||||
|
ret.RepoName = strings.TrimSuffix(fields[1], ".git")
|
||||||
|
if len(fields) == 3 {
|
||||||
|
ret.RemainingPath = "/" + fields[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if parsed.URL.Scheme == "http" || parsed.URL.Scheme == "https" {
|
||||||
|
if !httplib.IsCurrentGiteaSiteURL(ctx, repoURL) {
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
fillPathParts(strings.TrimPrefix(parsed.URL.Path, setting.AppSubURL))
|
||||||
|
} else if parsed.URL.Scheme == "ssh" || parsed.URL.Scheme == "git+ssh" {
|
||||||
|
domainSSH := setting.SSH.Domain
|
||||||
|
domainCur := httplib.GuessCurrentHostDomain(ctx)
|
||||||
|
urlDomain, _, _ := net.SplitHostPort(parsed.URL.Host)
|
||||||
|
urlDomain = util.IfZero(urlDomain, parsed.URL.Host)
|
||||||
|
if urlDomain == "" {
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
// check whether URL domain is the App domain
|
||||||
|
domainMatches := domainSSH == urlDomain
|
||||||
|
// check whether URL domain is current domain from context
|
||||||
|
domainMatches = domainMatches || (domainCur != "" && domainCur == urlDomain)
|
||||||
|
if domainMatches {
|
||||||
|
fillPathParts(parsed.URL.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRepositoryWebLink generates a web link (http/https) for a git repository (by guessing sometimes)
|
||||||
|
func MakeRepositoryWebLink(repoURL *RepositoryURL) string {
|
||||||
|
if repoURL.OwnerName != "" {
|
||||||
|
return setting.AppSubURL + "/" + repoURL.OwnerName + "/" + repoURL.RepoName
|
||||||
|
}
|
||||||
|
|
||||||
|
// now, let's guess, for example:
|
||||||
|
// * git@github.com:owner/submodule.git
|
||||||
|
// * https://github.com/example/submodule1.git
|
||||||
|
if repoURL.GitURL.Scheme == "http" || repoURL.GitURL.Scheme == "https" {
|
||||||
|
return strings.TrimSuffix(repoURL.GitURL.String(), ".git")
|
||||||
|
} else if repoURL.GitURL.Scheme == "ssh" || repoURL.GitURL.Scheme == "git+ssh" {
|
||||||
|
hostname, _, _ := net.SplitHostPort(repoURL.GitURL.Host)
|
||||||
|
hostname = util.IfZero(hostname, repoURL.GitURL.Host)
|
||||||
|
urlPath := strings.TrimSuffix(repoURL.GitURL.Path, ".git")
|
||||||
|
urlPath = strings.TrimPrefix(urlPath, "/")
|
||||||
|
urlFull := fmt.Sprintf("https://%s/%s", hostname, urlPath)
|
||||||
|
urlFull = strings.TrimSuffix(urlFull, "/")
|
||||||
|
return urlFull
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
@ -4,9 +4,15 @@
|
|||||||
package url
|
package url
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -157,10 +163,105 @@ func TestParseGitURLs(t *testing.T) {
|
|||||||
|
|
||||||
for _, kase := range kases {
|
for _, kase := range kases {
|
||||||
t.Run(kase.kase, func(t *testing.T) {
|
t.Run(kase.kase, func(t *testing.T) {
|
||||||
u, err := Parse(kase.kase)
|
u, err := ParseGitURL(kase.kase)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, kase.expected.extraMark, u.extraMark)
|
assert.EqualValues(t, kase.expected.extraMark, u.extraMark)
|
||||||
assert.EqualValues(t, *kase.expected, *u)
|
assert.EqualValues(t, *kase.expected, *u)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseRepositoryURL(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.AppURL, "https://localhost:3000")()
|
||||||
|
defer test.MockVariableValue(&setting.SSH.Domain, "try.gitea.io")()
|
||||||
|
|
||||||
|
ctxURL, _ := url.Parse("https://gitea")
|
||||||
|
ctxReq := &http.Request{URL: ctxURL, Header: http.Header{}}
|
||||||
|
ctxReq.Host = ctxURL.Host
|
||||||
|
ctxReq.Header.Add("X-Forwarded-Proto", ctxURL.Scheme)
|
||||||
|
ctx := context.WithValue(context.Background(), httplib.RequestContextKey, ctxReq)
|
||||||
|
cases := []struct {
|
||||||
|
input string
|
||||||
|
ownerName, repoName, remaining string
|
||||||
|
}{
|
||||||
|
{input: "/user/repo"},
|
||||||
|
|
||||||
|
{input: "https://localhost:3000/user/repo", ownerName: "user", repoName: "repo"},
|
||||||
|
{input: "https://external:3000/user/repo"},
|
||||||
|
|
||||||
|
{input: "https://localhost:3000/user/repo.git/other", ownerName: "user", repoName: "repo", remaining: "/other"},
|
||||||
|
|
||||||
|
{input: "https://gitea/user/repo", ownerName: "user", repoName: "repo"},
|
||||||
|
{input: "https://gitea:3333/user/repo"},
|
||||||
|
|
||||||
|
{input: "ssh://try.gitea.io:2222/user/repo", ownerName: "user", repoName: "repo"},
|
||||||
|
{input: "ssh://external:2222/user/repo"},
|
||||||
|
|
||||||
|
{input: "git+ssh://user@try.gitea.io/user/repo.git", ownerName: "user", repoName: "repo"},
|
||||||
|
{input: "git+ssh://user@external/user/repo.git"},
|
||||||
|
|
||||||
|
{input: "root@try.gitea.io:user/repo.git", ownerName: "user", repoName: "repo"},
|
||||||
|
{input: "root@gitea:user/repo.git", ownerName: "user", repoName: "repo"},
|
||||||
|
{input: "root@external:user/repo.git"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.input, func(t *testing.T) {
|
||||||
|
ret, _ := ParseRepositoryURL(ctx, c.input)
|
||||||
|
assert.Equal(t, c.ownerName, ret.OwnerName)
|
||||||
|
assert.Equal(t, c.repoName, ret.RepoName)
|
||||||
|
assert.Equal(t, c.remaining, ret.RemainingPath)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("WithSubpath", func(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.AppURL, "https://localhost:3000/subpath")()
|
||||||
|
defer test.MockVariableValue(&setting.AppSubURL, "/subpath")()
|
||||||
|
cases = []struct {
|
||||||
|
input string
|
||||||
|
ownerName, repoName, remaining string
|
||||||
|
}{
|
||||||
|
{input: "https://localhost:3000/user/repo"},
|
||||||
|
{input: "https://localhost:3000/subpath/user/repo.git/other", ownerName: "user", repoName: "repo", remaining: "/other"},
|
||||||
|
|
||||||
|
{input: "ssh://try.gitea.io:2222/user/repo", ownerName: "user", repoName: "repo"},
|
||||||
|
{input: "ssh://external:2222/user/repo"},
|
||||||
|
|
||||||
|
{input: "git+ssh://user@try.gitea.io/user/repo.git", ownerName: "user", repoName: "repo"},
|
||||||
|
{input: "git+ssh://user@external/user/repo.git"},
|
||||||
|
|
||||||
|
{input: "root@try.gitea.io:user/repo.git", ownerName: "user", repoName: "repo"},
|
||||||
|
{input: "root@external:user/repo.git"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.input, func(t *testing.T) {
|
||||||
|
ret, _ := ParseRepositoryURL(ctx, c.input)
|
||||||
|
assert.Equal(t, c.ownerName, ret.OwnerName)
|
||||||
|
assert.Equal(t, c.repoName, ret.RepoName)
|
||||||
|
assert.Equal(t, c.remaining, ret.RemainingPath)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMakeRepositoryBaseLink(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.AppURL, "https://localhost:3000/subpath")()
|
||||||
|
defer test.MockVariableValue(&setting.AppSubURL, "/subpath")()
|
||||||
|
|
||||||
|
u, err := ParseRepositoryURL(context.Background(), "https://localhost:3000/subpath/user/repo.git")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "/subpath/user/repo", MakeRepositoryWebLink(u))
|
||||||
|
|
||||||
|
u, err = ParseRepositoryURL(context.Background(), "https://github.com/owner/repo.git")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "https://github.com/owner/repo", MakeRepositoryWebLink(u))
|
||||||
|
|
||||||
|
u, err = ParseRepositoryURL(context.Background(), "git@github.com:owner/repo.git")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "https://github.com/owner/repo", MakeRepositoryWebLink(u))
|
||||||
|
|
||||||
|
u, err = ParseRepositoryURL(context.Background(), "git+ssh://other:123/owner/repo.git")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "https://other/owner/repo", MakeRepositoryWebLink(u))
|
||||||
|
}
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkGetCommitGraph(b *testing.B) {
|
func BenchmarkGetCommitGraph(b *testing.B) {
|
||||||
@ -235,9 +237,7 @@ func TestParseGlyphs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
row++
|
row++
|
||||||
}
|
}
|
||||||
if len(parser.availableColors) != 9 {
|
assert.Len(t, parser.availableColors, 9)
|
||||||
t.Errorf("Expected 9 colors but have %d", len(parser.availableColors))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommitStringParsing(t *testing.T) {
|
func TestCommitStringParsing(t *testing.T) {
|
||||||
@ -262,9 +262,7 @@ func TestCommitStringParsing(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.commitMessage != commit.Subject {
|
assert.Equal(t, test.commitMessage, commit.Subject)
|
||||||
t.Errorf("%s does not match %s", test.commitMessage, commit.Subject)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ func ParseSizeAndClass(defaultSize int, defaultClass string, others ...any) (int
|
|||||||
return size, class
|
return size, class
|
||||||
}
|
}
|
||||||
|
|
||||||
func HTMLFormat(s string, rawArgs ...any) template.HTML {
|
func HTMLFormat(s template.HTML, rawArgs ...any) template.HTML {
|
||||||
args := slices.Clone(rawArgs)
|
args := slices.Clone(rawArgs)
|
||||||
for i, v := range args {
|
for i, v := range args {
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
@ -44,5 +44,5 @@ func HTMLFormat(s string, rawArgs ...any) template.HTML {
|
|||||||
args[i] = template.HTMLEscapeString(fmt.Sprint(v))
|
args[i] = template.HTMLEscapeString(fmt.Sprint(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return template.HTML(fmt.Sprintf(s, args...))
|
return template.HTML(fmt.Sprintf(string(s), args...))
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServeContentByReader(t *testing.T) {
|
func TestServeContentByReader(t *testing.T) {
|
||||||
@ -71,9 +72,7 @@ func TestServeContentByReadSeeker(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
seekReader, err := os.OpenFile(tmpFile, os.O_RDONLY, 0o644)
|
seekReader, err := os.OpenFile(tmpFile, os.O_RDONLY, 0o644)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
defer seekReader.Close()
|
defer seekReader.Close()
|
||||||
|
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
@ -5,6 +5,7 @@ package httplib
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@ -81,6 +82,12 @@ func GuessCurrentHostURL(ctx context.Context) string {
|
|||||||
return reqScheme + "://" + req.Host
|
return reqScheme + "://" + req.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GuessCurrentHostDomain(ctx context.Context) string {
|
||||||
|
_, host, _ := strings.Cut(GuessCurrentHostURL(ctx), "://")
|
||||||
|
domain, _, _ := net.SplitHostPort(host)
|
||||||
|
return util.IfZero(domain, host)
|
||||||
|
}
|
||||||
|
|
||||||
// MakeAbsoluteURL tries to make a link to an absolute URL:
|
// MakeAbsoluteURL tries to make a link to an absolute URL:
|
||||||
// * If link is empty, it returns the current app URL.
|
// * If link is empty, it returns the current app URL.
|
||||||
// * If link is absolute, it returns the link.
|
// * If link is absolute, it returns the link.
|
||||||
@ -105,7 +112,7 @@ func IsCurrentGiteaSiteURL(ctx context.Context, s string) bool {
|
|||||||
if cleanedPath == "" || cleanedPath == "." {
|
if cleanedPath == "" || cleanedPath == "." {
|
||||||
u.Path = "/"
|
u.Path = "/"
|
||||||
} else {
|
} else {
|
||||||
u.Path += "/" + cleanedPath + "/"
|
u.Path = "/" + cleanedPath + "/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if urlIsRelative(s, u) {
|
if urlIsRelative(s, u) {
|
||||||
|
@ -11,6 +11,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/indexer/issues/internal/tests"
|
"code.gitea.io/gitea/modules/indexer/issues/internal/tests"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestElasticsearchIndexer(t *testing.T) {
|
func TestElasticsearchIndexer(t *testing.T) {
|
||||||
@ -26,20 +28,10 @@ func TestElasticsearchIndexer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := false
|
require.Eventually(t, func() bool {
|
||||||
for i := 0; i < 60; i++ {
|
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err == nil && resp.StatusCode == http.StatusOK {
|
return err == nil && resp.StatusCode == http.StatusOK
|
||||||
ok = true
|
}, time.Minute, time.Second, "Expected elasticsearch to be up")
|
||||||
break
|
|
||||||
}
|
|
||||||
t.Logf("Waiting for elasticsearch to be up: %v", err)
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("Failed to wait for elasticsearch to be up")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
indexer := NewIndexer(url, fmt.Sprintf("test_elasticsearch_indexer_%d", time.Now().Unix()))
|
indexer := NewIndexer(url, fmt.Sprintf("test_elasticsearch_indexer_%d", time.Now().Unix()))
|
||||||
defer indexer.Close()
|
defer indexer.Close()
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
_ "code.gitea.io/gitea/models/activities"
|
_ "code.gitea.io/gitea/models/activities"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
@ -26,7 +27,7 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDBSearchIssues(t *testing.T) {
|
func TestDBSearchIssues(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
require.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
setting.Indexer.IssueType = "db"
|
setting.Indexer.IssueType = "db"
|
||||||
InitIssueIndexer(true)
|
InitIssueIndexer(true)
|
||||||
@ -83,9 +84,7 @@ func searchIssueWithKeyword(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,9 +119,7 @@ func searchIssueByIndex(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,9 +163,7 @@ func searchIssueInRepo(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,9 +233,7 @@ func searchIssueByID(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,9 +258,7 @@ func searchIssueIsPull(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,9 +283,7 @@ func searchIssueIsClosed(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,9 +308,7 @@ func searchIssueIsArchived(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -346,9 +333,7 @@ func searchIssueByMilestoneID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,9 +364,7 @@ func searchIssueByLabelID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,9 +383,7 @@ func searchIssueByTime(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -421,9 +402,7 @@ func searchIssueWithOrder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -454,9 +433,7 @@ func searchIssueInProject(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -479,9 +456,7 @@ func searchIssueWithPaginator(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
issueIDs, total, err := SearchIssues(context.TODO(), &test.opts)
|
issueIDs, total, err := SearchIssues(context.TODO(), &test.opts)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||||
assert.Equal(t, test.expectedTotal, total)
|
assert.Equal(t, test.expectedTotal, total)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
"github.com/meilisearch/meilisearch-go"
|
"github.com/meilisearch/meilisearch-go"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMeilisearchIndexer(t *testing.T) {
|
func TestMeilisearchIndexer(t *testing.T) {
|
||||||
@ -32,20 +33,10 @@ func TestMeilisearchIndexer(t *testing.T) {
|
|||||||
key = os.Getenv("TEST_MEILISEARCH_KEY")
|
key = os.Getenv("TEST_MEILISEARCH_KEY")
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := false
|
require.Eventually(t, func() bool {
|
||||||
for i := 0; i < 60; i++ {
|
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err == nil && resp.StatusCode == http.StatusOK {
|
return err == nil && resp.StatusCode == http.StatusOK
|
||||||
ok = true
|
}, time.Minute, time.Second, "Expected meilisearch to be up")
|
||||||
break
|
|
||||||
}
|
|
||||||
t.Logf("Waiting for meilisearch to be up: %v", err)
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("Failed to wait for meilisearch to be up")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
indexer := NewIndexer(url, key, fmt.Sprintf("test_meilisearch_indexer_%d", time.Now().Unix()))
|
indexer := NewIndexer(url, key, fmt.Sprintf("test_meilisearch_indexer_%d", time.Now().Unix()))
|
||||||
defer indexer.Close()
|
defer indexer.Close()
|
||||||
|
@ -957,9 +957,8 @@ func Test_minQuotes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := minQuotes(tt.args.value); got != tt.want {
|
got := minQuotes(tt.args.value)
|
||||||
t.Errorf("minQuotes() = %v, want %v", got, tt.want)
|
assert.Equal(t, tt.want, got)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ func (r *RenderInternal) ProtectSafeAttrs(content template.HTML) template.HTML {
|
|||||||
return template.HTML(reAttrClass().ReplaceAllString(string(content), `$1 data-attr-class="`+r.secureIDPrefix+`$2"$3`))
|
return template.HTML(reAttrClass().ReplaceAllString(string(content), `$1 data-attr-class="`+r.secureIDPrefix+`$2"$3`))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RenderInternal) FormatWithSafeAttrs(w io.Writer, fmt string, a ...any) error {
|
func (r *RenderInternal) FormatWithSafeAttrs(w io.Writer, fmt template.HTML, a ...any) error {
|
||||||
_, err := w.Write([]byte(r.ProtectSafeAttrs(htmlutil.HTMLFormat(fmt, a...))))
|
_, err := w.Write([]byte(r.ProtectSafeAttrs(htmlutil.HTMLFormat(fmt, a...))))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
package math
|
package math
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"html/template"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/markup/internal"
|
"code.gitea.io/gitea/modules/markup/internal"
|
||||||
giteaUtil "code.gitea.io/gitea/modules/util"
|
giteaUtil "code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ func (r *BlockRenderer) renderBlock(w util.BufWriter, source []byte, node gast.N
|
|||||||
n := node.(*Block)
|
n := node.(*Block)
|
||||||
if entering {
|
if entering {
|
||||||
code := giteaUtil.Iif(n.Inline, "", `<pre class="code-block is-loading">`) + `<code class="language-math display">`
|
code := giteaUtil.Iif(n.Inline, "", `<pre class="code-block is-loading">`) + `<code class="language-math display">`
|
||||||
_ = r.renderInternal.FormatWithSafeAttrs(w, code)
|
_ = r.renderInternal.FormatWithSafeAttrs(w, template.HTML(code))
|
||||||
r.writeLines(w, source, n)
|
r.writeLines(w, source, n)
|
||||||
} else {
|
} else {
|
||||||
_, _ = w.WriteString(`</code>` + giteaUtil.Iif(n.Inline, "", `</pre>`) + "\n")
|
_, _ = w.WriteString(`</code>` + giteaUtil.Iif(n.Inline, "", `</pre>`) + "\n")
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -140,23 +142,13 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
|
|||||||
Icon: "table",
|
Icon: "table",
|
||||||
Lang: "",
|
Lang: "",
|
||||||
}
|
}
|
||||||
if err := yaml.Unmarshal([]byte(strings.ReplaceAll(tt.args, "\t", " ")), got); err != nil {
|
err := yaml.Unmarshal([]byte(strings.ReplaceAll(tt.args, "\t", " ")), got)
|
||||||
t.Errorf("RenderConfig.UnmarshalYAML() error = %v\n%q", err, tt.args)
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if got.Meta != tt.expected.Meta {
|
assert.Equal(t, tt.expected.Meta, got.Meta)
|
||||||
t.Errorf("Meta Expected %s Got %s", tt.expected.Meta, got.Meta)
|
assert.Equal(t, tt.expected.Icon, got.Icon)
|
||||||
}
|
assert.Equal(t, tt.expected.Lang, got.Lang)
|
||||||
if got.Icon != tt.expected.Icon {
|
assert.Equal(t, tt.expected.TOC, got.TOC)
|
||||||
t.Errorf("Icon Expected %s Got %s", tt.expected.Icon, got.Icon)
|
|
||||||
}
|
|
||||||
if got.Lang != tt.expected.Lang {
|
|
||||||
t.Errorf("Lang Expected %s Got %s", tt.expected.Lang, got.Lang)
|
|
||||||
}
|
|
||||||
if got.TOC != tt.expected.TOC {
|
|
||||||
t.Errorf("TOC Expected %q Got %q", tt.expected.TOC, got.TOC)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ func (r *orgWriter) resolveLink(kind, link string) string {
|
|||||||
func (r *orgWriter) WriteRegularLink(l org.RegularLink) {
|
func (r *orgWriter) WriteRegularLink(l org.RegularLink) {
|
||||||
link := r.resolveLink(l.Kind(), l.URL)
|
link := r.resolveLink(l.Kind(), l.URL)
|
||||||
|
|
||||||
printHTML := func(html string, a ...any) {
|
printHTML := func(html template.HTML, a ...any) {
|
||||||
_, _ = fmt.Fprint(r, htmlutil.HTMLFormat(html, a...))
|
_, _ = fmt.Fprint(r, htmlutil.HTMLFormat(html, a...))
|
||||||
}
|
}
|
||||||
// Inspired by https://github.com/niklasfasching/go-org/blob/6eb20dbda93cb88c3503f7508dc78cbbc639378f/org/html_writer.go#L406-L427
|
// Inspired by https://github.com/niklasfasching/go-org/blob/6eb20dbda93cb88c3503f7508dc78cbbc639378f/org/html_writer.go#L406-L427
|
||||||
|
@ -103,8 +103,8 @@ func HelloWorld() {
|
|||||||
}
|
}
|
||||||
#+end_src
|
#+end_src
|
||||||
`, `<div class="src src-go">
|
`, `<div class="src src-go">
|
||||||
<pre><code class="chroma language-go"><span class="c1">// HelloWorld prints "Hello World"
|
<pre><code class="chroma language-go"><span class="c1">// HelloWorld prints "Hello World"</span>
|
||||||
</span><span class="c1"></span><span class="kd">func</span> <span class="nf">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
|
<span class="kd">func</span> <span class="nf">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
|
||||||
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"Hello World"</span><span class="p">)</span>
|
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"Hello World"</span><span class="p">)</span>
|
||||||
<span class="p">}</span></code></pre>
|
<span class="p">}</span></code></pre>
|
||||||
</div>`)
|
</div>`)
|
||||||
|
@ -5,6 +5,9 @@ package nosql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestToRedisURI(t *testing.T) {
|
func TestToRedisURI(t *testing.T) {
|
||||||
@ -26,9 +29,9 @@ func TestToRedisURI(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := ToRedisURI(tt.connection); got == nil || got.String() != tt.want {
|
got := ToRedisURI(tt.connection)
|
||||||
t.Errorf(`ToRedisURI(%q) = %s, want %s`, tt.connection, got.String(), tt.want)
|
require.NotNil(t, got)
|
||||||
}
|
assert.Equal(t, tt.want, got.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,7 @@ type PackageMetadataVersion struct {
|
|||||||
BundleDependencies []string `json:"bundleDependencies,omitempty"`
|
BundleDependencies []string `json:"bundleDependencies,omitempty"`
|
||||||
DevDependencies map[string]string `json:"devDependencies,omitempty"`
|
DevDependencies map[string]string `json:"devDependencies,omitempty"`
|
||||||
PeerDependencies map[string]string `json:"peerDependencies,omitempty"`
|
PeerDependencies map[string]string `json:"peerDependencies,omitempty"`
|
||||||
|
PeerDependenciesMeta map[string]any `json:"peerDependenciesMeta,omitempty"`
|
||||||
Bin map[string]string `json:"bin,omitempty"`
|
Bin map[string]string `json:"bin,omitempty"`
|
||||||
OptionalDependencies map[string]string `json:"optionalDependencies,omitempty"`
|
OptionalDependencies map[string]string `json:"optionalDependencies,omitempty"`
|
||||||
Readme string `json:"readme,omitempty"`
|
Readme string `json:"readme,omitempty"`
|
||||||
@ -222,6 +223,7 @@ func ParsePackage(r io.Reader) (*Package, error) {
|
|||||||
BundleDependencies: meta.BundleDependencies,
|
BundleDependencies: meta.BundleDependencies,
|
||||||
DevelopmentDependencies: meta.DevDependencies,
|
DevelopmentDependencies: meta.DevDependencies,
|
||||||
PeerDependencies: meta.PeerDependencies,
|
PeerDependencies: meta.PeerDependencies,
|
||||||
|
PeerDependenciesMeta: meta.PeerDependenciesMeta,
|
||||||
OptionalDependencies: meta.OptionalDependencies,
|
OptionalDependencies: meta.OptionalDependencies,
|
||||||
Bin: meta.Bin,
|
Bin: meta.Bin,
|
||||||
Readme: meta.Readme,
|
Readme: meta.Readme,
|
||||||
|
@ -19,6 +19,7 @@ type Metadata struct {
|
|||||||
BundleDependencies []string `json:"bundleDependencies,omitempty"`
|
BundleDependencies []string `json:"bundleDependencies,omitempty"`
|
||||||
DevelopmentDependencies map[string]string `json:"development_dependencies,omitempty"`
|
DevelopmentDependencies map[string]string `json:"development_dependencies,omitempty"`
|
||||||
PeerDependencies map[string]string `json:"peer_dependencies,omitempty"`
|
PeerDependencies map[string]string `json:"peer_dependencies,omitempty"`
|
||||||
|
PeerDependenciesMeta map[string]any `json:"peer_dependencies_meta,omitempty"`
|
||||||
OptionalDependencies map[string]string `json:"optional_dependencies,omitempty"`
|
OptionalDependencies map[string]string `json:"optional_dependencies,omitempty"`
|
||||||
Bin map[string]string `json:"bin,omitempty"`
|
Bin map[string]string `json:"bin,omitempty"`
|
||||||
Readme string `json:"readme,omitempty"`
|
Readme string `json:"readme,omitempty"`
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"gitea.com/lunny/levelqueue"
|
"gitea.com/lunny/levelqueue"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,9 +30,7 @@ func TestCorruptedLevelQueue(t *testing.T) {
|
|||||||
// sometimes the levelqueue could be in a corrupted state, this test is to make sure it can recover from it
|
// sometimes the levelqueue could be in a corrupted state, this test is to make sure it can recover from it
|
||||||
dbDir := t.TempDir() + "/levelqueue-test"
|
dbDir := t.TempDir() + "/levelqueue-test"
|
||||||
db, err := leveldb.OpenFile(dbDir, nil)
|
db, err := leveldb.OpenFile(dbDir, nil)
|
||||||
if !assert.NoError(t, err) {
|
require.NoError(t, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
assert.NoError(t, db.Put([]byte("other-key"), []byte("other-value"), nil))
|
assert.NoError(t, db.Put([]byte("other-key"), []byte("other-value"), nil))
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func waitRedisReady(conn string, dur time.Duration) (ready bool) {
|
func waitRedisReady(conn string, dur time.Duration) (ready bool) {
|
||||||
@ -61,9 +62,7 @@ func TestBaseRedis(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
assert.NoError(t, redisServer.Start())
|
assert.NoError(t, redisServer.Start())
|
||||||
if !assert.True(t, waitRedisReady("redis://127.0.0.1:6379/0", 5*time.Second), "start redis-server") {
|
require.True(t, waitRedisReady("redis://127.0.0.1:6379/0", 5*time.Second), "start redis-server")
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testQueueBasic(t, newBaseRedisSimple, toBaseConfig("baseRedis", setting.QueueSettings{Length: 10}), false)
|
testQueueBasic(t, newBaseRedisSimple, toBaseConfig("baseRedis", setting.QueueSettings{Length: 10}), false)
|
||||||
|
@ -6,6 +6,7 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
@ -51,6 +52,9 @@ func SyncRepoBranchesWithRepo(ctx context.Context, repo *repo_model.Repository,
|
|||||||
{
|
{
|
||||||
branches, _, err := gitRepo.GetBranchNames(0, 0)
|
branches, _, err := gitRepo.GetBranchNames(0, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "ref file is empty") {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
log.Trace("SyncRepoBranches[%s]: branches[%d]: %v", repo.FullName(), len(branches), branches)
|
log.Trace("SyncRepoBranches[%s]: branches[%d]: %v", repo.FullName(), len(branches), branches)
|
||||||
|
@ -5,6 +5,8 @@ package structs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNoBetterThan(t *testing.T) {
|
func TestNoBetterThan(t *testing.T) {
|
||||||
@ -166,9 +168,7 @@ func TestNoBetterThan(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
result := tt.args.css.NoBetterThan(tt.args.css2)
|
result := tt.args.css.NoBetterThan(tt.args.css2)
|
||||||
if result != tt.want {
|
assert.Equal(t, tt.want, result)
|
||||||
t.Errorf("NoBetterThan() = %v, want %v", result, tt.want)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ func NewFuncMap() template.FuncMap {
|
|||||||
"Iif": iif,
|
"Iif": iif,
|
||||||
"Eval": evalTokens,
|
"Eval": evalTokens,
|
||||||
"SafeHTML": safeHTML,
|
"SafeHTML": safeHTML,
|
||||||
"HTMLFormat": htmlutil.HTMLFormat,
|
"HTMLFormat": htmlFormat,
|
||||||
"HTMLEscape": htmlEscape,
|
"HTMLEscape": htmlEscape,
|
||||||
"QueryEscape": queryEscape,
|
"QueryEscape": queryEscape,
|
||||||
"QueryBuild": QueryBuild,
|
"QueryBuild": QueryBuild,
|
||||||
@ -207,6 +207,20 @@ func htmlEscape(s any) template.HTML {
|
|||||||
panic(fmt.Sprintf("unexpected type %T", s))
|
panic(fmt.Sprintf("unexpected type %T", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func htmlFormat(s any, args ...any) template.HTML {
|
||||||
|
if len(args) == 0 {
|
||||||
|
// to prevent developers from calling "HTMLFormat $userInput" by mistake which will lead to XSS
|
||||||
|
panic("missing arguments for HTMLFormat")
|
||||||
|
}
|
||||||
|
switch v := s.(type) {
|
||||||
|
case string:
|
||||||
|
return htmlutil.HTMLFormat(template.HTML(v), args...)
|
||||||
|
case template.HTML:
|
||||||
|
return htmlutil.HTMLFormat(v, args...)
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("unexpected type %T", s))
|
||||||
|
}
|
||||||
|
|
||||||
func jsEscapeSafe(s string) template.HTML {
|
func jsEscapeSafe(s string) template.HTML {
|
||||||
return template.HTML(template.JSEscapeString(s))
|
return template.HTML(template.JSEscapeString(s))
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/htmlutil"
|
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -88,7 +87,7 @@ func TestTemplateIif(t *testing.T) {
|
|||||||
func TestTemplateEscape(t *testing.T) {
|
func TestTemplateEscape(t *testing.T) {
|
||||||
execTmpl := func(code string) string {
|
execTmpl := func(code string) string {
|
||||||
tmpl := template.New("test")
|
tmpl := template.New("test")
|
||||||
tmpl.Funcs(template.FuncMap{"QueryBuild": QueryBuild, "HTMLFormat": htmlutil.HTMLFormat})
|
tmpl.Funcs(template.FuncMap{"QueryBuild": QueryBuild, "HTMLFormat": htmlFormat})
|
||||||
template.Must(tmpl.Parse(code))
|
template.Must(tmpl.Parse(code))
|
||||||
w := &strings.Builder{}
|
w := &strings.Builder{}
|
||||||
assert.NoError(t, tmpl.Execute(w, nil))
|
assert.NoError(t, tmpl.Execute(w, nil))
|
||||||
|
@ -150,7 +150,7 @@ func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteNa
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := giturl.Parse(remoteURL)
|
u, err := giturl.ParseGitURL(remoteURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("giturl.Parse %v", err)
|
log.Error("giturl.Parse %v", err)
|
||||||
return ret
|
return ret
|
||||||
|
@ -8,6 +8,9 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getWhoamiOutput() (string, error) {
|
func getWhoamiOutput() (string, error) {
|
||||||
@ -20,24 +23,19 @@ func getWhoamiOutput() (string, error) {
|
|||||||
|
|
||||||
func TestCurrentUsername(t *testing.T) {
|
func TestCurrentUsername(t *testing.T) {
|
||||||
user := CurrentUsername()
|
user := CurrentUsername()
|
||||||
if len(user) == 0 {
|
require.NotEmpty(t, user)
|
||||||
t.Errorf("expected non-empty user, got: %s", user)
|
|
||||||
}
|
|
||||||
// Windows whoami is weird, so just skip remaining tests
|
// Windows whoami is weird, so just skip remaining tests
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
t.Skip("skipped test because of weird whoami on Windows")
|
t.Skip("skipped test because of weird whoami on Windows")
|
||||||
}
|
}
|
||||||
whoami, err := getWhoamiOutput()
|
whoami, err := getWhoamiOutput()
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
t.Errorf("failed to run whoami to test current user: %f", err)
|
|
||||||
}
|
|
||||||
user = CurrentUsername()
|
user = CurrentUsername()
|
||||||
if user != whoami {
|
assert.Equal(t, whoami, user)
|
||||||
t.Errorf("expected %s as user, got: %s", whoami, user)
|
|
||||||
}
|
|
||||||
t.Setenv("USER", "spoofed")
|
t.Setenv("USER", "spoofed")
|
||||||
user = CurrentUsername()
|
user = CurrentUsername()
|
||||||
if user != whoami {
|
assert.Equal(t, whoami, user)
|
||||||
t.Errorf("expected %s as user, got: %s", whoami, user)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
func TestShellEscape(t *testing.T) {
|
func TestShellEscape(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -83,9 +87,7 @@ func TestShellEscape(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := ShellEscape(tt.toEscape); got != tt.want {
|
assert.Equal(t, tt.want, ShellEscape(tt.toEscape))
|
||||||
t.Errorf("ShellEscape(%q):\nGot: %s\nWanted: %s", tt.toEscape, got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,11 +89,23 @@ func (p *routerPathMatcher) matchPath(chiCtx *chi.Context, path string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isValidMethod(name string) bool {
|
||||||
|
switch name {
|
||||||
|
case http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete, http.MethodHead, http.MethodOptions, http.MethodConnect, http.MethodTrace:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func newRouterPathMatcher(methods, pattern string, h ...any) *routerPathMatcher {
|
func newRouterPathMatcher(methods, pattern string, h ...any) *routerPathMatcher {
|
||||||
middlewares, handlerFunc := wrapMiddlewareAndHandler(nil, h)
|
middlewares, handlerFunc := wrapMiddlewareAndHandler(nil, h)
|
||||||
p := &routerPathMatcher{methods: make(container.Set[string]), middlewares: middlewares, handlerFunc: handlerFunc}
|
p := &routerPathMatcher{methods: make(container.Set[string]), middlewares: middlewares, handlerFunc: handlerFunc}
|
||||||
for _, method := range strings.Split(methods, ",") {
|
for _, method := range strings.Split(methods, ",") {
|
||||||
p.methods.Add(strings.TrimSpace(method))
|
method = strings.TrimSpace(method)
|
||||||
|
if !isValidMethod(method) {
|
||||||
|
panic(fmt.Sprintf("invalid HTTP method: %s", method))
|
||||||
|
}
|
||||||
|
p.methods.Add(method)
|
||||||
}
|
}
|
||||||
re := []byte{'^'}
|
re := []byte{'^'}
|
||||||
lastEnd := 0
|
lastEnd := 0
|
||||||
|
@ -6,6 +6,8 @@ package routing
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_shortenFilename(t *testing.T) {
|
func Test_shortenFilename(t *testing.T) {
|
||||||
@ -37,9 +39,8 @@ func Test_shortenFilename(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(fmt.Sprintf("shortenFilename('%s')", tt.filename), func(t *testing.T) {
|
t.Run(fmt.Sprintf("shortenFilename('%s')", tt.filename), func(t *testing.T) {
|
||||||
if gotShort := shortenFilename(tt.filename, tt.fallback); gotShort != tt.expected {
|
gotShort := shortenFilename(tt.filename, tt.fallback)
|
||||||
t.Errorf("shortenFilename('%s'), expect '%s', but get '%s'", tt.filename, tt.expected, gotShort)
|
assert.Equal(t, tt.expected, gotShort)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,9 +73,8 @@ func Test_trimAnonymousFunctionSuffix(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := trimAnonymousFunctionSuffix(tt.name); got != tt.want {
|
got := trimAnonymousFunctionSuffix(tt.name)
|
||||||
t.Errorf("trimAnonymousFunctionSuffix() = %v, want %v", got, tt.want)
|
assert.Equal(t, tt.want, got)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,10 @@ func (h HookEventType) Event() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h HookEventType) IsPullRequest() bool {
|
||||||
|
return h.Event() == "pull_request"
|
||||||
|
}
|
||||||
|
|
||||||
// HookType is the type of a webhook
|
// HookType is the type of a webhook
|
||||||
type HookType = string
|
type HookType = string
|
||||||
|
|
||||||
|
@ -145,6 +145,7 @@ confirm_delete_selected=Potvrdit odstranění všech vybraných položek?
|
|||||||
|
|
||||||
name=Název
|
name=Název
|
||||||
value=Hodnota
|
value=Hodnota
|
||||||
|
readme=Readme
|
||||||
|
|
||||||
filter=Filtr
|
filter=Filtr
|
||||||
filter.clear=Vymazat filtr
|
filter.clear=Vymazat filtr
|
||||||
@ -243,6 +244,7 @@ license_desc=Vše je na <a target="_blank" rel="noopener noreferrer" href="%[1]s
|
|||||||
|
|
||||||
[install]
|
[install]
|
||||||
install=Instalace
|
install=Instalace
|
||||||
|
installing_desc=Probíhá instalace, čekejte prosím...
|
||||||
title=Výchozí konfigurace
|
title=Výchozí konfigurace
|
||||||
docker_helper=Pokud spouštíte Gitea v Dockeru, přečtěte si <a target="_blank" rel="noopener noreferrer" href="%s">dokumentaci</a>, než budete měnit jakákoliv nastavení.
|
docker_helper=Pokud spouštíte Gitea v Dockeru, přečtěte si <a target="_blank" rel="noopener noreferrer" href="%s">dokumentaci</a>, než budete měnit jakákoliv nastavení.
|
||||||
require_db_desc=Gitea requires MySQL, PostgreSQL, MSSQL, SQLite3 or TiDB (MySQL protocol).
|
require_db_desc=Gitea requires MySQL, PostgreSQL, MSSQL, SQLite3 or TiDB (MySQL protocol).
|
||||||
@ -459,6 +461,7 @@ authorize_application=Autorizovat aplikaci
|
|||||||
authorize_redirect_notice=Budete přesměrováni na %s, pokud autorizujete tuto aplikaci.
|
authorize_redirect_notice=Budete přesměrováni na %s, pokud autorizujete tuto aplikaci.
|
||||||
authorize_application_created_by=Tuto aplikaci vytvořil %s.
|
authorize_application_created_by=Tuto aplikaci vytvořil %s.
|
||||||
authorize_application_description=Pokud povolíte přístup, bude moci přistupovat a zapisovat do všech vašich informací o účtu včetně soukromých repozitářů a organizací.
|
authorize_application_description=Pokud povolíte přístup, bude moci přistupovat a zapisovat do všech vašich informací o účtu včetně soukromých repozitářů a organizací.
|
||||||
|
authorize_application_with_scopes=S rozsahy působnosti: %s
|
||||||
authorize_title=Autorizovat „%s“ pro přístup k vašemu účtu?
|
authorize_title=Autorizovat „%s“ pro přístup k vašemu účtu?
|
||||||
authorization_failed=Autorizace selhala
|
authorization_failed=Autorizace selhala
|
||||||
authorization_failed_desc=Autorizace selhala, protože jsme detekovali neplatný požadavek. Kontaktujte prosím správce aplikace, kterou jste se pokoušeli autorizovat.
|
authorization_failed_desc=Autorizace selhala, protože jsme detekovali neplatný požadavek. Kontaktujte prosím správce aplikace, kterou jste se pokoušeli autorizovat.
|
||||||
@ -765,6 +768,7 @@ uploaded_avatar_not_a_image=Nahraný soubor není obrázek.
|
|||||||
uploaded_avatar_is_too_big=Nahraný soubor (%d KiB) přesahuje maximální velikost (%d KiB).
|
uploaded_avatar_is_too_big=Nahraný soubor (%d KiB) přesahuje maximální velikost (%d KiB).
|
||||||
update_avatar_success=Vaše avatar byl aktualizován.
|
update_avatar_success=Vaše avatar byl aktualizován.
|
||||||
update_user_avatar_success=Uživatelův avatar byl aktualizován.
|
update_user_avatar_success=Uživatelův avatar byl aktualizován.
|
||||||
|
cropper_prompt=Před uložením můžete obrázek upravit. Upravený obrázek bude uložen jako PNG.
|
||||||
|
|
||||||
change_password=Aktualizovat heslo
|
change_password=Aktualizovat heslo
|
||||||
old_password=Stávající heslo
|
old_password=Stávající heslo
|
||||||
@ -1012,6 +1016,9 @@ new_repo_helper=Repozitář obsahuje všechny projektové soubory, včetně hist
|
|||||||
owner=Vlastník
|
owner=Vlastník
|
||||||
owner_helper=Některé organizace se nemusejí v seznamu zobrazit kvůli maximálnímu dosaženému počtu repozitářů.
|
owner_helper=Některé organizace se nemusejí v seznamu zobrazit kvůli maximálnímu dosaženému počtu repozitářů.
|
||||||
repo_name=Název repozitáře
|
repo_name=Název repozitáře
|
||||||
|
repo_name_profile_public_hint=.profile je speciální repozitář, který můžete použít k přidání souboru README.md do svého veřejného profilu organizace, který je viditelný pro každého. Ujistěte se, že je veřejný, a pro začátek jej inicializujte pomocí README v adresáři profilu.
|
||||||
|
repo_name_profile_private_hint=.profile-private je speciální repozitář, který můžete použít k přidání souboru README.md do profilu člena organizace, který je viditelný pouze pro členy organizace. Ujistěte se, že je soukromý, a pro začátek jej inicializujte pomocí README v adresáři profilu.
|
||||||
|
repo_name_helper=Dobrá jména repozitářů používají krátká, zapamatovatelná a unikátní klíčová slova. Repozitář s názvem „.profile“ nebo „.profile-private“ lze použít k přidání README.md pro uživatelský/organizační profil.
|
||||||
repo_size=Velikost repozitáře
|
repo_size=Velikost repozitáře
|
||||||
template=Šablona
|
template=Šablona
|
||||||
template_select=Vyberte šablonu.
|
template_select=Vyberte šablonu.
|
||||||
@ -1030,6 +1037,8 @@ fork_to_different_account=Rozštěpit na jiný účet
|
|||||||
fork_visibility_helper=Viditelnost rozštěpeného repozitáře nemůže být změněna.
|
fork_visibility_helper=Viditelnost rozštěpeného repozitáře nemůže být změněna.
|
||||||
fork_branch=Větev, která má být klonována pro fork
|
fork_branch=Větev, která má být klonována pro fork
|
||||||
all_branches=Všechny větve
|
all_branches=Všechny větve
|
||||||
|
view_all_branches=Zobrazit všechny větve
|
||||||
|
view_all_tags=Zobrazit všechny značky
|
||||||
fork_no_valid_owners=Tento repozitář nemůže být rozštěpen, protože neexistují žádní platní vlastníci.
|
fork_no_valid_owners=Tento repozitář nemůže být rozštěpen, protože neexistují žádní platní vlastníci.
|
||||||
fork.blocked_user=Nelze rozštěpit repozitář, protože jste blokováni majitelem repozitáře.
|
fork.blocked_user=Nelze rozštěpit repozitář, protože jste blokováni majitelem repozitáře.
|
||||||
use_template=Použít tuto šablonu
|
use_template=Použít tuto šablonu
|
||||||
@ -1041,6 +1050,8 @@ generate_repo=Generovat repozitář
|
|||||||
generate_from=Generovat z
|
generate_from=Generovat z
|
||||||
repo_desc=Popis
|
repo_desc=Popis
|
||||||
repo_desc_helper=Zadejte krátký popis (volitelné)
|
repo_desc_helper=Zadejte krátký popis (volitelné)
|
||||||
|
repo_no_desc=Nebyl uveden žádný popis
|
||||||
|
repo_lang=Jazyky
|
||||||
repo_gitignore_helper=Vyberte šablony .gitignore.
|
repo_gitignore_helper=Vyberte šablony .gitignore.
|
||||||
repo_gitignore_helper_desc=Vyberte soubory, které nechcete sledovat ze seznamu šablon pro běžné jazyky. Typické artefakty generované nástroji pro sestavení každého jazyka jsou ve výchozím stavu součástí .gitignore.
|
repo_gitignore_helper_desc=Vyberte soubory, které nechcete sledovat ze seznamu šablon pro běžné jazyky. Typické artefakty generované nástroji pro sestavení každého jazyka jsou ve výchozím stavu součástí .gitignore.
|
||||||
issue_labels=Štítky úkolů
|
issue_labels=Štítky úkolů
|
||||||
@ -1102,6 +1113,7 @@ delete_preexisting_success=Smazány nepřijaté soubory v %s
|
|||||||
blame_prior=Zobrazit blame před touto změnou
|
blame_prior=Zobrazit blame před touto změnou
|
||||||
blame.ignore_revs=Ignorování revizí v <a href="%s">.git-blame-ignorerevs</a>. Klikněte zde <a href="%s">pro obejití</a> a zobrazení normálního pohledu blame.
|
blame.ignore_revs=Ignorování revizí v <a href="%s">.git-blame-ignorerevs</a>. Klikněte zde <a href="%s">pro obejití</a> a zobrazení normálního pohledu blame.
|
||||||
blame.ignore_revs.failed=Nepodařilo se ignorovat revize v <a href="%s">.git-blame-ignore-revs</a>.
|
blame.ignore_revs.failed=Nepodařilo se ignorovat revize v <a href="%s">.git-blame-ignore-revs</a>.
|
||||||
|
user_search_tooltip=Zobrazí maximálně 30 uživatelů
|
||||||
|
|
||||||
tree_path_not_found_commit=Cesta %[1]s v commitu %[2]s neexistuje
|
tree_path_not_found_commit=Cesta %[1]s v commitu %[2]s neexistuje
|
||||||
tree_path_not_found_branch=Cesta %[1]s ve větvi %[2]s neexistuje
|
tree_path_not_found_branch=Cesta %[1]s ve větvi %[2]s neexistuje
|
||||||
@ -1223,6 +1235,7 @@ create_new_repo_command=Vytvořit nový repozitář na příkazové řádce
|
|||||||
push_exist_repo=Nahrání existujícího repozitáře z příkazové řádky
|
push_exist_repo=Nahrání existujícího repozitáře z příkazové řádky
|
||||||
empty_message=Tento repozitář nemá žádný obsah.
|
empty_message=Tento repozitář nemá žádný obsah.
|
||||||
broken_message=Data gitu, která jsou základem tohoto repozitáře, nelze číst. Kontaktujte správce této instance nebo smažte tento repositář.
|
broken_message=Data gitu, která jsou základem tohoto repozitáře, nelze číst. Kontaktujte správce této instance nebo smažte tento repositář.
|
||||||
|
no_branch=Tento repozitář nemá žádné větve.
|
||||||
|
|
||||||
code=Zdrojový kód
|
code=Zdrojový kód
|
||||||
code.desc=Přístup ke zdrojovým kódům, souborům, commitům a větvím.
|
code.desc=Přístup ke zdrojovým kódům, souborům, commitům a větvím.
|
||||||
@ -1520,6 +1533,8 @@ issues.filter_assignee=Zpracovatel
|
|||||||
issues.filter_assginee_no_select=Všichni zpracovatelé
|
issues.filter_assginee_no_select=Všichni zpracovatelé
|
||||||
issues.filter_assginee_no_assignee=Bez zpracovatele
|
issues.filter_assginee_no_assignee=Bez zpracovatele
|
||||||
issues.filter_poster=Autor
|
issues.filter_poster=Autor
|
||||||
|
issues.filter_user_placeholder=Hledat uživatele
|
||||||
|
issues.filter_user_no_select=Všichni uživatelé
|
||||||
issues.filter_type=Typ
|
issues.filter_type=Typ
|
||||||
issues.filter_type.all_issues=Všechny úkoly
|
issues.filter_type.all_issues=Všechny úkoly
|
||||||
issues.filter_type.assigned_to_you=Přiřazené vám
|
issues.filter_type.assigned_to_you=Přiřazené vám
|
||||||
@ -1664,12 +1679,25 @@ issues.delete.title=Smazat tento úkol?
|
|||||||
issues.delete.text=Opravdu chcete tento úkol smazat? (Tím se trvale odstraní veškerý obsah. Pokud jej hodláte archivovat, zvažte raději jeho uzavření.)
|
issues.delete.text=Opravdu chcete tento úkol smazat? (Tím se trvale odstraní veškerý obsah. Pokud jej hodláte archivovat, zvažte raději jeho uzavření.)
|
||||||
|
|
||||||
issues.tracker=Sledování času
|
issues.tracker=Sledování času
|
||||||
|
issues.timetracker_timer_start=Spustit časovač
|
||||||
|
issues.timetracker_timer_stop=Zastavit časovač
|
||||||
|
issues.timetracker_timer_discard=Zahodit časovač
|
||||||
|
issues.timetracker_timer_manually_add=Přidat čas
|
||||||
|
|
||||||
|
issues.time_estimate_set=Nastavit odhadovaný čas
|
||||||
|
issues.time_estimate_display=Odhad: %s
|
||||||
|
issues.change_time_estimate_at=změnil/a odhad času na <b>%s</b> %s
|
||||||
|
issues.remove_time_estimate_at=odstranil/a odhad času %s
|
||||||
|
issues.time_estimate_invalid=Formát odhadu času je neplatný
|
||||||
|
issues.start_tracking_history=započal/a práci %s
|
||||||
issues.tracker_auto_close=Časovač se automaticky zastaví po zavření tohoto úkolu
|
issues.tracker_auto_close=Časovač se automaticky zastaví po zavření tohoto úkolu
|
||||||
issues.tracking_already_started=`Již jste spustili sledování času na <a href="%s">jiném úkolu</a>!`
|
issues.tracking_already_started=`Již jste spustili sledování času na <a href="%s">jiném úkolu</a>!`
|
||||||
|
issues.stop_tracking_history=pracoval/a <b>%s</b> %s
|
||||||
issues.cancel_tracking_history=`zrušil/a sledování času %s`
|
issues.cancel_tracking_history=`zrušil/a sledování času %s`
|
||||||
issues.del_time=Odstranit tento časový záznam
|
issues.del_time=Odstranit tento časový záznam
|
||||||
|
issues.add_time_history=přidal/a strávený čas <b>%s</b> %s
|
||||||
issues.del_time_history=`odstranil/a strávený čas %s`
|
issues.del_time_history=`odstranil/a strávený čas %s`
|
||||||
|
issues.add_time_manually=Přidat čas ručně
|
||||||
issues.add_time_hours=Hodiny
|
issues.add_time_hours=Hodiny
|
||||||
issues.add_time_minutes=Minuty
|
issues.add_time_minutes=Minuty
|
||||||
issues.add_time_sum_to_small=Čas nebyl zadán.
|
issues.add_time_sum_to_small=Čas nebyl zadán.
|
||||||
@ -1922,6 +1950,9 @@ pulls.delete.title=Odstranit tento pull request?
|
|||||||
pulls.delete.text=Opravdu chcete tento pull request smazat? (Tím se trvale odstraní veškerý obsah. Pokud jej hodláte archivovat, zvažte raději jeho uzavření.)
|
pulls.delete.text=Opravdu chcete tento pull request smazat? (Tím se trvale odstraní veškerý obsah. Pokud jej hodláte archivovat, zvažte raději jeho uzavření.)
|
||||||
|
|
||||||
pulls.recently_pushed_new_branches=Nahráli jste větev <strong>%[1]s</strong> %[2]s
|
pulls.recently_pushed_new_branches=Nahráli jste větev <strong>%[1]s</strong> %[2]s
|
||||||
|
pulls.upstream_diverging_prompt_behind_1=Tato větev je %[1]d commit pozadu za %[2]s
|
||||||
|
pulls.upstream_diverging_prompt_behind_n=Tato větev je %[1]d commitů pozadu za %[2]s
|
||||||
|
pulls.upstream_diverging_prompt_base_newer=Hlavní větev %s má nové změny
|
||||||
|
|
||||||
pull.deleted_branch=(odstraněno):%s
|
pull.deleted_branch=(odstraněno):%s
|
||||||
pull.agit_documentation=Prohlédněte si dokumentaci o AGit
|
pull.agit_documentation=Prohlédněte si dokumentaci o AGit
|
||||||
@ -2595,6 +2626,9 @@ diff.image.overlay=Překrytí
|
|||||||
diff.has_escaped=Tento řádek má skryté znaky Unicode
|
diff.has_escaped=Tento řádek má skryté znaky Unicode
|
||||||
diff.show_file_tree=Zobrazit souborový strom
|
diff.show_file_tree=Zobrazit souborový strom
|
||||||
diff.hide_file_tree=Skrýt souborový strom
|
diff.hide_file_tree=Skrýt souborový strom
|
||||||
|
diff.submodule_added=Submodul %[1]s přidán v %[2]s
|
||||||
|
diff.submodule_deleted=Submodul %[1]s odebrán z %[2]s
|
||||||
|
diff.submodule_updated=Submodul %[1]s aktualizován: %[2]s
|
||||||
|
|
||||||
releases.desc=Sledování verzí projektu a souborů ke stažení.
|
releases.desc=Sledování verzí projektu a souborů ke stažení.
|
||||||
release.releases=Vydání
|
release.releases=Vydání
|
||||||
@ -2604,6 +2638,7 @@ release.new_release=Nové vydání
|
|||||||
release.draft=Koncept
|
release.draft=Koncept
|
||||||
release.prerelease=Předběžná verze
|
release.prerelease=Předběžná verze
|
||||||
release.stable=Stabilní
|
release.stable=Stabilní
|
||||||
|
release.latest=Nejnovější
|
||||||
release.compare=Porovnat
|
release.compare=Porovnat
|
||||||
release.edit=upravit
|
release.edit=upravit
|
||||||
release.ahead.commits=<strong>%d</strong> revizí
|
release.ahead.commits=<strong>%d</strong> revizí
|
||||||
@ -2832,6 +2867,9 @@ teams.invite.title=Byli jste pozváni do týmu <strong>%s</strong> v organizaci
|
|||||||
teams.invite.by=Pozvání od %s
|
teams.invite.by=Pozvání od %s
|
||||||
teams.invite.description=Pro připojení k týmu klikněte na tlačítko níže.
|
teams.invite.description=Pro připojení k týmu klikněte na tlačítko níže.
|
||||||
|
|
||||||
|
view_as_role=Zobrazit jako: %s
|
||||||
|
view_as_public_hint=Prohlížíte README jako veřejný uživatel.
|
||||||
|
view_as_member_hint=Prohlížíte README jako člen této organizace.
|
||||||
|
|
||||||
[admin]
|
[admin]
|
||||||
maintenance=Údržba
|
maintenance=Údržba
|
||||||
@ -3502,6 +3540,7 @@ versions=Verze
|
|||||||
versions.view_all=Zobrazit všechny
|
versions.view_all=Zobrazit všechny
|
||||||
dependency.id=ID
|
dependency.id=ID
|
||||||
dependency.version=Verze
|
dependency.version=Verze
|
||||||
|
search_in_external_registry=Hledat v %s
|
||||||
alpine.registry=Nastavte tento registr přidáním URL do <code>/etc/apk/repositories</code>:
|
alpine.registry=Nastavte tento registr přidáním URL do <code>/etc/apk/repositories</code>:
|
||||||
alpine.registry.key=Stáhněte si veřejný RSA klíč registru do složky <code>/etc/apk/keys/</code> pro ověření podpisu indexu:
|
alpine.registry.key=Stáhněte si veřejný RSA klíč registru do složky <code>/etc/apk/keys/</code> pro ověření podpisu indexu:
|
||||||
alpine.registry.info=Vyberte $branch a $repository ze seznamu níže.
|
alpine.registry.info=Vyberte $branch a $repository ze seznamu níže.
|
||||||
@ -3510,6 +3549,8 @@ alpine.repository=Informace o repozitáři
|
|||||||
alpine.repository.branches=Větve
|
alpine.repository.branches=Větve
|
||||||
alpine.repository.repositories=Repozitáře
|
alpine.repository.repositories=Repozitáře
|
||||||
alpine.repository.architectures=Architektury
|
alpine.repository.architectures=Architektury
|
||||||
|
arch.registry=Přidejte server se souvisejícím repozitářem a architekturou do <code>/etc/pacman.conf</code>:
|
||||||
|
arch.install=Synchronizovat balíček s pacman:
|
||||||
arch.repository=Informace o repozitáři
|
arch.repository=Informace o repozitáři
|
||||||
arch.repository.repositories=Repozitáře
|
arch.repository.repositories=Repozitáře
|
||||||
arch.repository.architectures=Architektury
|
arch.repository.architectures=Architektury
|
||||||
@ -3692,6 +3733,7 @@ runners.status.active=Aktivní
|
|||||||
runners.status.offline=Offline
|
runners.status.offline=Offline
|
||||||
runners.version=Verze
|
runners.version=Verze
|
||||||
runners.reset_registration_token=Resetovat registrační token
|
runners.reset_registration_token=Resetovat registrační token
|
||||||
|
runners.reset_registration_token_confirm=Chcete zneplatnit stávající token a vygenerovat nový?
|
||||||
runners.reset_registration_token_success=Registrační token runneru byl úspěšně obnoven
|
runners.reset_registration_token_success=Registrační token runneru byl úspěšně obnoven
|
||||||
|
|
||||||
runs.all_workflows=Všechny pracovní postupy
|
runs.all_workflows=Všechny pracovní postupy
|
||||||
@ -3724,6 +3766,7 @@ workflow.not_found=Pracovní postup „%s“ nebyl nalezen.
|
|||||||
workflow.run_success=Pracovní postup „%s“ proběhl úspěšně.
|
workflow.run_success=Pracovní postup „%s“ proběhl úspěšně.
|
||||||
workflow.from_ref=Použít pracovní postup od
|
workflow.from_ref=Použít pracovní postup od
|
||||||
workflow.has_workflow_dispatch=Tento pracovní postup má spouštěč události workflow_dispatch.
|
workflow.has_workflow_dispatch=Tento pracovní postup má spouštěč události workflow_dispatch.
|
||||||
|
workflow.has_no_workflow_dispatch=Pracovní postup „%s“ memá workflow_dispatch spouštěč.
|
||||||
|
|
||||||
need_approval_desc=Potřebujete schválení pro spuštění pracovních postupů pro rozštěpený pull request.
|
need_approval_desc=Potřebujete schválení pro spuštění pracovních postupů pro rozštěpený pull request.
|
||||||
|
|
||||||
@ -3743,6 +3786,8 @@ variables.creation.success=Proměnná „%s“ byla přidána.
|
|||||||
variables.update.failed=Úprava proměnné se nezdařila.
|
variables.update.failed=Úprava proměnné se nezdařila.
|
||||||
variables.update.success=Proměnná byla upravena.
|
variables.update.success=Proměnná byla upravena.
|
||||||
|
|
||||||
|
logs.always_auto_scroll=Vždy automaticky posouvat logy
|
||||||
|
logs.always_expand_running=Vždy rozšířit běžící logy
|
||||||
|
|
||||||
[projects]
|
[projects]
|
||||||
deleted.display_name=Odstraněný projekt
|
deleted.display_name=Odstraněný projekt
|
||||||
|
@ -1235,6 +1235,7 @@ create_new_repo_command = Creating a new repository on the command line
|
|||||||
push_exist_repo = Pushing an existing repository from the command line
|
push_exist_repo = Pushing an existing repository from the command line
|
||||||
empty_message = This repository does not contain any content.
|
empty_message = This repository does not contain any content.
|
||||||
broken_message = The Git data underlying this repository cannot be read. Contact the administrator of this instance or delete this repository.
|
broken_message = The Git data underlying this repository cannot be read. Contact the administrator of this instance or delete this repository.
|
||||||
|
no_branch = This repository doesn’t have any branches.
|
||||||
|
|
||||||
code = Code
|
code = Code
|
||||||
code.desc = Access source code, files, commits and branches.
|
code.desc = Access source code, files, commits and branches.
|
||||||
@ -2627,6 +2628,9 @@ diff.image.overlay = Overlay
|
|||||||
diff.has_escaped = This line has hidden Unicode characters
|
diff.has_escaped = This line has hidden Unicode characters
|
||||||
diff.show_file_tree = Show file tree
|
diff.show_file_tree = Show file tree
|
||||||
diff.hide_file_tree = Hide file tree
|
diff.hide_file_tree = Hide file tree
|
||||||
|
diff.submodule_added = Submodule %[1]s added at %[2]s
|
||||||
|
diff.submodule_deleted = Submodule %[1]s deleted from %[2]s
|
||||||
|
diff.submodule_updated = Submodule %[1]s updated: %[2]s
|
||||||
|
|
||||||
releases.desc = Track project versions and downloads.
|
releases.desc = Track project versions and downloads.
|
||||||
release.releases = Releases
|
release.releases = Releases
|
||||||
@ -3764,6 +3768,7 @@ workflow.not_found = Workflow '%s' not found.
|
|||||||
workflow.run_success = Workflow '%s' run successfully.
|
workflow.run_success = Workflow '%s' run successfully.
|
||||||
workflow.from_ref = Use workflow from
|
workflow.from_ref = Use workflow from
|
||||||
workflow.has_workflow_dispatch = This workflow has a workflow_dispatch event trigger.
|
workflow.has_workflow_dispatch = This workflow has a workflow_dispatch event trigger.
|
||||||
|
workflow.has_no_workflow_dispatch = Workflow '%s' has no workflow_dispatch event trigger.
|
||||||
|
|
||||||
need_approval_desc = Need approval to run workflows for fork pull request.
|
need_approval_desc = Need approval to run workflows for fork pull request.
|
||||||
|
|
||||||
|
@ -244,6 +244,7 @@ license_desc=Venez récupérer <a target="_blank" rel="noopener noreferrer" href
|
|||||||
|
|
||||||
[install]
|
[install]
|
||||||
install=Installation
|
install=Installation
|
||||||
|
installing_desc=Installation en cours, veuillez patienter…
|
||||||
title=Configuration initiale
|
title=Configuration initiale
|
||||||
docker_helper=Si vous exécutez Gitea dans Docker, veuillez lire la <a target="_blank" rel="noopener noreferrer" href="%s">documentation</a> avant de modifier les paramètres.
|
docker_helper=Si vous exécutez Gitea dans Docker, veuillez lire la <a target="_blank" rel="noopener noreferrer" href="%s">documentation</a> avant de modifier les paramètres.
|
||||||
require_db_desc=Gitea nécessite MySQL, PostgreSQL, MSSQL, SQLite3 ou TiDB (avec le protocole MySQL).
|
require_db_desc=Gitea nécessite MySQL, PostgreSQL, MSSQL, SQLite3 ou TiDB (avec le protocole MySQL).
|
||||||
@ -1015,6 +1016,9 @@ new_repo_helper=Un dépôt contient tous les fichiers d’un projet, ainsi que l
|
|||||||
owner=Propriétaire
|
owner=Propriétaire
|
||||||
owner_helper=Certaines organisations peuvent ne pas apparaître dans la liste déroulante en raison d'une limite maximale du nombre de dépôts.
|
owner_helper=Certaines organisations peuvent ne pas apparaître dans la liste déroulante en raison d'une limite maximale du nombre de dépôts.
|
||||||
repo_name=Nom du dépôt
|
repo_name=Nom du dépôt
|
||||||
|
repo_name_profile_public_hint=.profile est un dépôt spécial que vous pouvez utiliser pour ajouter un README.md à votre profil public d’organisation, visible à tout le monde. Assurez-vous qu’il soit public et initialisez-le avec un README dans le répertoire de profil pour commencer.
|
||||||
|
repo_name_profile_private_hint=.profile-private est un dépôt spécial que vous pouvez utiliser pour ajouter un README.md à votre profil d’organisation, visible uniquement aux membres de l’organisation. Assurez-vous qu’il soit privé et initialisez-le avec un README dans le répertoire de profil pour commencer.
|
||||||
|
repo_name_helper=Idéalement, le nom d’un dépôt devrait être court, mémorisable et unique. Vous pouvez personnaliser votre profil ou celui de votre organisation en créant un dépôt nommé « .profile » ou « .profile-private » et contenant un README.md.
|
||||||
repo_size=Taille du dépôt
|
repo_size=Taille du dépôt
|
||||||
template=Modèle
|
template=Modèle
|
||||||
template_select=Répliquer un modèle
|
template_select=Répliquer un modèle
|
||||||
@ -1231,6 +1235,7 @@ create_new_repo_command=Création d'un nouveau dépôt en ligne de commande
|
|||||||
push_exist_repo=Soumission d'un dépôt existant par ligne de commande
|
push_exist_repo=Soumission d'un dépôt existant par ligne de commande
|
||||||
empty_message=Ce dépôt n'a pas de contenu.
|
empty_message=Ce dépôt n'a pas de contenu.
|
||||||
broken_message=Les données git de ce dépôt ne peuvent pas être lues. Contactez l'administrateur de cette instance ou supprimez ce dépôt.
|
broken_message=Les données git de ce dépôt ne peuvent pas être lues. Contactez l'administrateur de cette instance ou supprimez ce dépôt.
|
||||||
|
no_branch=Ce dépôt n’a aucune branche.
|
||||||
|
|
||||||
code=Code
|
code=Code
|
||||||
code.desc=Accéder au code source, fichiers, révisions et branches.
|
code.desc=Accéder au code source, fichiers, révisions et branches.
|
||||||
@ -2860,6 +2865,9 @@ teams.invite.title=Vous avez été invité à rejoindre l'équipe <strong>%s</st
|
|||||||
teams.invite.by=Invité par %s
|
teams.invite.by=Invité par %s
|
||||||
teams.invite.description=Veuillez cliquer sur le bouton ci-dessous pour rejoindre l’équipe.
|
teams.invite.description=Veuillez cliquer sur le bouton ci-dessous pour rejoindre l’équipe.
|
||||||
|
|
||||||
|
view_as_role=Voir en tant que %s
|
||||||
|
view_as_public_hint=Vous visualisez le README en tant qu’utilisateur public.
|
||||||
|
view_as_member_hint=Vous visualisez le README en tant que membre de cette organisation.
|
||||||
|
|
||||||
[admin]
|
[admin]
|
||||||
maintenance=Maintenance
|
maintenance=Maintenance
|
||||||
@ -3530,6 +3538,7 @@ versions=Versions
|
|||||||
versions.view_all=Voir tout
|
versions.view_all=Voir tout
|
||||||
dependency.id=ID
|
dependency.id=ID
|
||||||
dependency.version=Version
|
dependency.version=Version
|
||||||
|
search_in_external_registry=Rechercher dans %s
|
||||||
alpine.registry=Configurez ce registre en ajoutant l’URL dans votre fichier <code>/etc/apk/repositories</code> :
|
alpine.registry=Configurez ce registre en ajoutant l’URL dans votre fichier <code>/etc/apk/repositories</code> :
|
||||||
alpine.registry.key=Téléchargez la clé RSA publique du registre dans le dossier <code>/etc/apk/keys/</code> pour vérifier la signature de l'index :
|
alpine.registry.key=Téléchargez la clé RSA publique du registre dans le dossier <code>/etc/apk/keys/</code> pour vérifier la signature de l'index :
|
||||||
alpine.registry.info=Choisissez $branch et $repository dans la liste ci-dessous.
|
alpine.registry.info=Choisissez $branch et $repository dans la liste ci-dessous.
|
||||||
@ -3722,6 +3731,7 @@ runners.status.active=Actif
|
|||||||
runners.status.offline=Hors-ligne
|
runners.status.offline=Hors-ligne
|
||||||
runners.version=Version
|
runners.version=Version
|
||||||
runners.reset_registration_token=Réinitialiser le jeton d'enregistrement
|
runners.reset_registration_token=Réinitialiser le jeton d'enregistrement
|
||||||
|
runners.reset_registration_token_confirm=Voulez-vous révoquer le jeton actuel et en générer un nouveau ?
|
||||||
runners.reset_registration_token_success=Le jeton d’inscription de l’exécuteur a été réinitialisé avec succès
|
runners.reset_registration_token_success=Le jeton d’inscription de l’exécuteur a été réinitialisé avec succès
|
||||||
|
|
||||||
runs.all_workflows=Tous les flux de travail
|
runs.all_workflows=Tous les flux de travail
|
||||||
@ -3754,6 +3764,7 @@ workflow.not_found=Flux de travail « %s » introuvable.
|
|||||||
workflow.run_success=Le flux de travail « %s » s’est correctement exécuté.
|
workflow.run_success=Le flux de travail « %s » s’est correctement exécuté.
|
||||||
workflow.from_ref=Utiliser le flux de travail depuis
|
workflow.from_ref=Utiliser le flux de travail depuis
|
||||||
workflow.has_workflow_dispatch=Ce flux de travail a un déclencheur d’événement workflow_dispatch.
|
workflow.has_workflow_dispatch=Ce flux de travail a un déclencheur d’événement workflow_dispatch.
|
||||||
|
workflow.has_no_workflow_dispatch=Le flux de travail %s n’a pas de déclencheur d’événement workflow_dispatch.
|
||||||
|
|
||||||
need_approval_desc=Besoin d’approbation pour exécuter des flux de travail pour une demande d’ajout de bifurcation.
|
need_approval_desc=Besoin d’approbation pour exécuter des flux de travail pour une demande d’ajout de bifurcation.
|
||||||
|
|
||||||
@ -3773,6 +3784,8 @@ variables.creation.success=La variable « %s » a été ajoutée.
|
|||||||
variables.update.failed=Impossible d’éditer la variable.
|
variables.update.failed=Impossible d’éditer la variable.
|
||||||
variables.update.success=La variable a bien été modifiée.
|
variables.update.success=La variable a bien été modifiée.
|
||||||
|
|
||||||
|
logs.always_auto_scroll=Toujours faire défiler les journaux automatiquement
|
||||||
|
logs.always_expand_running=Toujours développer les journaux en cours
|
||||||
|
|
||||||
[projects]
|
[projects]
|
||||||
deleted.display_name=Projet supprimé
|
deleted.display_name=Projet supprimé
|
||||||
|
@ -3763,6 +3763,8 @@ variables.creation.success=変数 "%s" を追加しました。
|
|||||||
variables.update.failed=変数を更新できませんでした。
|
variables.update.failed=変数を更新できませんでした。
|
||||||
variables.update.success=変数を更新しました。
|
variables.update.success=変数を更新しました。
|
||||||
|
|
||||||
|
logs.always_auto_scroll=常にログを自動スクロール
|
||||||
|
logs.always_expand_running=常に実行中のログを展開
|
||||||
|
|
||||||
[projects]
|
[projects]
|
||||||
deleted.display_name=削除されたプロジェクト
|
deleted.display_name=削除されたプロジェクト
|
||||||
|
@ -111,7 +111,7 @@ license=오픈 소스
|
|||||||
[install]
|
[install]
|
||||||
install=설치
|
install=설치
|
||||||
title=초기 설정
|
title=초기 설정
|
||||||
docker_helper="Gitea를 Docker에서 실행하려면 설정 전에 이 <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"%s\">문서</a>를 읽어보세요."
|
docker_helper=Gitea를 Docker에서 실행하려면 설정 전에 이 <a target="_blank" rel="noopener noreferrer" href="%s">문서</a>를 읽어보세요.
|
||||||
db_title=데이터베이스 설정
|
db_title=데이터베이스 설정
|
||||||
db_type=데이터베이스 유형
|
db_type=데이터베이스 유형
|
||||||
host=호스트
|
host=호스트
|
||||||
@ -436,8 +436,8 @@ manage_gpg_keys=GPG 키 관리
|
|||||||
add_key=키 추가
|
add_key=키 추가
|
||||||
ssh_desc=이러한 SSH 공용 키는 귀하의 계정과 연결되어 있습니다. 해당 개인 키는 당신의 저장소에 대한 전체 액세스를 가능하게 합니다.
|
ssh_desc=이러한 SSH 공용 키는 귀하의 계정과 연결되어 있습니다. 해당 개인 키는 당신의 저장소에 대한 전체 액세스를 가능하게 합니다.
|
||||||
gpg_desc=이러한 GPG 공개키는 당신의 계정과 연결되어있습니다. 커밋이 검증될 수 있도록 당신의 개인 키를 안전하게 유지하십시오.
|
gpg_desc=이러한 GPG 공개키는 당신의 계정과 연결되어있습니다. 커밋이 검증될 수 있도록 당신의 개인 키를 안전하게 유지하십시오.
|
||||||
ssh_helper="<strong>도움이 필요하세요?</strong> GitHub의 설명서를 참조하시기 바랍니다: <a href=\"%s\">SSH 키 생성하기</a> 또는 SSH를 사용할 때 <a href=\"%s\">일반적인 문제</a>"
|
ssh_helper=<strong>도움이 필요하세요?</strong> GitHub의 설명서를 참조하시기 바랍니다: <a href="%s">SSH 키 생성하기</a> 또는 SSH를 사용할 때 <a href="%s">일반적인 문제</a>
|
||||||
gpg_helper="<strong>도움이 필요하세요?</strong> GitHub의 설명서를 참조하시기 바랍니다: <a href=\"%s\">GPG키에 대하여</a>."
|
gpg_helper=<strong>도움이 필요하세요?</strong> GitHub의 설명서를 참조하시기 바랍니다: <a href="%s">GPG키에 대하여</a>.
|
||||||
add_new_key=SSH 키 추가
|
add_new_key=SSH 키 추가
|
||||||
add_new_gpg_key=GPG 키 추가
|
add_new_gpg_key=GPG 키 추가
|
||||||
gpg_key_id_used=같은 ID의 GPG 공개키가 이미 존재합니다.
|
gpg_key_id_used=같은 ID의 GPG 공개키가 이미 존재합니다.
|
||||||
@ -538,7 +538,7 @@ template_helper=템플릿으로 저장소 만들기
|
|||||||
visibility=가시성
|
visibility=가시성
|
||||||
visibility_helper_forced=사이트 관리자가 새 레포지토리에 대해 비공개로만 생성되도록 하였습니다.
|
visibility_helper_forced=사이트 관리자가 새 레포지토리에 대해 비공개로만 생성되도록 하였습니다.
|
||||||
visibility_fork_helper=(변경사항을 적용하는 경우 모든 포크가 영향을 받게 됩니다.)
|
visibility_fork_helper=(변경사항을 적용하는 경우 모든 포크가 영향을 받게 됩니다.)
|
||||||
clone_helper="클론하는데에 도움이 필요하면 <a target=\"_blank\" href=\"%s\">Help</a>에 방문하세요."
|
clone_helper=클론하는데에 도움이 필요하면 <a target="_blank" href="%s">Help</a>에 방문하세요.
|
||||||
fork_repo=저장소 포크
|
fork_repo=저장소 포크
|
||||||
fork_from=원본 프로젝트 :
|
fork_from=원본 프로젝트 :
|
||||||
fork_visibility_helper=포크된 저장소의 가시성은 변경하실 수 없습니다.
|
fork_visibility_helper=포크된 저장소의 가시성은 변경하실 수 없습니다.
|
||||||
@ -640,7 +640,7 @@ editor.or=혹은
|
|||||||
editor.cancel_lower=취소
|
editor.cancel_lower=취소
|
||||||
editor.commit_changes=변경 내용을 커밋
|
editor.commit_changes=변경 내용을 커밋
|
||||||
editor.commit_message_desc=선택적 확장 설명을 추가...
|
editor.commit_message_desc=선택적 확장 설명을 추가...
|
||||||
editor.commit_directly_to_this_branch="<strong class=\"branch-name\">%s</strong> 브랜치에서 직접 커밋해주세요."
|
editor.commit_directly_to_this_branch=<strong class="branch-name">%s</strong> 브랜치에서 직접 커밋해주세요.
|
||||||
editor.create_new_branch=이 커밋에 대한 <strong>새로운 브랜치</strong>를 만들고 끌어오기 요청을 시작합니다.
|
editor.create_new_branch=이 커밋에 대한 <strong>새로운 브랜치</strong>를 만들고 끌어오기 요청을 시작합니다.
|
||||||
editor.new_branch_name_desc=새로운 브랜치 명...
|
editor.new_branch_name_desc=새로운 브랜치 명...
|
||||||
editor.cancel=취소
|
editor.cancel=취소
|
||||||
@ -667,7 +667,7 @@ ext_issues.desc=외부 이슈 트래커 연결.
|
|||||||
projects.description_placeholder=설명
|
projects.description_placeholder=설명
|
||||||
projects.title=제목
|
projects.title=제목
|
||||||
projects.new=새 프로젝트
|
projects.new=새 프로젝트
|
||||||
projects.template.desc="템플릿"
|
projects.template.desc=템플릿
|
||||||
projects.column.edit_title=이름
|
projects.column.edit_title=이름
|
||||||
projects.column.new_title=이름
|
projects.column.new_title=이름
|
||||||
|
|
||||||
@ -731,7 +731,7 @@ issues.action_milestone=마일스톤
|
|||||||
issues.action_milestone_no_select=마일스톤 없음
|
issues.action_milestone_no_select=마일스톤 없음
|
||||||
issues.action_assignee=담당자
|
issues.action_assignee=담당자
|
||||||
issues.action_assignee_no_select=담당자 없음
|
issues.action_assignee_no_select=담당자 없음
|
||||||
issues.opened_by="<a href=\"%[2]s\"> %[3]s</a>가 %[1]s을 오픈"
|
issues.opened_by=<a href="%[2]s"> %[3]s</a>가 %[1]s을 오픈
|
||||||
issues.previous=이전
|
issues.previous=이전
|
||||||
issues.next=다음
|
issues.next=다음
|
||||||
issues.open_title=오픈
|
issues.open_title=오픈
|
||||||
@ -747,7 +747,7 @@ issues.create_comment=코멘트
|
|||||||
issues.commit_ref_at=` 커밋 <a id="%[1]s" href="#%[1]s">%[2]s</a>에서 이 이슈 언급`
|
issues.commit_ref_at=` 커밋 <a id="%[1]s" href="#%[1]s">%[2]s</a>에서 이 이슈 언급`
|
||||||
issues.role.owner=소유자
|
issues.role.owner=소유자
|
||||||
issues.role.member=멤버
|
issues.role.member=멤버
|
||||||
issues.sign_in_require_desc="<a href=\"%s\">로그인</a>하여 이 대화에 참여"
|
issues.sign_in_require_desc=<a href="%s">로그인</a>하여 이 대화에 참여
|
||||||
issues.edit=수정
|
issues.edit=수정
|
||||||
issues.cancel=취소
|
issues.cancel=취소
|
||||||
issues.save=저장
|
issues.save=저장
|
||||||
@ -780,9 +780,9 @@ issues.time_spent_total=총 경과된 시간
|
|||||||
issues.time_spent_from_all_authors=`총 경과된 시간: %s`
|
issues.time_spent_from_all_authors=`총 경과된 시간: %s`
|
||||||
|
|
||||||
issues.due_date=마감일
|
issues.due_date=마감일
|
||||||
issues.invalid_due_date_format="마감일은 반드시 'yyyy-mm-dd' 형식이어야 합니다."
|
issues.invalid_due_date_format=마감일은 반드시 'yyyy-mm-dd' 형식이어야 합니다.
|
||||||
issues.error_modifying_due_date="마감일 수정을 실패하였습니다."
|
issues.error_modifying_due_date=마감일 수정을 실패하였습니다.
|
||||||
issues.error_removing_due_date="마감일 삭제를 실패하였습니다."
|
issues.error_removing_due_date=마감일 삭제를 실패하였습니다.
|
||||||
issues.due_date_form=yyyy-mm-dd
|
issues.due_date_form=yyyy-mm-dd
|
||||||
issues.due_date_form_add=마감일 추가
|
issues.due_date_form_add=마감일 추가
|
||||||
issues.due_date_form_edit=편집
|
issues.due_date_form_edit=편집
|
||||||
@ -790,8 +790,8 @@ issues.due_date_form_remove=삭제
|
|||||||
issues.due_date_not_set=마감일이 설정되지 않았습니다.
|
issues.due_date_not_set=마감일이 설정되지 않았습니다.
|
||||||
issues.due_date_added=마감일 %s 를 추가 %s
|
issues.due_date_added=마감일 %s 를 추가 %s
|
||||||
issues.due_date_remove=%s %s 마감일이 삭제되었습니다.
|
issues.due_date_remove=%s %s 마감일이 삭제되었습니다.
|
||||||
issues.due_date_overdue="기한 초과"
|
issues.due_date_overdue=기한 초과
|
||||||
issues.due_date_invalid="기한이 올바르지 않거나 범위를 벗어났습니다. 'yyyy-mm-dd'형식을 사용해주십시오."
|
issues.due_date_invalid=기한이 올바르지 않거나 범위를 벗어났습니다. 'yyyy-mm-dd'형식을 사용해주십시오.
|
||||||
issues.dependency.title=의존성
|
issues.dependency.title=의존성
|
||||||
issues.dependency.add=의존성 추가...
|
issues.dependency.add=의존성 추가...
|
||||||
issues.dependency.cancel=취소
|
issues.dependency.cancel=취소
|
||||||
@ -809,7 +809,7 @@ issues.dependency.add_error_dep_exists=의존성이 이미 존재합니다.
|
|||||||
issues.dependency.add_error_dep_not_same_repo=두 이슈는 같은 레포지토리 안에 있어야 합니다.
|
issues.dependency.add_error_dep_not_same_repo=두 이슈는 같은 레포지토리 안에 있어야 합니다.
|
||||||
issues.review.self.approval=자신의 풀 리퀘스트를 승인할 수 없습니다.
|
issues.review.self.approval=자신의 풀 리퀘스트를 승인할 수 없습니다.
|
||||||
issues.review.self.rejection=자신의 풀 리퀘스트에 대한 변경을 요청할 수 없습니다.
|
issues.review.self.rejection=자신의 풀 리퀘스트에 대한 변경을 요청할 수 없습니다.
|
||||||
issues.review.approve="이 변경사항을 승인하였습니다. %s"
|
issues.review.approve=이 변경사항을 승인하였습니다. %s
|
||||||
issues.review.pending=보류
|
issues.review.pending=보류
|
||||||
issues.review.review=검토
|
issues.review.review=검토
|
||||||
issues.review.reviewers=리뷰어
|
issues.review.reviewers=리뷰어
|
||||||
@ -824,7 +824,7 @@ pulls.compare_base=병합하기
|
|||||||
pulls.compare_compare=다음으로부터 풀
|
pulls.compare_compare=다음으로부터 풀
|
||||||
pulls.filter_branch=Filter Branch
|
pulls.filter_branch=Filter Branch
|
||||||
pulls.create=풀 리퀘스트 생성
|
pulls.create=풀 리퀘스트 생성
|
||||||
pulls.title_desc="<code>%[2]s</code> 에서 <code id=\"branch_target\">%[3]s</code> 로 %[1]d commits 를 머지하려 합니다"
|
pulls.title_desc=<code>%[2]s</code> 에서 <code id="branch_target">%[3]s</code> 로 %[1]d commits 를 머지하려 합니다
|
||||||
pulls.merged_title_desc=<code>%[2]s</code> 에서 <code>%[3]s</code> 로 %[1]d commits 를 머지했습니다 %[4]s
|
pulls.merged_title_desc=<code>%[2]s</code> 에서 <code>%[3]s</code> 로 %[1]d commits 를 머지했습니다 %[4]s
|
||||||
pulls.tab_conversation=대화
|
pulls.tab_conversation=대화
|
||||||
pulls.tab_commits=커밋
|
pulls.tab_commits=커밋
|
||||||
@ -855,7 +855,7 @@ milestones.title=타이틀
|
|||||||
milestones.desc=설명
|
milestones.desc=설명
|
||||||
milestones.due_date=기한 (선택 사항)
|
milestones.due_date=기한 (선택 사항)
|
||||||
milestones.clear=지우기
|
milestones.clear=지우기
|
||||||
milestones.invalid_due_date_format="마감일은 반드시 'yyyy-mm-dd' 형식이어야 합니다."
|
milestones.invalid_due_date_format=마감일은 반드시 'yyyy-mm-dd' 형식이어야 합니다.
|
||||||
milestones.edit=마일스톤 편집
|
milestones.edit=마일스톤 편집
|
||||||
milestones.cancel=취소
|
milestones.cancel=취소
|
||||||
milestones.modify=마일스톤 갱신
|
milestones.modify=마일스톤 갱신
|
||||||
|
@ -495,7 +495,7 @@ register_notify.text_3=Se esta conta foi criada para si, <a href="%s">defina a s
|
|||||||
|
|
||||||
reset_password=Recupere a sua conta
|
reset_password=Recupere a sua conta
|
||||||
reset_password.title=%s, você pediu para recuperar a sua conta
|
reset_password.title=%s, você pediu para recuperar a sua conta
|
||||||
reset_password.text=Por favor clique na seguinte ligação para recuperar a sua conta em <b>%s</b>:
|
reset_password.text=Para recuperar a sua conta, clique na ligação seguinte (válida por <b>%s</b>):
|
||||||
|
|
||||||
register_success=Inscrição bem sucedida
|
register_success=Inscrição bem sucedida
|
||||||
|
|
||||||
@ -1017,6 +1017,8 @@ owner=Proprietário(a)
|
|||||||
owner_helper=Algumas organizações podem não aparecer na lista suspensa devido a um limite máximo de contagem de repositórios.
|
owner_helper=Algumas organizações podem não aparecer na lista suspensa devido a um limite máximo de contagem de repositórios.
|
||||||
repo_name=Nome do repositório
|
repo_name=Nome do repositório
|
||||||
repo_name_profile_public_hint=.profile é um repositório especial que pode usar para adicionar README.md ao seu perfil público da organização, visível para qualquer pessoa. Certifique-se que é público e inicialize-o com um README na pasta do perfil para começar.
|
repo_name_profile_public_hint=.profile é um repositório especial que pode usar para adicionar README.md ao seu perfil público da organização, visível para qualquer pessoa. Certifique-se que é público e inicialize-o com um README na pasta do perfil para começar.
|
||||||
|
repo_name_profile_private_hint=.profile-private é um repositório especial que pode usar para adicionar um README.md ao seu perfil de membro da organização, visível apenas para membros da organização. Certifique-se que é privado e inicialize-o com um README na pasta de perfil para começar.
|
||||||
|
repo_name_helper=Bons nomes de repositórios usam palavras-chave curtas, memorizáveis e únicas. Um repositório chamado ".profile" ou ".profile-private" pode ser usado para adicionar um README.md ao perfil do utilizador ou da organização.
|
||||||
repo_size=Tamanho do repositório
|
repo_size=Tamanho do repositório
|
||||||
template=Modelo
|
template=Modelo
|
||||||
template_select=Escolha um modelo.
|
template_select=Escolha um modelo.
|
||||||
@ -1233,6 +1235,7 @@ create_new_repo_command=Criando um novo repositório na linha de comandos
|
|||||||
push_exist_repo=Enviando, pela linha de comandos, um repositório existente
|
push_exist_repo=Enviando, pela linha de comandos, um repositório existente
|
||||||
empty_message=Este repositório não contém qualquer conteúdo.
|
empty_message=Este repositório não contém qualquer conteúdo.
|
||||||
broken_message=Os dados Git subjacentes a este repositório não podem ser lidos. Contacte o administrador desta instância ou elimine este repositório.
|
broken_message=Os dados Git subjacentes a este repositório não podem ser lidos. Contacte o administrador desta instância ou elimine este repositório.
|
||||||
|
no_branch=Este repositório não tem quaisquer ramos.
|
||||||
|
|
||||||
code=Código
|
code=Código
|
||||||
code.desc=Aceder ao código fonte, ficheiros, cometimentos e ramos.
|
code.desc=Aceder ao código fonte, ficheiros, cometimentos e ramos.
|
||||||
@ -2624,6 +2627,9 @@ diff.image.overlay=Sobrepor
|
|||||||
diff.has_escaped=Esta linha tem caracteres unicode escondidos
|
diff.has_escaped=Esta linha tem caracteres unicode escondidos
|
||||||
diff.show_file_tree=Mostrar árvore de ficheiros
|
diff.show_file_tree=Mostrar árvore de ficheiros
|
||||||
diff.hide_file_tree=Esconder árvore de ficheiros
|
diff.hide_file_tree=Esconder árvore de ficheiros
|
||||||
|
diff.submodule_added=Submódulo %[1]s adicionado em %[2]s
|
||||||
|
diff.submodule_deleted=Submódulo %[1]s eliminado de %[2]s
|
||||||
|
diff.submodule_updated=Submódulo %[1]s modificado: %[2]s
|
||||||
|
|
||||||
releases.desc=Acompanhe as versões e as descargas do repositório.
|
releases.desc=Acompanhe as versões e as descargas do repositório.
|
||||||
release.releases=Lançamentos
|
release.releases=Lançamentos
|
||||||
@ -3761,6 +3767,7 @@ workflow.not_found=A sequência de trabalho '%s' não foi encontrada.
|
|||||||
workflow.run_success=A sequência de trabalho '%s' foi executada com sucesso.
|
workflow.run_success=A sequência de trabalho '%s' foi executada com sucesso.
|
||||||
workflow.from_ref=Usar sequência de trabalho de
|
workflow.from_ref=Usar sequência de trabalho de
|
||||||
workflow.has_workflow_dispatch=Esta sequência de trabalho tem um despoletador de eventos workflow_dispatch.
|
workflow.has_workflow_dispatch=Esta sequência de trabalho tem um despoletador de eventos workflow_dispatch.
|
||||||
|
workflow.has_no_workflow_dispatch=A sequência de trabalho '%s' não tem nenhum despoletador de eventos workflow_dispatch.
|
||||||
|
|
||||||
need_approval_desc=É necessária aprovação para executar sequências de trabalho para a derivação do pedido de integração.
|
need_approval_desc=É necessária aprovação para executar sequências de trabalho para a derivação do pedido de integração.
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ func UploadPackageFile(ctx *context.Context) {
|
|||||||
|
|
||||||
pck, err := alpine_module.ParsePackage(buf)
|
pck, err := alpine_module.ParsePackage(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrInvalidArgument) || err == io.EOF {
|
if errors.Is(err, util.ErrInvalidArgument) || errors.Is(err, io.EOF) {
|
||||||
apiError(ctx, http.StatusBadRequest, err)
|
apiError(ctx, http.StatusBadRequest, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
@ -138,7 +138,8 @@ func CommonRoutes() *web.Router {
|
|||||||
}, reqPackageAccess(perm.AccessModeRead))
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/arch", func() {
|
r.Group("/arch", func() {
|
||||||
r.Methods("HEAD,GET", "/repository.key", arch.GetRepositoryKey)
|
r.Methods("HEAD,GET", "/repository.key", arch.GetRepositoryKey)
|
||||||
r.PathGroup("*", func(g *web.RouterPathGroup) {
|
r.Methods("PUT", "" /* no repository */, reqPackageAccess(perm.AccessModeWrite), arch.UploadPackageFile)
|
||||||
|
r.PathGroup("/*", func(g *web.RouterPathGroup) {
|
||||||
g.MatchPath("PUT", "/<repository:*>", reqPackageAccess(perm.AccessModeWrite), arch.UploadPackageFile)
|
g.MatchPath("PUT", "/<repository:*>", reqPackageAccess(perm.AccessModeWrite), arch.UploadPackageFile)
|
||||||
g.MatchPath("HEAD,GET", "/<repository:*>/<architecture>/<filename>", arch.GetPackageOrRepositoryFile)
|
g.MatchPath("HEAD,GET", "/<repository:*>/<architecture>/<filename>", arch.GetPackageOrRepositoryFile)
|
||||||
g.MatchPath("DELETE", "/<repository:*>/<name>/<version>/<architecture>", reqPackageAccess(perm.AccessModeWrite), arch.DeletePackageVersion)
|
g.MatchPath("DELETE", "/<repository:*>/<name>/<version>/<architecture>", reqPackageAccess(perm.AccessModeWrite), arch.DeletePackageVersion)
|
||||||
@ -698,150 +699,28 @@ func ContainerRoutes() *web.Router {
|
|||||||
})
|
})
|
||||||
r.Get("/_catalog", container.ReqContainerAccess, container.GetRepositoryList)
|
r.Get("/_catalog", container.ReqContainerAccess, container.GetRepositoryList)
|
||||||
r.Group("/{username}", func() {
|
r.Group("/{username}", func() {
|
||||||
r.Group("/{image}", func() {
|
r.PathGroup("/*", func(g *web.RouterPathGroup) {
|
||||||
r.Group("/blobs/uploads", func() {
|
g.MatchPath("POST", "/<image:*>/blobs/uploads", reqPackageAccess(perm.AccessModeWrite), container.VerifyImageName, container.InitiateUploadBlob)
|
||||||
r.Post("", container.InitiateUploadBlob)
|
g.MatchPath("GET", "/<image:*>/tags/list", container.VerifyImageName, container.GetTagList)
|
||||||
r.Group("/{uuid}", func() {
|
g.MatchPath("GET,PATCH,PUT,DELETE", `/<image:*>/blobs/uploads/<uuid:[-.=\w]+>`, reqPackageAccess(perm.AccessModeWrite), container.VerifyImageName, func(ctx *context.Context) {
|
||||||
r.Get("", container.GetUploadBlob)
|
if ctx.Req.Method == http.MethodGet {
|
||||||
r.Patch("", container.UploadBlob)
|
|
||||||
r.Put("", container.EndUploadBlob)
|
|
||||||
r.Delete("", container.CancelUploadBlob)
|
|
||||||
})
|
|
||||||
}, reqPackageAccess(perm.AccessModeWrite))
|
|
||||||
r.Group("/blobs/{digest}", func() {
|
|
||||||
r.Head("", container.HeadBlob)
|
|
||||||
r.Get("", container.GetBlob)
|
|
||||||
r.Delete("", reqPackageAccess(perm.AccessModeWrite), container.DeleteBlob)
|
|
||||||
})
|
|
||||||
r.Group("/manifests/{reference}", func() {
|
|
||||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), container.UploadManifest)
|
|
||||||
r.Head("", container.HeadManifest)
|
|
||||||
r.Get("", container.GetManifest)
|
|
||||||
r.Delete("", reqPackageAccess(perm.AccessModeWrite), container.DeleteManifest)
|
|
||||||
})
|
|
||||||
r.Get("/tags/list", container.GetTagList)
|
|
||||||
}, container.VerifyImageName)
|
|
||||||
|
|
||||||
var (
|
|
||||||
blobsUploadsPattern = regexp.MustCompile(`\A(.+)/blobs/uploads/([a-zA-Z0-9-_.=]+)\z`)
|
|
||||||
blobsPattern = regexp.MustCompile(`\A(.+)/blobs/([^/]+)\z`)
|
|
||||||
manifestsPattern = regexp.MustCompile(`\A(.+)/manifests/([^/]+)\z`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Manual mapping of routes because {image} can contain slashes which chi does not support
|
|
||||||
r.Methods("HEAD,GET,POST,PUT,PATCH,DELETE", "/*", func(ctx *context.Context) {
|
|
||||||
path := ctx.PathParam("*")
|
|
||||||
isHead := ctx.Req.Method == "HEAD"
|
|
||||||
isGet := ctx.Req.Method == "GET"
|
|
||||||
isPost := ctx.Req.Method == "POST"
|
|
||||||
isPut := ctx.Req.Method == "PUT"
|
|
||||||
isPatch := ctx.Req.Method == "PATCH"
|
|
||||||
isDelete := ctx.Req.Method == "DELETE"
|
|
||||||
|
|
||||||
if isPost && strings.HasSuffix(path, "/blobs/uploads") {
|
|
||||||
reqPackageAccess(perm.AccessModeWrite)(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetPathParam("image", path[:len(path)-14])
|
|
||||||
container.VerifyImageName(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
container.InitiateUploadBlob(ctx)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if isGet && strings.HasSuffix(path, "/tags/list") {
|
|
||||||
ctx.SetPathParam("image", path[:len(path)-10])
|
|
||||||
container.VerifyImageName(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
container.GetTagList(ctx)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
m := blobsUploadsPattern.FindStringSubmatch(path)
|
|
||||||
if len(m) == 3 && (isGet || isPut || isPatch || isDelete) {
|
|
||||||
reqPackageAccess(perm.AccessModeWrite)(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetPathParam("image", m[1])
|
|
||||||
container.VerifyImageName(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetPathParam("uuid", m[2])
|
|
||||||
|
|
||||||
if isGet {
|
|
||||||
container.GetUploadBlob(ctx)
|
container.GetUploadBlob(ctx)
|
||||||
} else if isPatch {
|
} else if ctx.Req.Method == http.MethodPatch {
|
||||||
container.UploadBlob(ctx)
|
container.UploadBlob(ctx)
|
||||||
} else if isPut {
|
} else if ctx.Req.Method == http.MethodPut {
|
||||||
container.EndUploadBlob(ctx)
|
container.EndUploadBlob(ctx)
|
||||||
} else {
|
} else /* DELETE */ {
|
||||||
container.CancelUploadBlob(ctx)
|
container.CancelUploadBlob(ctx)
|
||||||
}
|
}
|
||||||
return
|
})
|
||||||
}
|
g.MatchPath("HEAD", `/<image:*>/blobs/<digest>`, container.VerifyImageName, container.HeadBlob)
|
||||||
m = blobsPattern.FindStringSubmatch(path)
|
g.MatchPath("GET", `/<image:*>/blobs/<digest>`, container.VerifyImageName, container.GetBlob)
|
||||||
if len(m) == 3 && (isHead || isGet || isDelete) {
|
g.MatchPath("DELETE", `/<image:*>/blobs/<digest>`, container.VerifyImageName, reqPackageAccess(perm.AccessModeWrite), container.DeleteBlob)
|
||||||
ctx.SetPathParam("image", m[1])
|
|
||||||
container.VerifyImageName(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetPathParam("digest", m[2])
|
g.MatchPath("HEAD", `/<image:*>/manifests/<reference>`, container.VerifyImageName, container.HeadManifest)
|
||||||
|
g.MatchPath("GET", `/<image:*>/manifests/<reference>`, container.VerifyImageName, container.GetManifest)
|
||||||
if isHead {
|
g.MatchPath("PUT", `/<image:*>/manifests/<reference>`, container.VerifyImageName, reqPackageAccess(perm.AccessModeWrite), container.UploadManifest)
|
||||||
container.HeadBlob(ctx)
|
g.MatchPath("DELETE", `/<image:*>/manifests/<reference>`, container.VerifyImageName, reqPackageAccess(perm.AccessModeWrite), container.DeleteManifest)
|
||||||
} else if isGet {
|
|
||||||
container.GetBlob(ctx)
|
|
||||||
} else {
|
|
||||||
reqPackageAccess(perm.AccessModeWrite)(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container.DeleteBlob(ctx)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m = manifestsPattern.FindStringSubmatch(path)
|
|
||||||
if len(m) == 3 && (isHead || isGet || isPut || isDelete) {
|
|
||||||
ctx.SetPathParam("image", m[1])
|
|
||||||
container.VerifyImageName(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetPathParam("reference", m[2])
|
|
||||||
|
|
||||||
if isHead {
|
|
||||||
container.HeadManifest(ctx)
|
|
||||||
} else if isGet {
|
|
||||||
container.GetManifest(ctx)
|
|
||||||
} else {
|
|
||||||
reqPackageAccess(perm.AccessModeWrite)(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if isPut {
|
|
||||||
container.UploadManifest(ctx)
|
|
||||||
} else {
|
|
||||||
container.DeleteManifest(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Status(http.StatusNotFound)
|
|
||||||
})
|
})
|
||||||
}, container.ReqContainerAccess, context.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
|
}, container.ReqContainerAccess, context.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func UploadPackageFile(ctx *context.Context) {
|
|||||||
|
|
||||||
pck, err := arch_module.ParsePackage(buf)
|
pck, err := arch_module.ParsePackage(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrInvalidArgument) || err == io.EOF {
|
if errors.Is(err, util.ErrInvalidArgument) || errors.Is(err, io.EOF) {
|
||||||
apiError(ctx, http.StatusBadRequest, err)
|
apiError(ctx, http.StatusBadRequest, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
@ -181,7 +181,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -276,7 +276,7 @@ func UnyankPackage(ctx *context.Context) {
|
|||||||
func yankPackage(ctx *context.Context, yank bool) {
|
func yankPackage(ctx *context.Context, yank bool) {
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeCargo, ctx.PathParam("package"), ctx.PathParam("version"))
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeCargo, ctx.PathParam("package"), ctx.PathParam("version"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ func PackageVersionMetadata(ctx *context.Context) {
|
|||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeChef, packageName, packageVersion)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeChef, packageName, packageVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -327,7 +327,7 @@ func UploadPackage(ctx *context.Context) {
|
|||||||
func DownloadPackage(ctx *context.Context) {
|
func DownloadPackage(ctx *context.Context) {
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeChef, ctx.PathParam("name"), ctx.PathParam("version"))
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeChef, ctx.PathParam("name"), ctx.PathParam("version"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -368,7 +368,7 @@ func DeletePackageVersion(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
@ -176,7 +176,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ package conan
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
std_ctx "context"
|
std_ctx "context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -183,7 +184,7 @@ func serveSnapshot(ctx *context.Context, fileKey string) {
|
|||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -244,7 +245,7 @@ func serveDownloadURLs(ctx *context.Context, fileKey, downloadURL string) {
|
|||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -493,7 +494,7 @@ func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKe
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -509,7 +510,7 @@ func DeleteRecipeV1(ctx *context.Context) {
|
|||||||
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
|
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
|
||||||
|
|
||||||
if err := deleteRecipeOrPackage(ctx, rref, true, nil, false); err != nil {
|
if err := deleteRecipeOrPackage(ctx, rref, true, nil, false); err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == conan_model.ErrPackageReferenceNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -524,7 +525,7 @@ func DeleteRecipeV2(ctx *context.Context) {
|
|||||||
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
|
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
|
||||||
|
|
||||||
if err := deleteRecipeOrPackage(ctx, rref, rref.Revision == "", nil, false); err != nil {
|
if err := deleteRecipeOrPackage(ctx, rref, rref.Revision == "", nil, false); err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == conan_model.ErrPackageReferenceNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -571,7 +572,7 @@ func DeletePackageV1(ctx *context.Context) {
|
|||||||
for _, reference := range references {
|
for _, reference := range references {
|
||||||
pref, _ := conan_module.NewPackageReference(currentRref, reference.Value, conan_module.DefaultRevision)
|
pref, _ := conan_module.NewPackageReference(currentRref, reference.Value, conan_module.DefaultRevision)
|
||||||
if err := deleteRecipeOrPackage(ctx, currentRref, true, pref, true); err != nil {
|
if err := deleteRecipeOrPackage(ctx, currentRref, true, pref, true); err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == conan_model.ErrPackageReferenceNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -590,7 +591,7 @@ func DeletePackageV2(ctx *context.Context) {
|
|||||||
|
|
||||||
if pref != nil { // has package reference
|
if pref != nil { // has package reference
|
||||||
if err := deleteRecipeOrPackage(ctx, rref, false, pref, pref.Revision == ""); err != nil {
|
if err := deleteRecipeOrPackage(ctx, rref, false, pref, pref.Revision == ""); err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == conan_model.ErrPackageReferenceNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -615,7 +616,7 @@ func DeletePackageV2(ctx *context.Context) {
|
|||||||
pref, _ := conan_module.NewPackageReference(rref, reference.Value, conan_module.DefaultRevision)
|
pref, _ := conan_module.NewPackageReference(rref, reference.Value, conan_module.DefaultRevision)
|
||||||
|
|
||||||
if err := deleteRecipeOrPackage(ctx, rref, false, pref, true); err != nil {
|
if err := deleteRecipeOrPackage(ctx, rref, false, pref, true); err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == conan_model.ErrPackageReferenceNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -749,7 +750,7 @@ func LatestRecipeRevision(ctx *context.Context) {
|
|||||||
|
|
||||||
revision, err := conan_model.GetLastRecipeRevision(ctx, ctx.Package.Owner.ID, rref)
|
revision, err := conan_model.GetLastRecipeRevision(ctx, ctx.Package.Owner.ID, rref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == conan_model.ErrRecipeReferenceNotExist || err == conan_model.ErrPackageReferenceNotExist {
|
if errors.Is(err, conan_model.ErrRecipeReferenceNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -766,7 +767,7 @@ func LatestPackageRevision(ctx *context.Context) {
|
|||||||
|
|
||||||
revision, err := conan_model.GetLastPackageRevision(ctx, ctx.Package.Owner.ID, pref)
|
revision, err := conan_model.GetLastPackageRevision(ctx, ctx.Package.Owner.ID, pref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == conan_model.ErrRecipeReferenceNotExist || err == conan_model.ErrPackageReferenceNotExist {
|
if errors.Is(err, conan_model.ErrRecipeReferenceNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -796,7 +797,7 @@ func listRevisionFiles(ctx *context.Context, fileKey string) {
|
|||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
package conan
|
package conan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ func searchPackages(ctx *context.Context, searchAllRevisions bool) {
|
|||||||
if !searchAllRevisions && rref.Revision == "" {
|
if !searchAllRevisions && rref.Revision == "" {
|
||||||
lastRevision, err := conan_model.GetLastRecipeRevision(ctx, ctx.Package.Owner.ID, rref)
|
lastRevision, err := conan_model.GetLastRecipeRevision(ctx, ctx.Package.Owner.ID, rref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == conan_model.ErrRecipeReferenceNotExist {
|
if errors.Is(err, conan_model.ErrRecipeReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -87,7 +88,7 @@ func searchPackages(ctx *context.Context, searchAllRevisions bool) {
|
|||||||
} else {
|
} else {
|
||||||
has, err := conan_model.RecipeExists(ctx, ctx.Package.Owner.ID, rref)
|
has, err := conan_model.RecipeExists(ctx, ctx.Package.Owner.ID, rref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == conan_model.ErrRecipeReferenceNotExist {
|
if errors.Is(err, conan_model.ErrRecipeReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -119,7 +120,7 @@ func searchPackages(ctx *context.Context, searchAllRevisions bool) {
|
|||||||
}
|
}
|
||||||
packageReferences, err := conan_model.GetPackageReferences(ctx, ctx.Package.Owner.ID, currentRef)
|
packageReferences, err := conan_model.GetPackageReferences(ctx, ctx.Package.Owner.ID, currentRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == conan_model.ErrRecipeReferenceNotExist {
|
if errors.Is(err, conan_model.ErrRecipeReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -133,7 +134,7 @@ func searchPackages(ctx *context.Context, searchAllRevisions bool) {
|
|||||||
pref, _ := conan_module.NewPackageReference(currentRef, packageReference.Value, "")
|
pref, _ := conan_module.NewPackageReference(currentRef, packageReference.Value, "")
|
||||||
lastPackageRevision, err := conan_model.GetLastPackageRevision(ctx, ctx.Package.Owner.ID, pref)
|
lastPackageRevision, err := conan_model.GetLastPackageRevision(ctx, ctx.Package.Owner.ID, pref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == conan_model.ErrPackageReferenceNotExist {
|
if errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -143,7 +144,7 @@ func searchPackages(ctx *context.Context, searchAllRevisions bool) {
|
|||||||
pref = pref.WithRevision(lastPackageRevision.Value)
|
pref = pref.WithRevision(lastPackageRevision.Value)
|
||||||
infoRaw, err := conan_model.GetPackageInfo(ctx, ctx.Package.Owner.ID, pref)
|
infoRaw, err := conan_model.GetPackageInfo(ctx, ctx.Package.Owner.ID, pref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == conan_model.ErrPackageReferenceNotExist {
|
if errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
@ -111,12 +111,11 @@ func getOrCreateUploadVersion(ctx context.Context, pi *packages_service.PackageI
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
|
if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
|
||||||
if err == packages_model.ErrDuplicatePackage {
|
if !errors.Is(err, packages_model.ErrDuplicatePackage) {
|
||||||
created = false
|
|
||||||
} else {
|
|
||||||
log.Error("Error inserting package: %v", err)
|
log.Error("Error inserting package: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
created = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if created {
|
if created {
|
||||||
@ -135,7 +134,7 @@ func getOrCreateUploadVersion(ctx context.Context, pi *packages_service.PackageI
|
|||||||
MetadataJSON: "null",
|
MetadataJSON: "null",
|
||||||
}
|
}
|
||||||
if pv, err = packages_model.GetOrInsertVersion(ctx, pv); err != nil {
|
if pv, err = packages_model.GetOrInsertVersion(ctx, pv); err != nil {
|
||||||
if err != packages_model.ErrDuplicatePackageVersion {
|
if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) {
|
||||||
log.Error("Error inserting package: %v", err)
|
log.Error("Error inserting package: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -161,7 +160,7 @@ func createFileForBlob(ctx context.Context, pv *packages_model.PackageVersion, p
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if pf, err = packages_model.TryInsertFile(ctx, pf); err != nil {
|
if pf, err = packages_model.TryInsertFile(ctx, pf); err != nil {
|
||||||
if err == packages_model.ErrDuplicatePackageFile {
|
if errors.Is(err, packages_model.ErrDuplicatePackageFile) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Error("Error inserting package file: %v", err)
|
log.Error("Error inserting package file: %v", err)
|
||||||
|
@ -324,7 +324,7 @@ func GetUploadBlob(ctx *context.Context) {
|
|||||||
|
|
||||||
upload, err := packages_model.GetBlobUploadByID(ctx, uuid)
|
upload, err := packages_model.GetBlobUploadByID(ctx, uuid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageBlobUploadNotExist {
|
if errors.Is(err, packages_model.ErrPackageBlobUploadNotExist) {
|
||||||
apiErrorDefined(ctx, errBlobUploadUnknown)
|
apiErrorDefined(ctx, errBlobUploadUnknown)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -345,7 +345,7 @@ func UploadBlob(ctx *context.Context) {
|
|||||||
|
|
||||||
uploader, err := container_service.NewBlobUploader(ctx, ctx.PathParam("uuid"))
|
uploader, err := container_service.NewBlobUploader(ctx, ctx.PathParam("uuid"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageBlobUploadNotExist {
|
if errors.Is(err, packages_model.ErrPackageBlobUploadNotExist) {
|
||||||
apiErrorDefined(ctx, errBlobUploadUnknown)
|
apiErrorDefined(ctx, errBlobUploadUnknown)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -396,7 +396,7 @@ func EndUploadBlob(ctx *context.Context) {
|
|||||||
|
|
||||||
uploader, err := container_service.NewBlobUploader(ctx, ctx.PathParam("uuid"))
|
uploader, err := container_service.NewBlobUploader(ctx, ctx.PathParam("uuid"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageBlobUploadNotExist {
|
if errors.Is(err, packages_model.ErrPackageBlobUploadNotExist) {
|
||||||
apiErrorDefined(ctx, errBlobUploadUnknown)
|
apiErrorDefined(ctx, errBlobUploadUnknown)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -465,7 +465,7 @@ func CancelUploadBlob(ctx *context.Context) {
|
|||||||
|
|
||||||
_, err := packages_model.GetBlobUploadByID(ctx, uuid)
|
_, err := packages_model.GetBlobUploadByID(ctx, uuid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageBlobUploadNotExist {
|
if errors.Is(err, packages_model.ErrPackageBlobUploadNotExist) {
|
||||||
apiErrorDefined(ctx, errBlobUploadUnknown)
|
apiErrorDefined(ctx, errBlobUploadUnknown)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -501,7 +501,7 @@ func getBlobFromContext(ctx *context.Context) (*packages_model.PackageFileDescri
|
|||||||
func HeadBlob(ctx *context.Context) {
|
func HeadBlob(ctx *context.Context) {
|
||||||
blob, err := getBlobFromContext(ctx)
|
blob, err := getBlobFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == container_model.ErrContainerBlobNotExist {
|
if errors.Is(err, container_model.ErrContainerBlobNotExist) {
|
||||||
apiErrorDefined(ctx, errBlobUnknown)
|
apiErrorDefined(ctx, errBlobUnknown)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -520,7 +520,7 @@ func HeadBlob(ctx *context.Context) {
|
|||||||
func GetBlob(ctx *context.Context) {
|
func GetBlob(ctx *context.Context) {
|
||||||
blob, err := getBlobFromContext(ctx)
|
blob, err := getBlobFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == container_model.ErrContainerBlobNotExist {
|
if errors.Is(err, container_model.ErrContainerBlobNotExist) {
|
||||||
apiErrorDefined(ctx, errBlobUnknown)
|
apiErrorDefined(ctx, errBlobUnknown)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -639,7 +639,7 @@ func getManifestFromContext(ctx *context.Context) (*packages_model.PackageFileDe
|
|||||||
func HeadManifest(ctx *context.Context) {
|
func HeadManifest(ctx *context.Context) {
|
||||||
manifest, err := getManifestFromContext(ctx)
|
manifest, err := getManifestFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == container_model.ErrContainerBlobNotExist {
|
if errors.Is(err, container_model.ErrContainerBlobNotExist) {
|
||||||
apiErrorDefined(ctx, errManifestUnknown)
|
apiErrorDefined(ctx, errManifestUnknown)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -659,7 +659,7 @@ func HeadManifest(ctx *context.Context) {
|
|||||||
func GetManifest(ctx *context.Context) {
|
func GetManifest(ctx *context.Context) {
|
||||||
manifest, err := getManifestFromContext(ctx)
|
manifest, err := getManifestFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == container_model.ErrContainerBlobNotExist {
|
if errors.Is(err, container_model.ErrContainerBlobNotExist) {
|
||||||
apiErrorDefined(ctx, errManifestUnknown)
|
apiErrorDefined(ctx, errManifestUnknown)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -739,7 +739,7 @@ func GetTagList(ctx *context.Context) {
|
|||||||
image := ctx.PathParam("image")
|
image := ctx.PathParam("image")
|
||||||
|
|
||||||
if _, err := packages_model.GetPackageByName(ctx, ctx.Package.Owner.ID, packages_model.TypeContainer, image); err != nil {
|
if _, err := packages_model.GetPackageByName(ctx, ctx.Package.Owner.ID, packages_model.TypeContainer, image); err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiErrorDefined(ctx, errNameUnknown)
|
apiErrorDefined(ctx, errNameUnknown)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
@ -240,7 +240,7 @@ func processImageManifestIndex(ctx context.Context, mci *manifestCreationInfo, b
|
|||||||
IsManifest: true,
|
IsManifest: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == container_model.ErrContainerBlobNotExist {
|
if errors.Is(err, container_model.ErrContainerBlobNotExist) {
|
||||||
return errManifestBlobUnknown
|
return errManifestBlobUnknown
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@ -321,12 +321,11 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
|
if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
|
||||||
if err == packages_model.ErrDuplicatePackage {
|
if !errors.Is(err, packages_model.ErrDuplicatePackage) {
|
||||||
created = false
|
|
||||||
} else {
|
|
||||||
log.Error("Error inserting package: %v", err)
|
log.Error("Error inserting package: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
created = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if created {
|
if created {
|
||||||
@ -352,8 +351,12 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
|
|||||||
}
|
}
|
||||||
var pv *packages_model.PackageVersion
|
var pv *packages_model.PackageVersion
|
||||||
if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil {
|
if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil {
|
||||||
if err == packages_model.ErrDuplicatePackageVersion {
|
if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) {
|
||||||
if err := packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
|
log.Error("Error inserting package: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,12 +364,10 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
|
|||||||
_pv.DownloadCount = pv.DownloadCount
|
_pv.DownloadCount = pv.DownloadCount
|
||||||
|
|
||||||
if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil {
|
if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil {
|
||||||
|
if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) {
|
||||||
log.Error("Error inserting package: %v", err)
|
log.Error("Error inserting package: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log.Error("Error inserting package: %v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +418,7 @@ func createFileFromBlobReference(ctx context.Context, pv, uploadVersion *package
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if pf, err = packages_model.TryInsertFile(ctx, pf); err != nil {
|
if pf, err = packages_model.TryInsertFile(ctx, pf); err != nil {
|
||||||
if err == packages_model.ErrDuplicatePackageFile {
|
if errors.Is(err, packages_model.ErrDuplicatePackageFile) {
|
||||||
// Skip this blob because the manifest contains the same filesystem layer multiple times.
|
// Skip this blob because the manifest contains the same filesystem layer multiple times.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func GetRepositoryFile(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
} else {
|
} else {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
@ -44,7 +44,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ func DeletePackage(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -182,7 +182,7 @@ func DeletePackageFile(ctx *context.Context) {
|
|||||||
return pv, pf, nil
|
return pv, pf, nil
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,7 @@ func createPackageMetadataVersion(registryURL string, pd *packages_model.Package
|
|||||||
BundleDependencies: metadata.BundleDependencies,
|
BundleDependencies: metadata.BundleDependencies,
|
||||||
DevDependencies: metadata.DevelopmentDependencies,
|
DevDependencies: metadata.DevelopmentDependencies,
|
||||||
PeerDependencies: metadata.PeerDependencies,
|
PeerDependencies: metadata.PeerDependencies,
|
||||||
|
PeerDependenciesMeta: metadata.PeerDependenciesMeta,
|
||||||
OptionalDependencies: metadata.OptionalDependencies,
|
OptionalDependencies: metadata.OptionalDependencies,
|
||||||
Readme: metadata.Readme,
|
Readme: metadata.Readme,
|
||||||
Bin: metadata.Bin,
|
Bin: metadata.Bin,
|
||||||
|
@ -98,7 +98,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ func DownloadPackageFileByName(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -163,7 +163,7 @@ func UploadPackage(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := repo_model.GetRepositoryByURL(ctx, npmPackage.Metadata.Repository.URL)
|
repo, err := repo_model.GetRepositoryByURLRelax(ctx, npmPackage.Metadata.Repository.URL)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
canWrite := repo.OwnerID == ctx.Doer.ID
|
canWrite := repo.OwnerID == ctx.Doer.ID
|
||||||
|
|
||||||
@ -267,7 +267,7 @@ func DeletePackageVersion(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -341,7 +341,7 @@ func AddPackageTag(ctx *context.Context) {
|
|||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeNpm, packageName, version)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeNpm, packageName, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ func RegistrationLeafV2(ctx *context.Context) {
|
|||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeNuGet, packageName, packageVersion)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeNuGet, packageName, packageVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -288,7 +288,7 @@ func RegistrationLeafV3(ctx *context.Context) {
|
|||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeNuGet, packageName, packageVersion)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeNuGet, packageName, packageVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -418,7 +418,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -671,7 +671,7 @@ func DownloadSymbolFile(ctx *context.Context) {
|
|||||||
|
|
||||||
s, u, pf, err := packages_service.GetPackageFileStream(ctx, pfs[0])
|
s, u, pf, err := packages_service.GetPackageFileStream(ctx, pfs[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -699,7 +699,7 @@ func DeletePackage(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ func PackageVersionMetadata(ctx *context.Context) {
|
|||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypePub, packageName, packageVersion)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypePub, packageName, packageVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -233,7 +233,7 @@ func FinalizePackage(ctx *context.Context) {
|
|||||||
|
|
||||||
_, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypePub, packageName, packageVersion)
|
_, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypePub, packageName, packageVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -258,7 +258,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypePub, packageName, packageVersion)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypePub, packageName, packageVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,13 @@ package pypi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
@ -93,7 +95,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -139,9 +141,30 @@ func UploadPackageFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
projectURL := ctx.Req.FormValue("home_page")
|
// Ensure ctx.Req.Form exists.
|
||||||
if !validation.IsValidURL(projectURL) {
|
_ = ctx.Req.ParseForm()
|
||||||
projectURL = ""
|
|
||||||
|
var homepageURL string
|
||||||
|
projectURLs := ctx.Req.Form["project_urls"]
|
||||||
|
for _, purl := range projectURLs {
|
||||||
|
label, url, found := strings.Cut(purl, ",")
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if normalizeLabel(label) != "homepage" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
homepageURL = strings.TrimSpace(url)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(homepageURL) == 0 {
|
||||||
|
// TODO: Home-page is a deprecated metadata field. Remove this branch once it's no longer apart of the spec.
|
||||||
|
homepageURL = ctx.Req.FormValue("home_page")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !validation.IsValidURL(homepageURL) {
|
||||||
|
homepageURL = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = packages_service.CreatePackageOrAddFileToExisting(
|
_, _, err = packages_service.CreatePackageOrAddFileToExisting(
|
||||||
@ -160,7 +183,7 @@ func UploadPackageFile(ctx *context.Context) {
|
|||||||
Description: ctx.Req.FormValue("description"),
|
Description: ctx.Req.FormValue("description"),
|
||||||
LongDescription: ctx.Req.FormValue("long_description"),
|
LongDescription: ctx.Req.FormValue("long_description"),
|
||||||
Summary: ctx.Req.FormValue("summary"),
|
Summary: ctx.Req.FormValue("summary"),
|
||||||
ProjectURL: projectURL,
|
ProjectURL: homepageURL,
|
||||||
License: ctx.Req.FormValue("license"),
|
License: ctx.Req.FormValue("license"),
|
||||||
RequiresPython: ctx.Req.FormValue("requires_python"),
|
RequiresPython: ctx.Req.FormValue("requires_python"),
|
||||||
},
|
},
|
||||||
@ -189,6 +212,23 @@ func UploadPackageFile(ctx *context.Context) {
|
|||||||
ctx.Status(http.StatusCreated)
|
ctx.Status(http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normalizes a Project-URL label.
|
||||||
|
// See https://packaging.python.org/en/latest/specifications/well-known-project-urls/#label-normalization.
|
||||||
|
func normalizeLabel(label string) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
// "A label is normalized by deleting all ASCII punctuation and whitespace, and then converting the result
|
||||||
|
// to lowercase."
|
||||||
|
for _, r := range label {
|
||||||
|
if unicode.IsPunct(r) || unicode.IsSpace(r) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
builder.WriteRune(unicode.ToLower(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
func isValidNameAndVersion(packageName, packageVersion string) bool {
|
func isValidNameAndVersion(packageName, packageVersion string) bool {
|
||||||
return nameMatcher.MatchString(packageName) && versionMatcher.MatchString(packageVersion)
|
return nameMatcher.MatchString(packageName) && versionMatcher.MatchString(packageVersion)
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user