mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-15 00:01:25 -04:00
Compare commits
No commits in common. "79e7a6ec1e14c820c8475173a37aee84f2f4f1e8" and "8df1b4bd699897264c60da7ce982b09cee57f345" have entirely different histories.
79e7a6ec1e
...
8df1b4bd69
@ -44,7 +44,7 @@ Jimmy Praet <jimmy.praet@telenet.be> (@jpraet)
|
|||||||
Leon Hofmeister <dev.lh@web.de> (@delvh)
|
Leon Hofmeister <dev.lh@web.de> (@delvh)
|
||||||
Wim <wim@42.be> (@42wim)
|
Wim <wim@42.be> (@42wim)
|
||||||
Jason Song <i@wolfogre.com> (@wolfogre)
|
Jason Song <i@wolfogre.com> (@wolfogre)
|
||||||
Yarden Shoham <git@yardenshoham.com> (@yardenshoham)
|
Yarden Shoham <hrsi88@gmail.com> (@yardenshoham)
|
||||||
Yu Tian <zettat123@gmail.com> (@Zettat123)
|
Yu Tian <zettat123@gmail.com> (@Zettat123)
|
||||||
Eddie Yang <576951401@qq.com> (@yp05327)
|
Eddie Yang <576951401@qq.com> (@yp05327)
|
||||||
Dong Ge <gedong_1994@163.com> (@sillyguodong)
|
Dong Ge <gedong_1994@163.com> (@sillyguodong)
|
||||||
|
15
assets/go-licenses.json
generated
15
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
@ -72,21 +72,12 @@ var CmdMigrateStorage = cli.Command{
|
|||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "minio-base-path",
|
Name: "minio-base-path",
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Minio storage base path on the bucket",
|
Usage: "Minio storage basepath on the bucket",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "minio-use-ssl",
|
Name: "minio-use-ssl",
|
||||||
Usage: "Enable SSL for minio",
|
Usage: "Enable SSL for minio",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
|
||||||
Name: "minio-insecure-skip-verify",
|
|
||||||
Usage: "Skip SSL verification",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "minio-checksum-algorithm",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio checksum algorithm (default/md5)",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,15 +168,13 @@ func runMigrateStorage(ctx *cli.Context) error {
|
|||||||
dstStorage, err = storage.NewMinioStorage(
|
dstStorage, err = storage.NewMinioStorage(
|
||||||
stdCtx,
|
stdCtx,
|
||||||
storage.MinioStorageConfig{
|
storage.MinioStorageConfig{
|
||||||
Endpoint: ctx.String("minio-endpoint"),
|
Endpoint: ctx.String("minio-endpoint"),
|
||||||
AccessKeyID: ctx.String("minio-access-key-id"),
|
AccessKeyID: ctx.String("minio-access-key-id"),
|
||||||
SecretAccessKey: ctx.String("minio-secret-access-key"),
|
SecretAccessKey: ctx.String("minio-secret-access-key"),
|
||||||
Bucket: ctx.String("minio-bucket"),
|
Bucket: ctx.String("minio-bucket"),
|
||||||
Location: ctx.String("minio-location"),
|
Location: ctx.String("minio-location"),
|
||||||
BasePath: ctx.String("minio-base-path"),
|
BasePath: ctx.String("minio-base-path"),
|
||||||
UseSSL: ctx.Bool("minio-use-ssl"),
|
UseSSL: ctx.Bool("minio-use-ssl"),
|
||||||
InsecureSkipVerify: ctx.Bool("minio-insecure-skip-verify"),
|
|
||||||
ChecksumAlgorithm: ctx.String("minio-checksum-algorithm"),
|
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported storage type: %s", ctx.String("storage"))
|
return fmt.Errorf("unsupported storage type: %s", ctx.String("storage"))
|
||||||
|
@ -583,15 +583,15 @@ ROUTER = console
|
|||||||
;; * In request Header: X-Request-ID: test-id-123
|
;; * In request Header: X-Request-ID: test-id-123
|
||||||
;; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID
|
;; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID
|
||||||
;; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "test-id-123"
|
;; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "test-id-123"
|
||||||
;;
|
;;
|
||||||
;; If you configure more than one in the .ini file, it will match in the order of configuration,
|
;; If you configure more than one in the .ini file, it will match in the order of configuration,
|
||||||
;; and the first match will be finally printed in the log.
|
;; and the first match will be finally printed in the log.
|
||||||
;; * E.g:
|
;; * E.g:
|
||||||
;; * In reuqest Header: X-Trace-ID: trace-id-1q2w3e4r
|
;; * In reuqest Header: X-Trace-ID: trace-id-1q2w3e4r
|
||||||
;; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID, X-Trace-ID, X-Req-ID
|
;; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID, X-Trace-ID, X-Req-ID
|
||||||
;; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "trace-id-1q2w3e4r"
|
;; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "trace-id-1q2w3e4r"
|
||||||
;;
|
;;
|
||||||
;; REQUEST_ID_HEADERS =
|
;; REQUEST_ID_HEADERS =
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
@ -1357,13 +1357,13 @@ ROUTER = console
|
|||||||
;; Issue Indexer settings
|
;; Issue Indexer settings
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
;; Issue indexer type, currently support: bleve, db, elasticsearch or meilisearch default is bleve
|
;; Issue indexer type, currently support: bleve, db or elasticsearch, default is bleve
|
||||||
;ISSUE_INDEXER_TYPE = bleve
|
;ISSUE_INDEXER_TYPE = bleve
|
||||||
;;
|
;;
|
||||||
;; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve
|
;; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve
|
||||||
;ISSUE_INDEXER_PATH = indexers/issues.bleve ; Relative paths will be made absolute against _`AppWorkPath`_.
|
;ISSUE_INDEXER_PATH = indexers/issues.bleve ; Relative paths will be made absolute against _`AppWorkPath`_.
|
||||||
;;
|
;;
|
||||||
;; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch or meilisearch
|
;; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch
|
||||||
;ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
|
;ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
|
||||||
;;
|
;;
|
||||||
;; Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch
|
;; Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch
|
||||||
@ -1886,9 +1886,6 @@ ROUTER = console
|
|||||||
;;
|
;;
|
||||||
;; Minio skip SSL verification available when STORAGE_TYPE is `minio`
|
;; Minio skip SSL verification available when STORAGE_TYPE is `minio`
|
||||||
;MINIO_INSECURE_SKIP_VERIFY = false
|
;MINIO_INSECURE_SKIP_VERIFY = false
|
||||||
;;
|
|
||||||
;; Minio checksum algorithm: default (for MinIO or AWS S3) or md5 (for Cloudflare or Backblaze)
|
|
||||||
;MINIO_CHECKSUM_ALGORITHM = default
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -456,8 +456,8 @@ relation to port exhaustion.
|
|||||||
|
|
||||||
## Indexer (`indexer`)
|
## Indexer (`indexer`)
|
||||||
|
|
||||||
- `ISSUE_INDEXER_TYPE`: **bleve**: Issue indexer type, currently supported: `bleve`, `db`, `elasticsearch` or `meilisearch`.
|
- `ISSUE_INDEXER_TYPE`: **bleve**: Issue indexer type, currently supported: `bleve`, `db` or `elasticsearch`.
|
||||||
- `ISSUE_INDEXER_CONN_STR`: ****: Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch, or meilisearch. i.e. http://elastic:changeme@localhost:9200
|
- `ISSUE_INDEXER_CONN_STR`: ****: Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch. i.e. http://elastic:changeme@localhost:9200
|
||||||
- `ISSUE_INDEXER_NAME`: **gitea_issues**: Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch
|
- `ISSUE_INDEXER_NAME`: **gitea_issues**: Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch
|
||||||
- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search; available when ISSUE_INDEXER_TYPE is bleve and elasticsearch. Relative paths will be made absolute against _`AppWorkPath`_.
|
- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search; available when ISSUE_INDEXER_TYPE is bleve and elasticsearch. Relative paths will be made absolute against _`AppWorkPath`_.
|
||||||
- The next 4 configuration values are deprecated and should be set in `queue.issue_indexer` however are kept for backwards compatibility:
|
- The next 4 configuration values are deprecated and should be set in `queue.issue_indexer` however are kept for backwards compatibility:
|
||||||
@ -855,7 +855,6 @@ Default templates for project boards:
|
|||||||
- `MINIO_BASE_PATH`: **attachments/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
|
- `MINIO_BASE_PATH`: **attachments/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
|
||||||
- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when STORAGE_TYPE is `minio`
|
- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when STORAGE_TYPE is `minio`
|
||||||
- `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio skip SSL verification available when STORAGE_TYPE is `minio`
|
- `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio skip SSL verification available when STORAGE_TYPE is `minio`
|
||||||
- `MINIO_CHECKSUM_ALGORITHM`: **default**: Minio checksum algorithm: `default` (for MinIO or AWS S3) or `md5` (for Cloudflare or Backblaze)
|
|
||||||
|
|
||||||
## Log (`log`)
|
## Log (`log`)
|
||||||
|
|
||||||
|
@ -50,17 +50,6 @@ Possible file names for issue templates:
|
|||||||
- `.github/issue_template.yaml`
|
- `.github/issue_template.yaml`
|
||||||
- `.github/issue_template.yml`
|
- `.github/issue_template.yml`
|
||||||
|
|
||||||
Possible file names for issue config:
|
|
||||||
|
|
||||||
- `.gitea/ISSUE_TEMPLATE/config.yaml`
|
|
||||||
- `.gitea/ISSUE_TEMPLATE/config.yml`
|
|
||||||
- `.gitea/issue_template/config.yaml`
|
|
||||||
- `.gitea/issue_template/config.yml`
|
|
||||||
- `.github/ISSUE_TEMPLATE/config.yaml`
|
|
||||||
- `.github/ISSUE_TEMPLATE/config.yml`
|
|
||||||
- `.github/issue_template/config.yaml`
|
|
||||||
- `.github/issue_template/config.yml`
|
|
||||||
|
|
||||||
Possible file names for PR templates:
|
Possible file names for PR templates:
|
||||||
|
|
||||||
- `PULL_REQUEST_TEMPLATE.md`
|
- `PULL_REQUEST_TEMPLATE.md`
|
||||||
@ -278,30 +267,3 @@ For each value in the options array, you can set the following keys.
|
|||||||
|----------|------------------------------------------------------------------------------------------------------------------------------------------|----------|---------|---------|---------|
|
|----------|------------------------------------------------------------------------------------------------------------------------------------------|----------|---------|---------|---------|
|
||||||
| label | The identifier for the option, which is displayed in the form. Markdown is supported for bold or italic text formatting, and hyperlinks. | Required | String | - | - |
|
| label | The identifier for the option, which is displayed in the form. Markdown is supported for bold or italic text formatting, and hyperlinks. | Required | String | - | - |
|
||||||
| required | Prevents form submission until element is completed. | Optional | Boolean | false | - |
|
| required | Prevents form submission until element is completed. | Optional | Boolean | false | - |
|
||||||
|
|
||||||
## Syntax for issue config
|
|
||||||
|
|
||||||
This is a example for a issue config file
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
blank_issues_enabled: true
|
|
||||||
contact_links:
|
|
||||||
- name: Gitea
|
|
||||||
url: https://gitea.io
|
|
||||||
about: Visit the Gitea Website
|
|
||||||
```
|
|
||||||
|
|
||||||
### Possible Options
|
|
||||||
|
|
||||||
| Key | Description | Type | Default |
|
|
||||||
|----------------------|-------------------------------------------------------------------------------------------------------|--------------------|----------------|
|
|
||||||
| blank_issues_enabled | If set to false, the User is forced to use a Template | Boolean | true |
|
|
||||||
| contact_links | Custom Links to show in the Choose Box | Contact Link Array | Empty Array |
|
|
||||||
|
|
||||||
### Contact Link
|
|
||||||
|
|
||||||
| Key | Description | Type | Required |
|
|
||||||
|----------------------|-------------------------------------------------------------------------------------------------------|---------|----------|
|
|
||||||
| name | the name of your link | String | true |
|
|
||||||
| url | The URL of your Link | String | true |
|
|
||||||
| about | A short description of your Link | String | true |
|
|
||||||
|
5
go.mod
5
go.mod
@ -73,7 +73,6 @@ require (
|
|||||||
github.com/markbates/goth v1.76.0
|
github.com/markbates/goth v1.76.0
|
||||||
github.com/mattn/go-isatty v0.0.17
|
github.com/mattn/go-isatty v0.0.17
|
||||||
github.com/mattn/go-sqlite3 v1.14.16
|
github.com/mattn/go-sqlite3 v1.14.16
|
||||||
github.com/meilisearch/meilisearch-go v0.23.0
|
|
||||||
github.com/mholt/archiver/v3 v3.5.1
|
github.com/mholt/archiver/v3 v3.5.1
|
||||||
github.com/microcosm-cc/bluemonday v1.0.22
|
github.com/microcosm-cc/bluemonday v1.0.22
|
||||||
github.com/minio/minio-go/v7 v7.0.49
|
github.com/minio/minio-go/v7 v7.0.49
|
||||||
@ -219,7 +218,7 @@ require (
|
|||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
github.com/mholt/acmez v1.0.4 // indirect
|
github.com/mholt/acmez v1.1.0 // indirect
|
||||||
github.com/miekg/dns v1.1.50 // indirect
|
github.com/miekg/dns v1.1.50 // indirect
|
||||||
github.com/minio/md5-simd v1.1.2 // indirect
|
github.com/minio/md5-simd v1.1.2 // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
@ -260,8 +259,6 @@ require (
|
|||||||
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
||||||
github.com/ulikunitz/xz v0.5.11 // indirect
|
github.com/ulikunitz/xz v0.5.11 // indirect
|
||||||
github.com/unknwon/com v1.0.1 // indirect
|
github.com/unknwon/com v1.0.1 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
|
||||||
github.com/valyala/fasthttp v1.44.0 // indirect
|
|
||||||
github.com/valyala/fastjson v1.6.4 // indirect
|
github.com/valyala/fastjson v1.6.4 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
|
26
go.sum
26
go.sum
@ -127,7 +127,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
|||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
|
||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
|
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
|
||||||
@ -152,7 +151,6 @@ github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZw
|
|||||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
@ -498,7 +496,6 @@ github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3
|
|||||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
|
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
@ -774,9 +771,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
|||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
|
||||||
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
|
||||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
|
||||||
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
|
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
|
||||||
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
|
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
@ -868,10 +862,8 @@ github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwp
|
|||||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/meilisearch/meilisearch-go v0.23.0 h1:CuqB+/NyEJKXF2SovTetAZW7lX+nSH+QTqbgSH6bv+Q=
|
github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY=
|
||||||
github.com/meilisearch/meilisearch-go v0.23.0/go.mod h1:sAPJgywANHUCFUo/spCQ8SoP6sJhmfIKFWIXu7Dd5GQ=
|
github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs=
|
||||||
github.com/mholt/acmez v1.0.4 h1:N3cE4Pek+dSolbsofIkAYz6H1d3pE+2G0os7QHslf80=
|
|
||||||
github.com/mholt/acmez v1.0.4/go.mod h1:qFGLZ4u+ehWINeJZjzPlsnjJBCPAADWTcIqE/7DAYQY=
|
|
||||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
||||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.22 h1:p2tT7RNzRdCi0qmwxG+HbqD6ILkmwter1ZwVZn1oTxA=
|
github.com/microcosm-cc/bluemonday v1.0.22 h1:p2tT7RNzRdCi0qmwxG+HbqD6ILkmwter1ZwVZn1oTxA=
|
||||||
@ -1189,15 +1181,9 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
|
|||||||
github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8=
|
github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8=
|
||||||
github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
|
github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
|
||||||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
|
||||||
github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
|
|
||||||
github.com/valyala/fasthttp v1.44.0 h1:R+gLUhldIsfg1HokMuQjdQ5bh9nuXHPIfvkYUu9eR5Q=
|
|
||||||
github.com/valyala/fasthttp v1.44.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY=
|
|
||||||
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
|
||||||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
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=
|
||||||
@ -1263,22 +1249,18 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
|
||||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
|
||||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||||
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
|
||||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
@ -1401,10 +1383,8 @@ golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||||||
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-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220630215102-69896b714898/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.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
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=
|
||||||
@ -1512,7 +1492,6 @@ golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -1612,7 +1591,6 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
|||||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||||
|
@ -134,7 +134,7 @@ func CreateIssueDependency(user *user_model.User, issue, dep *Issue) error {
|
|||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
// Check if it already exists
|
// Check if it aleready exists
|
||||||
exists, err := issueDepExists(ctx, issue.ID, dep.ID)
|
exists, err := issueDepExists(ctx, issue.ID, dep.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -189,7 +189,7 @@ func (issue *Issue) IsOverdue() bool {
|
|||||||
|
|
||||||
// LoadRepo loads issue's repository
|
// LoadRepo loads issue's repository
|
||||||
func (issue *Issue) LoadRepo(ctx context.Context) (err error) {
|
func (issue *Issue) LoadRepo(ctx context.Context) (err error) {
|
||||||
if issue.Repo == nil && issue.RepoID != 0 {
|
if issue.Repo == nil {
|
||||||
issue.Repo, err = repo_model.GetRepositoryByID(ctx, issue.RepoID)
|
issue.Repo, err = repo_model.GetRepositoryByID(ctx, issue.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getRepositoryByID [%d]: %w", issue.RepoID, err)
|
return fmt.Errorf("getRepositoryByID [%d]: %w", issue.RepoID, err)
|
||||||
@ -223,7 +223,7 @@ func (issue *Issue) GetPullRequest() (pr *PullRequest, err error) {
|
|||||||
|
|
||||||
// LoadLabels loads labels
|
// LoadLabels loads labels
|
||||||
func (issue *Issue) LoadLabels(ctx context.Context) (err error) {
|
func (issue *Issue) LoadLabels(ctx context.Context) (err error) {
|
||||||
if issue.Labels == nil && issue.ID != 0 {
|
if issue.Labels == nil {
|
||||||
issue.Labels, err = GetLabelsByIssueID(ctx, issue.ID)
|
issue.Labels, err = GetLabelsByIssueID(ctx, issue.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getLabelsByIssueID [%d]: %w", issue.ID, err)
|
return fmt.Errorf("getLabelsByIssueID [%d]: %w", issue.ID, err)
|
||||||
@ -234,7 +234,7 @@ func (issue *Issue) LoadLabels(ctx context.Context) (err error) {
|
|||||||
|
|
||||||
// LoadPoster loads poster
|
// LoadPoster loads poster
|
||||||
func (issue *Issue) LoadPoster(ctx context.Context) (err error) {
|
func (issue *Issue) LoadPoster(ctx context.Context) (err error) {
|
||||||
if issue.Poster == nil && issue.PosterID != 0 {
|
if issue.Poster == nil {
|
||||||
issue.Poster, err = user_model.GetPossibleUserByID(ctx, issue.PosterID)
|
issue.Poster, err = user_model.GetPossibleUserByID(ctx, issue.PosterID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
issue.PosterID = -1
|
issue.PosterID = -1
|
||||||
@ -252,7 +252,7 @@ func (issue *Issue) LoadPoster(ctx context.Context) (err error) {
|
|||||||
// LoadPullRequest loads pull request info
|
// LoadPullRequest loads pull request info
|
||||||
func (issue *Issue) LoadPullRequest(ctx context.Context) (err error) {
|
func (issue *Issue) LoadPullRequest(ctx context.Context) (err error) {
|
||||||
if issue.IsPull {
|
if issue.IsPull {
|
||||||
if issue.PullRequest == nil && issue.ID != 0 {
|
if issue.PullRequest == nil {
|
||||||
issue.PullRequest, err = GetPullRequestByIssueID(ctx, issue.ID)
|
issue.PullRequest, err = GetPullRequestByIssueID(ctx, issue.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsErrPullRequestNotExist(err) {
|
if IsErrPullRequestNotExist(err) {
|
||||||
@ -261,9 +261,7 @@ func (issue *Issue) LoadPullRequest(ctx context.Context) (err error) {
|
|||||||
return fmt.Errorf("getPullRequestByIssueID [%d]: %w", issue.ID, err)
|
return fmt.Errorf("getPullRequestByIssueID [%d]: %w", issue.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if issue.PullRequest != nil {
|
issue.PullRequest.Issue = issue
|
||||||
issue.PullRequest.Issue = issue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -2130,18 +2128,15 @@ func (issue *Issue) GetParticipantIDsByIssue(ctx context.Context) ([]int64, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BlockedByDependencies finds all Dependencies an issue is blocked by
|
// BlockedByDependencies finds all Dependencies an issue is blocked by
|
||||||
func (issue *Issue) BlockedByDependencies(ctx context.Context, opts db.ListOptions) (issueDeps []*DependencyInfo, err error) {
|
func (issue *Issue) BlockedByDependencies(ctx context.Context) (issueDeps []*DependencyInfo, err error) {
|
||||||
sess := db.GetEngine(ctx).
|
err = db.GetEngine(ctx).
|
||||||
Table("issue").
|
Table("issue").
|
||||||
Join("INNER", "repository", "repository.id = issue.repo_id").
|
Join("INNER", "repository", "repository.id = issue.repo_id").
|
||||||
Join("INNER", "issue_dependency", "issue_dependency.dependency_id = issue.id").
|
Join("INNER", "issue_dependency", "issue_dependency.dependency_id = issue.id").
|
||||||
Where("issue_id = ?", issue.ID).
|
Where("issue_id = ?", issue.ID).
|
||||||
// sort by repo id then created date, with the issues of the same repo at the beginning of the list
|
// sort by repo id then created date, with the issues of the same repo at the beginning of the list
|
||||||
OrderBy("CASE WHEN issue.repo_id = ? THEN 0 ELSE issue.repo_id END, issue.created_unix DESC", issue.RepoID)
|
OrderBy("CASE WHEN issue.repo_id = ? THEN 0 ELSE issue.repo_id END, issue.created_unix DESC", issue.RepoID).
|
||||||
if opts.Page != 0 {
|
Find(&issueDeps)
|
||||||
sess = db.SetSessionPagination(sess, &opts)
|
|
||||||
}
|
|
||||||
err = sess.Find(&issueDeps)
|
|
||||||
|
|
||||||
for _, depInfo := range issueDeps {
|
for _, depInfo := range issueDeps {
|
||||||
depInfo.Issue.Repo = &depInfo.Repository
|
depInfo.Issue.Repo = &depInfo.Repository
|
||||||
|
@ -658,49 +658,6 @@ func GetRepositoryByName(ownerID int64, name string) (*Repository, error) {
|
|||||||
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
|
|
||||||
func GetRepositoryByURL(ctx context.Context, repoURL string) (*Repository, error) {
|
|
||||||
// possible urls for git:
|
|
||||||
// https://my.domain/sub-path/<owner>/<repo>.git
|
|
||||||
// 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")
|
|
||||||
}
|
|
||||||
|
|
||||||
ownerName := pathSegments[0]
|
|
||||||
repoName := strings.TrimSuffix(pathSegments[1], ".git")
|
|
||||||
return GetRepositoryByOwnerAndName(ctx, ownerName, repoName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRepositoryByID returns the repository by given id if exists.
|
// GetRepositoryByID returns the repository by given id if exists.
|
||||||
func GetRepositoryByID(ctx context.Context, id int64) (*Repository, error) {
|
func GetRepositoryByID(ctx context.Context, id int64) (*Repository, error) {
|
||||||
repo := new(Repository)
|
repo := new(Repository)
|
||||||
|
@ -124,65 +124,3 @@ func TestMetas(t *testing.T) {
|
|||||||
assert.Equal(t, "user3", metas["org"])
|
assert.Equal(t, "user3", metas["org"])
|
||||||
assert.Equal(t, ",owners,team1,", metas["teams"])
|
assert.Equal(t, ",owners,team1,", metas["teams"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetRepositoryByURL(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
t.Run("InvalidPath", func(t *testing.T) {
|
|
||||||
repo, err := repo_model.GetRepositoryByURL(db.DefaultContext, "something")
|
|
||||||
|
|
||||||
assert.Nil(t, repo)
|
|
||||||
assert.Error(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("ValidHttpURL", func(t *testing.T) {
|
|
||||||
test := func(t *testing.T, url string) {
|
|
||||||
repo, err := repo_model.GetRepositoryByURL(db.DefaultContext, url)
|
|
||||||
|
|
||||||
assert.NotNil(t, repo)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, repo.ID, int64(2))
|
|
||||||
assert.Equal(t, repo.OwnerID, int64(2))
|
|
||||||
}
|
|
||||||
|
|
||||||
test(t, "https://try.gitea.io/user2/repo2")
|
|
||||||
test(t, "https://try.gitea.io/user2/repo2.git")
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("ValidGitSshURL", func(t *testing.T) {
|
|
||||||
test := func(t *testing.T, url string) {
|
|
||||||
repo, err := repo_model.GetRepositoryByURL(db.DefaultContext, url)
|
|
||||||
|
|
||||||
assert.NotNil(t, repo)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, repo.ID, int64(2))
|
|
||||||
assert.Equal(t, repo.OwnerID, int64(2))
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
test := func(t *testing.T, url string) {
|
|
||||||
repo, err := repo_model.GetRepositoryByURL(db.DefaultContext, url)
|
|
||||||
|
|
||||||
assert.NotNil(t, repo)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, repo.ID, int64(2))
|
|
||||||
assert.Equal(t, repo.OwnerID, int64(2))
|
|
||||||
}
|
|
||||||
|
|
||||||
test(t, "sshuser@try.gitea.io:user2/repo2")
|
|
||||||
test(t, "sshuser@try.gitea.io:user2/repo2.git")
|
|
||||||
|
|
||||||
test(t, "try.gitea.io:user2/repo2")
|
|
||||||
test(t, "try.gitea.io:user2/repo2.git")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
@ -34,7 +33,6 @@ import (
|
|||||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||||
|
|
||||||
"github.com/editorconfig/editorconfig-core-go/v2"
|
"github.com/editorconfig/editorconfig-core-go/v2"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// IssueTemplateDirCandidates issue templates directory
|
// IssueTemplateDirCandidates issue templates directory
|
||||||
@ -49,13 +47,6 @@ var IssueTemplateDirCandidates = []string{
|
|||||||
".gitlab/issue_template",
|
".gitlab/issue_template",
|
||||||
}
|
}
|
||||||
|
|
||||||
var IssueConfigCandidates = []string{
|
|
||||||
".gitea/ISSUE_TEMPLATE/config",
|
|
||||||
".gitea/issue_template/config",
|
|
||||||
".github/ISSUE_TEMPLATE/config",
|
|
||||||
".github/issue_template/config",
|
|
||||||
}
|
|
||||||
|
|
||||||
// PullRequest contains information to make a pull request
|
// PullRequest contains information to make a pull request
|
||||||
type PullRequest struct {
|
type PullRequest struct {
|
||||||
BaseRepo *repo_model.Repository
|
BaseRepo *repo_model.Repository
|
||||||
@ -1097,108 +1088,3 @@ func (ctx *Context) IssueTemplatesErrorsFromDefaultBranch() ([]*api.IssueTemplat
|
|||||||
}
|
}
|
||||||
return issueTemplates, invalidFiles
|
return issueTemplates, invalidFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDefaultIssueConfig() api.IssueConfig {
|
|
||||||
return api.IssueConfig{
|
|
||||||
BlankIssuesEnabled: true,
|
|
||||||
ContactLinks: make([]api.IssueConfigContactLink, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetIssueConfig loads the given issue config file.
|
|
||||||
// It never returns a nil config.
|
|
||||||
func (r *Repository) GetIssueConfig(path string, commit *git.Commit) (api.IssueConfig, error) {
|
|
||||||
if r.GitRepo == nil {
|
|
||||||
return GetDefaultIssueConfig(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
treeEntry, err := commit.GetTreeEntryByPath(path)
|
|
||||||
if err != nil {
|
|
||||||
return GetDefaultIssueConfig(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
reader, err := treeEntry.Blob().DataAsync()
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("DataAsync: %v", err)
|
|
||||||
return GetDefaultIssueConfig(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
defer reader.Close()
|
|
||||||
|
|
||||||
configContent, err := io.ReadAll(reader)
|
|
||||||
if err != nil {
|
|
||||||
return GetDefaultIssueConfig(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
issueConfig := api.IssueConfig{}
|
|
||||||
if err := yaml.Unmarshal(configContent, &issueConfig); err != nil {
|
|
||||||
return GetDefaultIssueConfig(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
for pos, link := range issueConfig.ContactLinks {
|
|
||||||
if link.Name == "" {
|
|
||||||
return GetDefaultIssueConfig(), fmt.Errorf("contact_link at position %d is missing name key", pos+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if link.URL == "" {
|
|
||||||
return GetDefaultIssueConfig(), fmt.Errorf("contact_link at position %d is missing url key", pos+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if link.About == "" {
|
|
||||||
return GetDefaultIssueConfig(), fmt.Errorf("contact_link at position %d is missing about key", pos+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = url.ParseRequestURI(link.URL)
|
|
||||||
if err != nil {
|
|
||||||
return GetDefaultIssueConfig(), fmt.Errorf("%s is not a valid URL", link.URL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return issueConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IssueConfigFromDefaultBranch returns the issue config for this repo.
|
|
||||||
// It never returns a nil config.
|
|
||||||
func (ctx *Context) IssueConfigFromDefaultBranch() (api.IssueConfig, error) {
|
|
||||||
if ctx.Repo.Repository.IsEmpty {
|
|
||||||
return GetDefaultIssueConfig(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
|
|
||||||
if err != nil {
|
|
||||||
return GetDefaultIssueConfig(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, configName := range IssueConfigCandidates {
|
|
||||||
if _, err := commit.GetTreeEntryByPath(configName + ".yaml"); err == nil {
|
|
||||||
return ctx.Repo.GetIssueConfig(configName+".yaml", commit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := commit.GetTreeEntryByPath(configName + ".yml"); err == nil {
|
|
||||||
return ctx.Repo.GetIssueConfig(configName+".yml", commit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetDefaultIssueConfig(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsIssueConfig returns if the given path is a issue config file.
|
|
||||||
func (r *Repository) IsIssueConfig(path string) bool {
|
|
||||||
for _, configName := range IssueConfigCandidates {
|
|
||||||
if path == configName+".yaml" || path == configName+".yml" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *Context) HasIssueTemplatesOrContactLinks() bool {
|
|
||||||
if len(ctx.IssueTemplatesFromDefaultBranch()) > 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
issueConfig, _ := ctx.IssueConfigFromDefaultBranch()
|
|
||||||
return len(issueConfig.ContactLinks) > 0
|
|
||||||
}
|
|
||||||
|
@ -107,7 +107,7 @@ func InitIssueIndexer(syncReindex bool) {
|
|||||||
|
|
||||||
// Create the Queue
|
// Create the Queue
|
||||||
switch setting.Indexer.IssueType {
|
switch setting.Indexer.IssueType {
|
||||||
case "bleve", "elasticsearch", "meilisearch":
|
case "bleve", "elasticsearch":
|
||||||
handler := func(data ...queue.Data) []queue.Data {
|
handler := func(data ...queue.Data) []queue.Data {
|
||||||
indexer := holder.get()
|
indexer := holder.get()
|
||||||
if indexer == nil {
|
if indexer == nil {
|
||||||
@ -220,21 +220,6 @@ func InitIssueIndexer(syncReindex bool) {
|
|||||||
issueIndexer := &DBIndexer{}
|
issueIndexer := &DBIndexer{}
|
||||||
holder.set(issueIndexer)
|
holder.set(issueIndexer)
|
||||||
graceful.GetManager().RunAtTerminate(finished)
|
graceful.GetManager().RunAtTerminate(finished)
|
||||||
case "meilisearch":
|
|
||||||
graceful.GetManager().RunWithShutdownFns(func(_, atTerminate func(func())) {
|
|
||||||
pprof.SetGoroutineLabels(ctx)
|
|
||||||
issueIndexer, err := NewMeilisearchIndexer(setting.Indexer.IssueConnStr, setting.Indexer.IssueConnAuth, setting.Indexer.IssueIndexerName)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Unable to initialize Meilisearch Issue Indexer at connection: %s Error: %v", setting.Indexer.IssueConnStr, err)
|
|
||||||
}
|
|
||||||
exist, err := issueIndexer.Init()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Unable to issueIndexer.Init with connection %s Error: %v", setting.Indexer.IssueConnStr, err)
|
|
||||||
}
|
|
||||||
populate = !exist
|
|
||||||
holder.set(issueIndexer)
|
|
||||||
atTerminate(finished)
|
|
||||||
})
|
|
||||||
default:
|
default:
|
||||||
holder.cancel()
|
holder.cancel()
|
||||||
log.Fatal("Unknown issue indexer type: %s", setting.Indexer.IssueType)
|
log.Fatal("Unknown issue indexer type: %s", setting.Indexer.IssueType)
|
||||||
|
@ -1,183 +0,0 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package issues
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/meilisearch/meilisearch-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ Indexer = &MeilisearchIndexer{}
|
|
||||||
|
|
||||||
// MeilisearchIndexer implements Indexer interface
|
|
||||||
type MeilisearchIndexer struct {
|
|
||||||
client *meilisearch.Client
|
|
||||||
indexerName string
|
|
||||||
available bool
|
|
||||||
availabilityCallback func(bool)
|
|
||||||
stopTimer chan struct{}
|
|
||||||
lock sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// MeilisearchIndexer creates a new meilisearch indexer
|
|
||||||
func NewMeilisearchIndexer(url, apiKey, indexerName string) (*MeilisearchIndexer, error) {
|
|
||||||
client := meilisearch.NewClient(meilisearch.ClientConfig{
|
|
||||||
Host: url,
|
|
||||||
APIKey: apiKey,
|
|
||||||
})
|
|
||||||
|
|
||||||
indexer := &MeilisearchIndexer{
|
|
||||||
client: client,
|
|
||||||
indexerName: indexerName,
|
|
||||||
available: true,
|
|
||||||
stopTimer: make(chan struct{}),
|
|
||||||
}
|
|
||||||
|
|
||||||
ticker := time.NewTicker(10 * time.Second)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
indexer.checkAvailability()
|
|
||||||
case <-indexer.stopTimer:
|
|
||||||
ticker.Stop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return indexer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init will initialize the indexer
|
|
||||||
func (b *MeilisearchIndexer) Init() (bool, error) {
|
|
||||||
_, err := b.client.GetIndex(b.indexerName)
|
|
||||||
if err == nil {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
_, err = b.client.CreateIndex(&meilisearch.IndexConfig{
|
|
||||||
Uid: b.indexerName,
|
|
||||||
PrimaryKey: "id",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return false, b.checkError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = b.client.Index(b.indexerName).UpdateFilterableAttributes(&[]string{"repo_id"})
|
|
||||||
return false, b.checkError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAvailabilityChangeCallback sets callback that will be triggered when availability changes
|
|
||||||
func (b *MeilisearchIndexer) SetAvailabilityChangeCallback(callback func(bool)) {
|
|
||||||
b.lock.Lock()
|
|
||||||
defer b.lock.Unlock()
|
|
||||||
b.availabilityCallback = callback
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ping checks if meilisearch is available
|
|
||||||
func (b *MeilisearchIndexer) Ping() bool {
|
|
||||||
b.lock.RLock()
|
|
||||||
defer b.lock.RUnlock()
|
|
||||||
return b.available
|
|
||||||
}
|
|
||||||
|
|
||||||
// Index will save the index data
|
|
||||||
func (b *MeilisearchIndexer) Index(issues []*IndexerData) error {
|
|
||||||
if len(issues) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for _, issue := range issues {
|
|
||||||
_, err := b.client.Index(b.indexerName).AddDocuments(issue)
|
|
||||||
if err != nil {
|
|
||||||
return b.checkError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: bulk send index data
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete deletes indexes by ids
|
|
||||||
func (b *MeilisearchIndexer) Delete(ids ...int64) error {
|
|
||||||
if len(ids) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, id := range ids {
|
|
||||||
_, err := b.client.Index(b.indexerName).DeleteDocument(strconv.FormatInt(id, 10))
|
|
||||||
if err != nil {
|
|
||||||
return b.checkError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: bulk send deletes
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search searches for issues by given conditions.
|
|
||||||
// Returns the matching issue IDs
|
|
||||||
func (b *MeilisearchIndexer) Search(ctx context.Context, keyword string, repoIDs []int64, limit, start int) (*SearchResult, error) {
|
|
||||||
filter := make([][]string, 0, len(repoIDs))
|
|
||||||
for _, repoID := range repoIDs {
|
|
||||||
filter = append(filter, []string{"repo_id = " + strconv.FormatInt(repoID, 10)})
|
|
||||||
}
|
|
||||||
searchRes, err := b.client.Index(b.indexerName).Search(keyword, &meilisearch.SearchRequest{
|
|
||||||
Filter: filter,
|
|
||||||
Limit: int64(limit),
|
|
||||||
Offset: int64(start),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, b.checkError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hits := make([]Match, 0, len(searchRes.Hits))
|
|
||||||
for _, hit := range searchRes.Hits {
|
|
||||||
hits = append(hits, Match{
|
|
||||||
ID: int64(hit.(map[string]interface{})["id"].(float64)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return &SearchResult{
|
|
||||||
Total: searchRes.TotalHits,
|
|
||||||
Hits: hits,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close implements indexer
|
|
||||||
func (b *MeilisearchIndexer) Close() {
|
|
||||||
select {
|
|
||||||
case <-b.stopTimer:
|
|
||||||
default:
|
|
||||||
close(b.stopTimer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *MeilisearchIndexer) checkError(err error) error {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *MeilisearchIndexer) checkAvailability() {
|
|
||||||
_, err := b.client.Health()
|
|
||||||
if err != nil {
|
|
||||||
b.setAvailability(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b.setAvailability(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *MeilisearchIndexer) setAvailability(available bool) {
|
|
||||||
b.lock.Lock()
|
|
||||||
defer b.lock.Unlock()
|
|
||||||
|
|
||||||
if b.available == available {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
b.available = available
|
|
||||||
if b.availabilityCallback != nil {
|
|
||||||
// Call the callback from within the lock to ensure that the ordering remains correct
|
|
||||||
b.availabilityCallback(b.available)
|
|
||||||
}
|
|
||||||
}
|
|
@ -60,22 +60,15 @@ func (s *ContentStore) Put(pointer Pointer, r io.Reader) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// check again whether there is any error during the Save operation
|
// This shouldn't happen but it is sensible to test
|
||||||
// because some errors might be ignored by the Reader's caller
|
if written != pointer.Size {
|
||||||
if wrappedRd.lastError != nil && !errors.Is(wrappedRd.lastError, io.EOF) {
|
if err := s.Delete(p); err != nil {
|
||||||
err = wrappedRd.lastError
|
log.Error("Cleaning the LFS OID[%s] failed: %v", pointer.Oid, err)
|
||||||
} else if written != pointer.Size {
|
|
||||||
err = ErrSizeMismatch
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the upload failed, try to delete the file
|
|
||||||
if err != nil {
|
|
||||||
if errDel := s.Delete(p); errDel != nil {
|
|
||||||
log.Error("Cleaning the LFS OID[%s] failed: %v", pointer.Oid, errDel)
|
|
||||||
}
|
}
|
||||||
|
return ErrSizeMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists returns true if the object exists in the content store.
|
// Exists returns true if the object exists in the content store.
|
||||||
@ -116,17 +109,6 @@ type hashingReader struct {
|
|||||||
expectedSize int64
|
expectedSize int64
|
||||||
hash hash.Hash
|
hash hash.Hash
|
||||||
expectedHash string
|
expectedHash string
|
||||||
lastError error
|
|
||||||
}
|
|
||||||
|
|
||||||
// recordError records the last error during the Save operation
|
|
||||||
// Some callers of the Reader doesn't respect the returned "err"
|
|
||||||
// For example, MinIO's Put will ignore errors if the written size could equal to expected size
|
|
||||||
// So we must remember the error by ourselves,
|
|
||||||
// and later check again whether ErrSizeMismatch or ErrHashMismatch occurs during the Save operation
|
|
||||||
func (r *hashingReader) recordError(err error) error {
|
|
||||||
r.lastError = err
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *hashingReader) Read(b []byte) (int, error) {
|
func (r *hashingReader) Read(b []byte) (int, error) {
|
||||||
@ -136,22 +118,22 @@ func (r *hashingReader) Read(b []byte) (int, error) {
|
|||||||
r.currentSize += int64(n)
|
r.currentSize += int64(n)
|
||||||
wn, werr := r.hash.Write(b[:n])
|
wn, werr := r.hash.Write(b[:n])
|
||||||
if wn != n || werr != nil {
|
if wn != n || werr != nil {
|
||||||
return n, r.recordError(werr)
|
return n, werr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, io.EOF) || r.currentSize >= r.expectedSize {
|
if err != nil && err == io.EOF {
|
||||||
if r.currentSize != r.expectedSize {
|
if r.currentSize != r.expectedSize {
|
||||||
return n, r.recordError(ErrSizeMismatch)
|
return n, ErrSizeMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
shaStr := hex.EncodeToString(r.hash.Sum(nil))
|
shaStr := hex.EncodeToString(r.hash.Sum(nil))
|
||||||
if shaStr != r.expectedHash {
|
if shaStr != r.expectedHash {
|
||||||
return n, r.recordError(ErrHashMismatch)
|
return n, ErrHashMismatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return n, r.recordError(err)
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHashingReader(expectedSize int64, expectedHash string, reader io.Reader) *hashingReader {
|
func newHashingReader(expectedSize int64, expectedHash string, reader io.Reader) *hashingReader {
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package setting
|
package setting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -19,7 +18,6 @@ var Indexer = struct {
|
|||||||
IssueType string
|
IssueType string
|
||||||
IssuePath string
|
IssuePath string
|
||||||
IssueConnStr string
|
IssueConnStr string
|
||||||
IssueConnAuth string
|
|
||||||
IssueIndexerName string
|
IssueIndexerName string
|
||||||
StartupTimeout time.Duration
|
StartupTimeout time.Duration
|
||||||
|
|
||||||
@ -36,7 +34,6 @@ var Indexer = struct {
|
|||||||
IssueType: "bleve",
|
IssueType: "bleve",
|
||||||
IssuePath: "indexers/issues.bleve",
|
IssuePath: "indexers/issues.bleve",
|
||||||
IssueConnStr: "",
|
IssueConnStr: "",
|
||||||
IssueConnAuth: "",
|
|
||||||
IssueIndexerName: "gitea_issues",
|
IssueIndexerName: "gitea_issues",
|
||||||
|
|
||||||
RepoIndexerEnabled: false,
|
RepoIndexerEnabled: false,
|
||||||
@ -56,18 +53,6 @@ func loadIndexerFrom(rootCfg ConfigProvider) {
|
|||||||
Indexer.IssuePath = filepath.ToSlash(filepath.Join(AppWorkPath, Indexer.IssuePath))
|
Indexer.IssuePath = filepath.ToSlash(filepath.Join(AppWorkPath, Indexer.IssuePath))
|
||||||
}
|
}
|
||||||
Indexer.IssueConnStr = sec.Key("ISSUE_INDEXER_CONN_STR").MustString(Indexer.IssueConnStr)
|
Indexer.IssueConnStr = sec.Key("ISSUE_INDEXER_CONN_STR").MustString(Indexer.IssueConnStr)
|
||||||
|
|
||||||
if Indexer.IssueType == "meilisearch" {
|
|
||||||
u, err := url.Parse(Indexer.IssueConnStr)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("Failed to parse ISSUE_INDEXER_CONN_STR: %v", err)
|
|
||||||
u = &url.URL{}
|
|
||||||
}
|
|
||||||
Indexer.IssueConnAuth, _ = u.User.Password()
|
|
||||||
u.User = nil
|
|
||||||
Indexer.IssueConnStr = u.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
Indexer.IssueIndexerName = sec.Key("ISSUE_INDEXER_NAME").MustString(Indexer.IssueIndexerName)
|
Indexer.IssueIndexerName = sec.Key("ISSUE_INDEXER_NAME").MustString(Indexer.IssueIndexerName)
|
||||||
|
|
||||||
// The following settings are deprecated and can be overridden by settings in [queue] or [queue.issue_indexer]
|
// The following settings are deprecated and can be overridden by settings in [queue] or [queue.issue_indexer]
|
||||||
|
@ -42,7 +42,6 @@ func getStorage(rootCfg ConfigProvider, name, typ string, targetSec *ini.Section
|
|||||||
sec.Key("MINIO_LOCATION").MustString("us-east-1")
|
sec.Key("MINIO_LOCATION").MustString("us-east-1")
|
||||||
sec.Key("MINIO_USE_SSL").MustBool(false)
|
sec.Key("MINIO_USE_SSL").MustBool(false)
|
||||||
sec.Key("MINIO_INSECURE_SKIP_VERIFY").MustBool(false)
|
sec.Key("MINIO_INSECURE_SKIP_VERIFY").MustBool(false)
|
||||||
sec.Key("MINIO_CHECKSUM_ALGORITHM").MustString("default")
|
|
||||||
|
|
||||||
if targetSec == nil {
|
if targetSec == nil {
|
||||||
targetSec, _ = rootCfg.NewSection(name)
|
targetSec, _ = rootCfg.NewSection(name)
|
||||||
|
@ -6,7 +6,6 @@ package storage
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -54,12 +53,10 @@ type MinioStorageConfig struct {
|
|||||||
BasePath string `ini:"MINIO_BASE_PATH"`
|
BasePath string `ini:"MINIO_BASE_PATH"`
|
||||||
UseSSL bool `ini:"MINIO_USE_SSL"`
|
UseSSL bool `ini:"MINIO_USE_SSL"`
|
||||||
InsecureSkipVerify bool `ini:"MINIO_INSECURE_SKIP_VERIFY"`
|
InsecureSkipVerify bool `ini:"MINIO_INSECURE_SKIP_VERIFY"`
|
||||||
ChecksumAlgorithm string `ini:"MINIO_CHECKSUM_ALGORITHM"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MinioStorage returns a minio bucket storage
|
// MinioStorage returns a minio bucket storage
|
||||||
type MinioStorage struct {
|
type MinioStorage struct {
|
||||||
cfg *MinioStorageConfig
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
client *minio.Client
|
client *minio.Client
|
||||||
bucket string
|
bucket string
|
||||||
@ -94,10 +91,6 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
|
|||||||
}
|
}
|
||||||
config := configInterface.(MinioStorageConfig)
|
config := configInterface.(MinioStorageConfig)
|
||||||
|
|
||||||
if config.ChecksumAlgorithm != "" && config.ChecksumAlgorithm != "default" && config.ChecksumAlgorithm != "md5" {
|
|
||||||
return nil, fmt.Errorf("invalid minio checksum algorithm: %s", config.ChecksumAlgorithm)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Creating Minio storage at %s:%s with base path %s", config.Endpoint, config.Bucket, config.BasePath)
|
log.Info("Creating Minio storage at %s:%s with base path %s", config.Endpoint, config.Bucket, config.BasePath)
|
||||||
|
|
||||||
minioClient, err := minio.New(config.Endpoint, &minio.Options{
|
minioClient, err := minio.New(config.Endpoint, &minio.Options{
|
||||||
@ -120,7 +113,6 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &MinioStorage{
|
return &MinioStorage{
|
||||||
cfg: &config,
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
client: minioClient,
|
client: minioClient,
|
||||||
bucket: config.Bucket,
|
bucket: config.Bucket,
|
||||||
@ -132,7 +124,7 @@ func (m *MinioStorage) buildMinioPath(p string) string {
|
|||||||
return util.PathJoinRelX(m.basePath, p)
|
return util.PathJoinRelX(m.basePath, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open opens a file
|
// Open open a file
|
||||||
func (m *MinioStorage) Open(path string) (Object, error) {
|
func (m *MinioStorage) Open(path string) (Object, error) {
|
||||||
opts := minio.GetObjectOptions{}
|
opts := minio.GetObjectOptions{}
|
||||||
object, err := m.client.GetObject(m.ctx, m.bucket, m.buildMinioPath(path), opts)
|
object, err := m.client.GetObject(m.ctx, m.bucket, m.buildMinioPath(path), opts)
|
||||||
@ -142,7 +134,7 @@ func (m *MinioStorage) Open(path string) (Object, error) {
|
|||||||
return &minioObject{object}, nil
|
return &minioObject{object}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save saves a file to minio
|
// Save save a file to minio
|
||||||
func (m *MinioStorage) Save(path string, r io.Reader, size int64) (int64, error) {
|
func (m *MinioStorage) Save(path string, r io.Reader, size int64) (int64, error) {
|
||||||
uploadInfo, err := m.client.PutObject(
|
uploadInfo, err := m.client.PutObject(
|
||||||
m.ctx,
|
m.ctx,
|
||||||
@ -150,14 +142,7 @@ func (m *MinioStorage) Save(path string, r io.Reader, size int64) (int64, error)
|
|||||||
m.buildMinioPath(path),
|
m.buildMinioPath(path),
|
||||||
r,
|
r,
|
||||||
size,
|
size,
|
||||||
minio.PutObjectOptions{
|
minio.PutObjectOptions{ContentType: "application/octet-stream"},
|
||||||
ContentType: "application/octet-stream",
|
|
||||||
// some storages like:
|
|
||||||
// * https://developers.cloudflare.com/r2/api/s3/api/
|
|
||||||
// * https://www.backblaze.com/b2/docs/s3_compatible_api.html
|
|
||||||
// do not support "x-amz-checksum-algorithm" header, so use legacy MD5 checksum
|
|
||||||
SendContentMd5: m.cfg.ChecksumAlgorithm == "md5",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, convertMinioErr(err)
|
return 0, convertMinioErr(err)
|
||||||
|
@ -190,22 +190,6 @@ func (l *IssueTemplateLabels) UnmarshalYAML(value *yaml.Node) error {
|
|||||||
return fmt.Errorf("line %d: cannot unmarshal %s into IssueTemplateLabels", value.Line, value.ShortTag())
|
return fmt.Errorf("line %d: cannot unmarshal %s into IssueTemplateLabels", value.Line, value.ShortTag())
|
||||||
}
|
}
|
||||||
|
|
||||||
type IssueConfigContactLink struct {
|
|
||||||
Name string `json:"name" yaml:"name"`
|
|
||||||
URL string `json:"url" yaml:"url"`
|
|
||||||
About string `json:"about" yaml:"about"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type IssueConfig struct {
|
|
||||||
BlankIssuesEnabled bool `json:"blank_issues_enabled" yaml:"blank_issues_enabled"`
|
|
||||||
ContactLinks []IssueConfigContactLink `json:"contact_links" yaml:"contact_links"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type IssueConfigValidation struct {
|
|
||||||
Valid bool `json:"valid"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// IssueTemplateType defines issue template type
|
// IssueTemplateType defines issue template type
|
||||||
type IssueTemplateType string
|
type IssueTemplateType string
|
||||||
|
|
||||||
@ -227,11 +211,3 @@ func (it IssueTemplate) Type() IssueTemplateType {
|
|||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssueMeta basic issue information
|
|
||||||
// swagger:model
|
|
||||||
type IssueMeta struct {
|
|
||||||
Index int64 `json:"index"`
|
|
||||||
Owner string `json:"owner"`
|
|
||||||
Name string `json:"repo"`
|
|
||||||
}
|
|
||||||
|
@ -1272,12 +1272,10 @@ issues.new.no_assignees = No Assignees
|
|||||||
issues.new.no_reviewers = No reviewers
|
issues.new.no_reviewers = No reviewers
|
||||||
issues.new.add_reviewer_title = Request review
|
issues.new.add_reviewer_title = Request review
|
||||||
issues.choose.get_started = Get Started
|
issues.choose.get_started = Get Started
|
||||||
issues.choose.open_external_link = Open
|
|
||||||
issues.choose.blank = Default
|
issues.choose.blank = Default
|
||||||
issues.choose.blank_about = Create an issue from default template.
|
issues.choose.blank_about = Create an issue from default template.
|
||||||
issues.choose.ignore_invalid_templates = Invalid templates have been ignored
|
issues.choose.ignore_invalid_templates = Invalid templates have been ignored
|
||||||
issues.choose.invalid_templates = %v invalid template(s) found
|
issues.choose.invalid_templates = %v invalid template(s) found
|
||||||
issues.choose.invalid_config = The issue config contains errors:
|
|
||||||
issues.no_ref = No Branch/Tag Specified
|
issues.no_ref = No Branch/Tag Specified
|
||||||
issues.create = Create Issue
|
issues.create = Create Issue
|
||||||
issues.new_label = New Label
|
issues.new_label = New Label
|
||||||
@ -1491,9 +1489,6 @@ issues.due_date_invalid = "The due date is invalid or out of range. Please use t
|
|||||||
issues.dependency.title = Dependencies
|
issues.dependency.title = Dependencies
|
||||||
issues.dependency.issue_no_dependencies = No dependencies set.
|
issues.dependency.issue_no_dependencies = No dependencies set.
|
||||||
issues.dependency.pr_no_dependencies = No dependencies set.
|
issues.dependency.pr_no_dependencies = No dependencies set.
|
||||||
issues.dependency.no_permission_1 = "You do not have permission to read %d dependency"
|
|
||||||
issues.dependency.no_permission_n = "You do not have permission to read %d dependencies"
|
|
||||||
issues.dependency.no_permission.can_remove = "You do not have permission to read this dependency but can remove this dependency"
|
|
||||||
issues.dependency.add = Add dependency…
|
issues.dependency.add = Add dependency…
|
||||||
issues.dependency.cancel = Cancel
|
issues.dependency.cancel = Cancel
|
||||||
issues.dependency.remove = Remove
|
issues.dependency.remove = Remove
|
||||||
@ -3365,7 +3360,6 @@ runners.status.idle = Idle
|
|||||||
runners.status.active = Active
|
runners.status.active = Active
|
||||||
runners.status.offline = Offline
|
runners.status.offline = Offline
|
||||||
runners.version = Version
|
runners.version = Version
|
||||||
runners.reset_registration_token_success = Runner registration token reset successfully
|
|
||||||
|
|
||||||
runs.all_workflows = All Workflows
|
runs.all_workflows = All Workflows
|
||||||
runs.open_tab = %d Open
|
runs.open_tab = %d Open
|
||||||
|
@ -84,7 +84,6 @@ add=追加
|
|||||||
add_all=すべて追加
|
add_all=すべて追加
|
||||||
remove=除去
|
remove=除去
|
||||||
remove_all=すべて除去
|
remove_all=すべて除去
|
||||||
remove_label_str=アイテム「%s」を削除
|
|
||||||
edit=編集
|
edit=編集
|
||||||
|
|
||||||
enabled=有効
|
enabled=有効
|
||||||
@ -219,7 +218,6 @@ openid_signup_popup=OpenIDベースでのユーザーのセルフ登録を有効
|
|||||||
enable_captcha=登録時のCAPTCHAを有効にする
|
enable_captcha=登録時のCAPTCHAを有効にする
|
||||||
enable_captcha_popup=ユーザーのセルフ登録時にCAPTCHAを必須にします。
|
enable_captcha_popup=ユーザーのセルフ登録時にCAPTCHAを必須にします。
|
||||||
require_sign_in_view=ページ閲覧にサインインが必要
|
require_sign_in_view=ページ閲覧にサインインが必要
|
||||||
require_sign_in_view_popup=ページアクセスをサインイン済みユーザーに限定します。 訪問者はサインインページと登録ページだけ見ることができます。
|
|
||||||
admin_setting_desc=管理者アカウントの作成は任意です。 最初に登録したユーザーは自動的に管理者になります。
|
admin_setting_desc=管理者アカウントの作成は任意です。 最初に登録したユーザーは自動的に管理者になります。
|
||||||
admin_title=管理者アカウントの設定
|
admin_title=管理者アカウントの設定
|
||||||
admin_name=管理者ユーザー名
|
admin_name=管理者ユーザー名
|
||||||
@ -249,7 +247,6 @@ no_reply_address=メールを隠すときのドメイン
|
|||||||
no_reply_address_helper=メールアドレスを隠しているユーザーに使用するドメイン名。 例えば 'noreply.example.org' と設定した場合、ユーザー名 'joe' はGitに 'joe@noreply.example.org' としてログインすることになります。
|
no_reply_address_helper=メールアドレスを隠しているユーザーに使用するドメイン名。 例えば 'noreply.example.org' と設定した場合、ユーザー名 'joe' はGitに 'joe@noreply.example.org' としてログインすることになります。
|
||||||
password_algorithm=パスワードハッシュアルゴリズム
|
password_algorithm=パスワードハッシュアルゴリズム
|
||||||
invalid_password_algorithm=無効なパスワードハッシュアルゴリズム
|
invalid_password_algorithm=無効なパスワードハッシュアルゴリズム
|
||||||
password_algorithm_helper=パスワードハッシュアルゴリズムを設定します。 アルゴリズムにより動作要件と強度が異なります。 argon2アルゴリズムはかなり安全ですが、多くのメモリを使用するため小さなシステムには適さない場合があります。
|
|
||||||
enable_update_checker=アップデートチェッカーを有効にする
|
enable_update_checker=アップデートチェッカーを有効にする
|
||||||
enable_update_checker_helper=gitea.ioに接続して定期的に新しいバージョンのリリースを確認します。
|
enable_update_checker_helper=gitea.ioに接続して定期的に新しいバージョンのリリースを確認します。
|
||||||
|
|
||||||
@ -521,14 +518,8 @@ invalid_ssh_key=SSHキーが確認できません: %s
|
|||||||
invalid_gpg_key=GPGキーが確認できません: %s
|
invalid_gpg_key=GPGキーが確認できません: %s
|
||||||
invalid_ssh_principal=無効なプリンシパル: %s
|
invalid_ssh_principal=無効なプリンシパル: %s
|
||||||
must_use_public_key=あなたが提供したキーは秘密鍵です。秘密鍵をどこにもアップロードしないでください。代わりに公開鍵を使用してください。
|
must_use_public_key=あなたが提供したキーは秘密鍵です。秘密鍵をどこにもアップロードしないでください。代わりに公開鍵を使用してください。
|
||||||
unable_verify_ssh_key=SSHキーが確認できません。間違いが無いか、よく確認してください。
|
|
||||||
auth_failed=認証に失敗しました: %v
|
auth_failed=認証に失敗しました: %v
|
||||||
|
|
||||||
still_own_repo=あなたのアカウントは1つ以上のリポジトリを所有しています。 先にそれらを削除するか移転してください。
|
|
||||||
still_has_org=あなたのアカウントは1つ以上の組織に参加しています。 先にそれらから脱退してください。
|
|
||||||
still_own_packages=あなたのアカウントは1つ以上のパッケージを所有しています。 先にそれらを削除してください。
|
|
||||||
org_still_own_repo=組織はまだ1つ以上のリポジトリを所有しています。 先にそれらを削除するか移転してください。
|
|
||||||
org_still_own_packages=組織はまだ1つ以上のパッケージを所有しています。 先にそれらを削除してください。
|
|
||||||
|
|
||||||
target_branch_not_exist=ターゲットのブランチが存在していません。
|
target_branch_not_exist=ターゲットのブランチが存在していません。
|
||||||
|
|
||||||
@ -993,7 +984,6 @@ migrate.github_token_desc=GitHub APIにはレート制限があります。移
|
|||||||
migrate.clone_local_path=、またはローカルサーバー上のパス
|
migrate.clone_local_path=、またはローカルサーバー上のパス
|
||||||
migrate.permission_denied=ローカルリポジトリをインポートする権限がありません。
|
migrate.permission_denied=ローカルリポジトリをインポートする権限がありません。
|
||||||
migrate.permission_denied_blocked=許可されていないホストからインポートできません。管理者に問い合わせて、ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS の設定を確認してください。
|
migrate.permission_denied_blocked=許可されていないホストからインポートできません。管理者に問い合わせて、ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS の設定を確認してください。
|
||||||
migrate.invalid_local_path=ローカルパスが無効です。 存在しないかディレクトリではありません。
|
|
||||||
migrate.invalid_lfs_endpoint=LFS エンドポイントが無効です。
|
migrate.invalid_lfs_endpoint=LFS エンドポイントが無効です。
|
||||||
migrate.failed=移行に失敗しました: %v
|
migrate.failed=移行に失敗しました: %v
|
||||||
migrate.migrate_items_options=追加の項目を移行するにはアクセストークンが必要です
|
migrate.migrate_items_options=追加の項目を移行するにはアクセストークンが必要です
|
||||||
@ -1175,7 +1165,6 @@ commits.commits=コミット
|
|||||||
commits.no_commits=共通のコミットはありません。 '%s' と '%s' の履歴はすべて異なっています。
|
commits.no_commits=共通のコミットはありません。 '%s' と '%s' の履歴はすべて異なっています。
|
||||||
commits.nothing_to_compare=二つのブランチは同じ内容です。
|
commits.nothing_to_compare=二つのブランチは同じ内容です。
|
||||||
commits.search=コミットの検索…
|
commits.search=コミットの検索…
|
||||||
commits.search.tooltip=`キーワード "author:"、"committer:"、"after:"、"before:" を付けて指定できます。 例 "revert author:Alice before:2019-01-13"`
|
|
||||||
commits.find=検索
|
commits.find=検索
|
||||||
commits.search_all=すべてのブランチ
|
commits.search_all=すべてのブランチ
|
||||||
commits.author=作成者
|
commits.author=作成者
|
||||||
@ -1934,7 +1923,6 @@ settings.trust_model.collaborator.long=共同作業者: 共同作業者による
|
|||||||
settings.trust_model.collaborator.desc=このリポジトリの共同作業者による正常な署名は、(署名がコミッターのものかどうかにかかわらず)「信頼済み」とみなします。 署名が共同作業者ではないコミッターのものであれば「信頼不可」、それ以外は「不一致」となります。
|
settings.trust_model.collaborator.desc=このリポジトリの共同作業者による正常な署名は、(署名がコミッターのものかどうかにかかわらず)「信頼済み」とみなします。 署名が共同作業者ではないコミッターのものであれば「信頼不可」、それ以外は「不一致」となります。
|
||||||
settings.trust_model.committer=コミッター
|
settings.trust_model.committer=コミッター
|
||||||
settings.trust_model.committer.long=コミッター: コミッターによる署名を信頼します (これはGitHub方式であり、Giteaの署名が付いたコミットはコミッターがGitea自身であることが強制されます)
|
settings.trust_model.committer.long=コミッター: コミッターによる署名を信頼します (これはGitHub方式であり、Giteaの署名が付いたコミットはコミッターがGitea自身であることが強制されます)
|
||||||
settings.trust_model.committer.desc=正常な署名は、コミッターに一致する場合のみ「信頼済み」とみなし、それ以外は「不一致」となります。 Giteaは署名付きでコミットすることが強制され、本来のコミッターはコミットの最後に Co-authored-by: と Co-committed-by: で追加されます。 Giteaのデフォルト鍵はデータベース内のユーザー1人とマッチしなければなりません。
|
|
||||||
settings.trust_model.collaboratorcommitter=共同作業者+コミッター
|
settings.trust_model.collaboratorcommitter=共同作業者+コミッター
|
||||||
settings.trust_model.collaboratorcommitter.long=共同作業者+コミッター: コミッターと一致する共同作業者による署名を信頼します
|
settings.trust_model.collaboratorcommitter.long=共同作業者+コミッター: コミッターと一致する共同作業者による署名を信頼します
|
||||||
settings.trust_model.collaboratorcommitter.desc=このリポジトリの共同作業者による正常な署名は、コミッターと一致する場合に「信頼済み」とみなします。 それ以外の正常な署名のうち、コミッターに一致するものは「信頼不可」、他は「不一致」となります。 Giteaが署名付きコミットのコミッターであることが強制され、本来のコミッターはコミットの最後に Co-Authored-By: と Co-Committed-By: で追加されます。 Giteaのデフォルト鍵はデータベース内のユーザー1人とマッチしなければなりません。
|
settings.trust_model.collaboratorcommitter.desc=このリポジトリの共同作業者による正常な署名は、コミッターと一致する場合に「信頼済み」とみなします。 それ以外の正常な署名のうち、コミッターに一致するものは「信頼不可」、他は「不一致」となります。 Giteaが署名付きコミットのコミッターであることが強制され、本来のコミッターはコミットの最後に Co-Authored-By: と Co-Committed-By: で追加されます。 Giteaのデフォルト鍵はデータベース内のユーザー1人とマッチしなければなりません。
|
||||||
@ -2476,7 +2464,6 @@ teams.remove_all_repos_title=チームリポジトリをすべて除去
|
|||||||
teams.remove_all_repos_desc=チームからすべてのリポジトリを除去します。
|
teams.remove_all_repos_desc=チームからすべてのリポジトリを除去します。
|
||||||
teams.add_all_repos_title=すべてのリポジトリを追加
|
teams.add_all_repos_title=すべてのリポジトリを追加
|
||||||
teams.add_all_repos_desc=組織のすべてのリポジトリをチームに追加します。
|
teams.add_all_repos_desc=組織のすべてのリポジトリをチームに追加します。
|
||||||
teams.add_nonexistent_repo=追加しようとしているリポジトリは存在しません。 先にリポジトリを作成してください。
|
|
||||||
teams.add_duplicate_users=ユーザーは既にチームのメンバーです。
|
teams.add_duplicate_users=ユーザーは既にチームのメンバーです。
|
||||||
teams.repos.none=このチームがアクセスできるリポジトリはありません。
|
teams.repos.none=このチームがアクセスできるリポジトリはありません。
|
||||||
teams.members.none=このチームにはメンバーがいません。
|
teams.members.none=このチームにはメンバーがいません。
|
||||||
@ -2506,7 +2493,6 @@ first_page=最初
|
|||||||
last_page=最後
|
last_page=最後
|
||||||
total=合計: %d
|
total=合計: %d
|
||||||
|
|
||||||
dashboard.new_version_hint=Gitea %s が入手可能になりました。 現在実行しているのは %s です。 詳細は <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">ブログ</a> を確認してください。
|
|
||||||
dashboard.statistic=サマリー
|
dashboard.statistic=サマリー
|
||||||
dashboard.operations=メンテナンス操作
|
dashboard.operations=メンテナンス操作
|
||||||
dashboard.system_status=システム状況
|
dashboard.system_status=システム状況
|
||||||
@ -2626,7 +2612,6 @@ users.still_own_repo=このユーザーはまだ1つ以上のリポジトリを
|
|||||||
users.still_has_org=このユーザーは組織のメンバーになっています。 先に組織からこのユーザーを削除してください。
|
users.still_has_org=このユーザーは組織のメンバーになっています。 先に組織からこのユーザーを削除してください。
|
||||||
users.purge=ユーザーを抹消
|
users.purge=ユーザーを抹消
|
||||||
users.purge_help=強制的にユーザーとそのユーザーが所有していたリポジトリ、組織、パッケージを削除します。コメントもすべて削除します。
|
users.purge_help=強制的にユーザーとそのユーザーが所有していたリポジトリ、組織、パッケージを削除します。コメントもすべて削除します。
|
||||||
users.still_own_packages=このユーザーはまだ1つ以上のパッケージを所有しています。先にそれらのパッケージを削除してください。
|
|
||||||
users.deletion_success=ユーザーアカウントを削除しました。
|
users.deletion_success=ユーザーアカウントを削除しました。
|
||||||
users.reset_2fa=2要素認証をリセット
|
users.reset_2fa=2要素認証をリセット
|
||||||
users.list_status_filter.menu_text=フィルター
|
users.list_status_filter.menu_text=フィルター
|
||||||
|
@ -13,9 +13,6 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unit"
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
npm_module "code.gitea.io/gitea/modules/packages/npm"
|
npm_module "code.gitea.io/gitea/modules/packages/npm"
|
||||||
@ -169,26 +166,6 @@ func UploadPackage(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := repo_model.GetRepositoryByURL(ctx, npmPackage.Metadata.Repository.URL)
|
|
||||||
if err == nil {
|
|
||||||
canWrite := repo.OwnerID == ctx.Doer.ID
|
|
||||||
|
|
||||||
if !canWrite {
|
|
||||||
perms, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
|
|
||||||
if err != nil {
|
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
canWrite = perms.CanWrite(unit.TypePackages)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !canWrite {
|
|
||||||
apiError(ctx, http.StatusForbidden, "no permission to upload this package")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, err := packages_module.CreateHashedBufferFromReader(bytes.NewReader(npmPackage.Data), 32*1024*1024)
|
buf, err := packages_module.CreateHashedBufferFromReader(bytes.NewReader(npmPackage.Data), 32*1024*1024)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
@ -240,13 +217,6 @@ func UploadPackage(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if repo != nil {
|
|
||||||
if err := packages_model.SetRepositoryLink(ctx, pv.PackageID, repo.ID); err != nil {
|
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Status(http.StatusCreated)
|
ctx.Status(http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1026,14 +1026,6 @@ func Routes(ctx gocontext.Context) *web.Route {
|
|||||||
Patch(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueAttachment).
|
Patch(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueAttachment).
|
||||||
Delete(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, repo.DeleteIssueAttachment)
|
Delete(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, repo.DeleteIssueAttachment)
|
||||||
}, mustEnableAttachments)
|
}, mustEnableAttachments)
|
||||||
m.Combo("/dependencies").
|
|
||||||
Get(repo.GetIssueDependencies).
|
|
||||||
Post(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.IssueMeta{}), repo.CreateIssueDependency).
|
|
||||||
Delete(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.IssueMeta{}), repo.RemoveIssueDependency)
|
|
||||||
m.Combo("/blocks").
|
|
||||||
Get(repo.GetIssueBlocks).
|
|
||||||
Post(reqToken(auth_model.AccessTokenScopeRepo), bind(api.IssueMeta{}), repo.CreateIssueBlocking).
|
|
||||||
Delete(reqToken(auth_model.AccessTokenScopeRepo), bind(api.IssueMeta{}), repo.RemoveIssueBlocking)
|
|
||||||
})
|
})
|
||||||
}, mustEnableIssuesOrPulls)
|
}, mustEnableIssuesOrPulls)
|
||||||
m.Group("/labels", func() {
|
m.Group("/labels", func() {
|
||||||
@ -1169,8 +1161,6 @@ func Routes(ctx gocontext.Context) *web.Route {
|
|||||||
}, reqAdmin())
|
}, reqAdmin())
|
||||||
}, reqAnyRepoReader())
|
}, reqAnyRepoReader())
|
||||||
m.Get("/issue_templates", context.ReferencesGitRepo(), repo.GetIssueTemplates)
|
m.Get("/issue_templates", context.ReferencesGitRepo(), repo.GetIssueTemplates)
|
||||||
m.Get("/issue_config", context.ReferencesGitRepo(), repo.GetIssueConfig)
|
|
||||||
m.Get("/issue_config/validate", context.ReferencesGitRepo(), repo.ValidateIssueConfig)
|
|
||||||
m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages)
|
m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages)
|
||||||
}, repoAssignment())
|
}, repoAssignment())
|
||||||
})
|
})
|
||||||
|
@ -1,598 +0,0 @@
|
|||||||
// Copyright 2016 The Gogs Authors. All rights reserved.
|
|
||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package repo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
|
||||||
"code.gitea.io/gitea/modules/web"
|
|
||||||
"code.gitea.io/gitea/services/convert"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetIssueDependencies list an issue's dependencies
|
|
||||||
func GetIssueDependencies(ctx *context.APIContext) {
|
|
||||||
// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/dependencies issue issueListIssueDependencies
|
|
||||||
// ---
|
|
||||||
// summary: List an issue's dependencies, i.e all issues that block this issue.
|
|
||||||
// produces:
|
|
||||||
// - application/json
|
|
||||||
// parameters:
|
|
||||||
// - name: owner
|
|
||||||
// in: path
|
|
||||||
// description: owner of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: repo
|
|
||||||
// in: path
|
|
||||||
// description: name of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: index
|
|
||||||
// in: path
|
|
||||||
// description: index of the issue
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: page
|
|
||||||
// in: query
|
|
||||||
// description: page number of results to return (1-based)
|
|
||||||
// type: integer
|
|
||||||
// - name: limit
|
|
||||||
// in: query
|
|
||||||
// description: page size of results
|
|
||||||
// type: integer
|
|
||||||
// responses:
|
|
||||||
// "200":
|
|
||||||
// "$ref": "#/responses/IssueList"
|
|
||||||
|
|
||||||
// If this issue's repository does not enable dependencies then there can be no dependencies by default
|
|
||||||
if !ctx.Repo.Repository.IsDependenciesEnabled(ctx) {
|
|
||||||
ctx.NotFound()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
|
||||||
if err != nil {
|
|
||||||
if issues_model.IsErrIssueNotExist(err) {
|
|
||||||
ctx.NotFound("IsErrIssueNotExist", err)
|
|
||||||
} else {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. We must be able to read this issue
|
|
||||||
if !ctx.Repo.Permission.CanReadIssuesOrPulls(issue.IsPull) {
|
|
||||||
ctx.NotFound()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page := ctx.FormInt("page")
|
|
||||||
if page <= 1 {
|
|
||||||
page = 1
|
|
||||||
}
|
|
||||||
limit := ctx.FormInt("limit")
|
|
||||||
if limit == 0 {
|
|
||||||
limit = setting.API.DefaultPagingNum
|
|
||||||
} else if limit > setting.API.MaxResponseItems {
|
|
||||||
limit = setting.API.MaxResponseItems
|
|
||||||
}
|
|
||||||
|
|
||||||
canWrite := ctx.Repo.Permission.CanWriteIssuesOrPulls(issue.IsPull)
|
|
||||||
|
|
||||||
blockerIssues := make([]*issues_model.Issue, 0, limit)
|
|
||||||
|
|
||||||
// 2. Get the issues this issue depends on, i.e. the `<#b>`: `<issue> <- <#b>`
|
|
||||||
blockersInfo, err := issue.BlockedByDependencies(ctx, db.ListOptions{
|
|
||||||
Page: page,
|
|
||||||
PageSize: limit,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "BlockedByDependencies", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastRepoID int64
|
|
||||||
var lastPerm access_model.Permission
|
|
||||||
for _, blocker := range blockersInfo {
|
|
||||||
// Get the permissions for this repository
|
|
||||||
perm := lastPerm
|
|
||||||
if lastRepoID != blocker.Repository.ID {
|
|
||||||
if blocker.Repository.ID == ctx.Repo.Repository.ID {
|
|
||||||
perm = ctx.Repo.Permission
|
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
perm, err = access_model.GetUserRepoPermission(ctx, &blocker.Repository, ctx.Doer)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("GetUserRepoPermission", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastRepoID = blocker.Repository.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// check permission
|
|
||||||
if !perm.CanReadIssuesOrPulls(blocker.Issue.IsPull) {
|
|
||||||
if !canWrite {
|
|
||||||
hiddenBlocker := &issues_model.DependencyInfo{
|
|
||||||
Issue: issues_model.Issue{
|
|
||||||
Title: "HIDDEN",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
blocker = hiddenBlocker
|
|
||||||
} else {
|
|
||||||
confidentialBlocker := &issues_model.DependencyInfo{
|
|
||||||
Issue: issues_model.Issue{
|
|
||||||
RepoID: blocker.Issue.RepoID,
|
|
||||||
Index: blocker.Index,
|
|
||||||
Title: blocker.Title,
|
|
||||||
IsClosed: blocker.IsClosed,
|
|
||||||
IsPull: blocker.IsPull,
|
|
||||||
},
|
|
||||||
Repository: repo_model.Repository{
|
|
||||||
ID: blocker.Issue.Repo.ID,
|
|
||||||
Name: blocker.Issue.Repo.Name,
|
|
||||||
OwnerName: blocker.Issue.Repo.OwnerName,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
confidentialBlocker.Issue.Repo = &confidentialBlocker.Repository
|
|
||||||
blocker = confidentialBlocker
|
|
||||||
}
|
|
||||||
}
|
|
||||||
blockerIssues = append(blockerIssues, &blocker.Issue)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, blockerIssues))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateIssueDependency create a new issue dependencies
|
|
||||||
func CreateIssueDependency(ctx *context.APIContext) {
|
|
||||||
// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/dependencies issue issueCreateIssueDependencies
|
|
||||||
// ---
|
|
||||||
// summary: Make the issue in the url depend on the issue in the form.
|
|
||||||
// produces:
|
|
||||||
// - application/json
|
|
||||||
// parameters:
|
|
||||||
// - name: owner
|
|
||||||
// in: path
|
|
||||||
// description: owner of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: repo
|
|
||||||
// in: path
|
|
||||||
// description: name of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: index
|
|
||||||
// in: path
|
|
||||||
// description: index of the issue
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: body
|
|
||||||
// in: body
|
|
||||||
// schema:
|
|
||||||
// "$ref": "#/definitions/IssueMeta"
|
|
||||||
// responses:
|
|
||||||
// "201":
|
|
||||||
// "$ref": "#/responses/Issue"
|
|
||||||
// "404":
|
|
||||||
// description: the issue does not exist
|
|
||||||
|
|
||||||
// We want to make <:index> depend on <Form>, i.e. <:index> is the target
|
|
||||||
target := getParamsIssue(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// and <Form> represents the dependency
|
|
||||||
form := web.GetForm(ctx).(*api.IssueMeta)
|
|
||||||
dependency := getFormIssue(ctx, form)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencyPerm := getPermissionForRepo(ctx, target.Repo)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
createIssueDependency(ctx, target, dependency, ctx.Repo.Permission, *dependencyPerm)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveIssueDependency remove an issue dependency
|
|
||||||
func RemoveIssueDependency(ctx *context.APIContext) {
|
|
||||||
// swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/dependencies issue issueRemoveIssueDependencies
|
|
||||||
// ---
|
|
||||||
// summary: Remove an issue dependency
|
|
||||||
// produces:
|
|
||||||
// - application/json
|
|
||||||
// parameters:
|
|
||||||
// - name: owner
|
|
||||||
// in: path
|
|
||||||
// description: owner of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: repo
|
|
||||||
// in: path
|
|
||||||
// description: name of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: index
|
|
||||||
// in: path
|
|
||||||
// description: index of the issue
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: body
|
|
||||||
// in: body
|
|
||||||
// schema:
|
|
||||||
// "$ref": "#/definitions/IssueMeta"
|
|
||||||
// responses:
|
|
||||||
// "200":
|
|
||||||
// "$ref": "#/responses/Issue"
|
|
||||||
|
|
||||||
// We want to make <:index> depend on <Form>, i.e. <:index> is the target
|
|
||||||
target := getParamsIssue(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// and <Form> represents the dependency
|
|
||||||
form := web.GetForm(ctx).(*api.IssueMeta)
|
|
||||||
dependency := getFormIssue(ctx, form)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencyPerm := getPermissionForRepo(ctx, target.Repo)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
removeIssueDependency(ctx, target, dependency, ctx.Repo.Permission, *dependencyPerm)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetIssueBlocks list issues that are blocked by this issue
|
|
||||||
func GetIssueBlocks(ctx *context.APIContext) {
|
|
||||||
// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/blocks issue issueListBlocks
|
|
||||||
// ---
|
|
||||||
// summary: List issues that are blocked by this issue
|
|
||||||
// produces:
|
|
||||||
// - application/json
|
|
||||||
// parameters:
|
|
||||||
// - name: owner
|
|
||||||
// in: path
|
|
||||||
// description: owner of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: repo
|
|
||||||
// in: path
|
|
||||||
// description: name of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: index
|
|
||||||
// in: path
|
|
||||||
// description: index of the issue
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: page
|
|
||||||
// in: query
|
|
||||||
// description: page number of results to return (1-based)
|
|
||||||
// type: integer
|
|
||||||
// - name: limit
|
|
||||||
// in: query
|
|
||||||
// description: page size of results
|
|
||||||
// type: integer
|
|
||||||
// responses:
|
|
||||||
// "200":
|
|
||||||
// "$ref": "#/responses/IssueList"
|
|
||||||
|
|
||||||
// We need to list the issues that DEPEND on this issue not the other way round
|
|
||||||
// Therefore whether dependencies are enabled or not in this repository is potentially irrelevant.
|
|
||||||
|
|
||||||
issue := getParamsIssue(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ctx.Repo.Permission.CanReadIssuesOrPulls(issue.IsPull) {
|
|
||||||
ctx.NotFound()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page := ctx.FormInt("page")
|
|
||||||
if page <= 1 {
|
|
||||||
page = 1
|
|
||||||
}
|
|
||||||
limit := ctx.FormInt("limit")
|
|
||||||
if limit <= 1 {
|
|
||||||
limit = setting.API.DefaultPagingNum
|
|
||||||
}
|
|
||||||
|
|
||||||
skip := (page - 1) * limit
|
|
||||||
max := page * limit
|
|
||||||
|
|
||||||
deps, err := issue.BlockingDependencies(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "BlockingDependencies", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastRepoID int64
|
|
||||||
var lastPerm access_model.Permission
|
|
||||||
|
|
||||||
var issues []*issues_model.Issue
|
|
||||||
for i, depMeta := range deps {
|
|
||||||
if i < skip || i >= max {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the permissions for this repository
|
|
||||||
perm := lastPerm
|
|
||||||
if lastRepoID != depMeta.Repository.ID {
|
|
||||||
if depMeta.Repository.ID == ctx.Repo.Repository.ID {
|
|
||||||
perm = ctx.Repo.Permission
|
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
perm, err = access_model.GetUserRepoPermission(ctx, &depMeta.Repository, ctx.Doer)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("GetUserRepoPermission", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastRepoID = depMeta.Repository.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
if !perm.CanReadIssuesOrPulls(depMeta.Issue.IsPull) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
depMeta.Issue.Repo = &depMeta.Repository
|
|
||||||
issues = append(issues, &depMeta.Issue)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateIssueBlocking block the issue given in the body by the issue in path
|
|
||||||
func CreateIssueBlocking(ctx *context.APIContext) {
|
|
||||||
// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/blocks issue issueCreateIssueBlocking
|
|
||||||
// ---
|
|
||||||
// summary: Block the issue given in the body by the issue in path
|
|
||||||
// produces:
|
|
||||||
// - application/json
|
|
||||||
// parameters:
|
|
||||||
// - name: owner
|
|
||||||
// in: path
|
|
||||||
// description: owner of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: repo
|
|
||||||
// in: path
|
|
||||||
// description: name of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: index
|
|
||||||
// in: path
|
|
||||||
// description: index of the issue
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: body
|
|
||||||
// in: body
|
|
||||||
// schema:
|
|
||||||
// "$ref": "#/definitions/IssueMeta"
|
|
||||||
// responses:
|
|
||||||
// "201":
|
|
||||||
// "$ref": "#/responses/Issue"
|
|
||||||
// "404":
|
|
||||||
// description: the issue does not exist
|
|
||||||
|
|
||||||
dependency := getParamsIssue(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.IssueMeta)
|
|
||||||
target := getFormIssue(ctx, form)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
targetPerm := getPermissionForRepo(ctx, target.Repo)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
createIssueDependency(ctx, target, dependency, *targetPerm, ctx.Repo.Permission)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, dependency))
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveIssueBlocking unblock the issue given in the body by the issue in path
|
|
||||||
func RemoveIssueBlocking(ctx *context.APIContext) {
|
|
||||||
// swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/blocks issue issueRemoveIssueBlocking
|
|
||||||
// ---
|
|
||||||
// summary: Unblock the issue given in the body by the issue in path
|
|
||||||
// produces:
|
|
||||||
// - application/json
|
|
||||||
// parameters:
|
|
||||||
// - name: owner
|
|
||||||
// in: path
|
|
||||||
// description: owner of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: repo
|
|
||||||
// in: path
|
|
||||||
// description: name of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: index
|
|
||||||
// in: path
|
|
||||||
// description: index of the issue
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: body
|
|
||||||
// in: body
|
|
||||||
// schema:
|
|
||||||
// "$ref": "#/definitions/IssueMeta"
|
|
||||||
// responses:
|
|
||||||
// "200":
|
|
||||||
// "$ref": "#/responses/Issue"
|
|
||||||
|
|
||||||
dependency := getParamsIssue(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.IssueMeta)
|
|
||||||
target := getFormIssue(ctx, form)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
targetPerm := getPermissionForRepo(ctx, target.Repo)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
removeIssueDependency(ctx, target, dependency, *targetPerm, ctx.Repo.Permission)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, dependency))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getParamsIssue(ctx *context.APIContext) *issues_model.Issue {
|
|
||||||
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
|
||||||
if err != nil {
|
|
||||||
if issues_model.IsErrIssueNotExist(err) {
|
|
||||||
ctx.NotFound("IsErrIssueNotExist", err)
|
|
||||||
} else {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
issue.Repo = ctx.Repo.Repository
|
|
||||||
return issue
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFormIssue(ctx *context.APIContext, form *api.IssueMeta) *issues_model.Issue {
|
|
||||||
var repo *repo_model.Repository
|
|
||||||
if form.Owner != ctx.Repo.Repository.OwnerName || form.Name != ctx.Repo.Repository.Name {
|
|
||||||
if !setting.Service.AllowCrossRepositoryDependencies {
|
|
||||||
ctx.JSON(http.StatusBadRequest, "CrossRepositoryDependencies not enabled")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
repo, err = repo_model.GetRepositoryByOwnerAndName(ctx, form.Owner, form.Name)
|
|
||||||
if err != nil {
|
|
||||||
if repo_model.IsErrRepoNotExist(err) {
|
|
||||||
ctx.NotFound("IsErrRepoNotExist", err)
|
|
||||||
} else {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "GetRepositoryByOwnerAndName", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
repo = ctx.Repo.Repository
|
|
||||||
}
|
|
||||||
|
|
||||||
issue, err := issues_model.GetIssueByIndex(repo.ID, form.Index)
|
|
||||||
if err != nil {
|
|
||||||
if issues_model.IsErrIssueNotExist(err) {
|
|
||||||
ctx.NotFound("IsErrIssueNotExist", err)
|
|
||||||
} else {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
issue.Repo = repo
|
|
||||||
return issue
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPermissionForRepo(ctx *context.APIContext, repo *repo_model.Repository) *access_model.Permission {
|
|
||||||
if repo.ID == ctx.Repo.Repository.ID {
|
|
||||||
return &ctx.Repo.Permission
|
|
||||||
}
|
|
||||||
|
|
||||||
perm, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &perm
|
|
||||||
}
|
|
||||||
|
|
||||||
func createIssueDependency(ctx *context.APIContext, target, dependency *issues_model.Issue, targetPerm, dependencyPerm access_model.Permission) {
|
|
||||||
if target.Repo.IsArchived || !target.Repo.IsDependenciesEnabled(ctx) {
|
|
||||||
// The target's repository doesn't have dependencies enabled
|
|
||||||
ctx.NotFound()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !targetPerm.CanWriteIssuesOrPulls(target.IsPull) {
|
|
||||||
// We can't write to the target
|
|
||||||
ctx.NotFound()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dependencyPerm.CanReadIssuesOrPulls(dependency.IsPull) {
|
|
||||||
// We can't read the dependency
|
|
||||||
ctx.NotFound()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err := issues_model.CreateIssueDependency(ctx.Doer, target, dependency)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "CreateIssueDependency", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeIssueDependency(ctx *context.APIContext, target, dependency *issues_model.Issue, targetPerm, dependencyPerm access_model.Permission) {
|
|
||||||
if target.Repo.IsArchived || !target.Repo.IsDependenciesEnabled(ctx) {
|
|
||||||
// The target's repository doesn't have dependencies enabled
|
|
||||||
ctx.NotFound()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !targetPerm.CanWriteIssuesOrPulls(target.IsPull) {
|
|
||||||
// We can't write to the target
|
|
||||||
ctx.NotFound()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dependencyPerm.CanReadIssuesOrPulls(dependency.IsPull) {
|
|
||||||
// We can't read the dependency
|
|
||||||
ctx.NotFound()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err := issues_model.RemoveIssueDependency(ctx.Doer, target, dependency, issues_model.DependencyTypeBlockedBy)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "CreateIssueDependency", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
@ -1144,58 +1144,3 @@ func GetIssueTemplates(ctx *context.APIContext) {
|
|||||||
|
|
||||||
ctx.JSON(http.StatusOK, ctx.IssueTemplatesFromDefaultBranch())
|
ctx.JSON(http.StatusOK, ctx.IssueTemplatesFromDefaultBranch())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssueConfig returns the issue config for a repo
|
|
||||||
func GetIssueConfig(ctx *context.APIContext) {
|
|
||||||
// swagger:operation GET /repos/{owner}/{repo}/issue_config repository repoGetIssueConfig
|
|
||||||
// ---
|
|
||||||
// summary: Returns the issue config for a repo
|
|
||||||
// produces:
|
|
||||||
// - application/json
|
|
||||||
// parameters:
|
|
||||||
// - name: owner
|
|
||||||
// in: path
|
|
||||||
// description: owner of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: repo
|
|
||||||
// in: path
|
|
||||||
// description: name of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// responses:
|
|
||||||
// "200":
|
|
||||||
// "$ref": "#/responses/RepoIssueConfig"
|
|
||||||
issueConfig, _ := ctx.IssueConfigFromDefaultBranch()
|
|
||||||
ctx.JSON(http.StatusOK, issueConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateIssueConfig returns validation errors for the issue config
|
|
||||||
func ValidateIssueConfig(ctx *context.APIContext) {
|
|
||||||
// swagger:operation GET /repos/{owner}/{repo}/issue_config/validate repository repoValidateIssueConfig
|
|
||||||
// ---
|
|
||||||
// summary: Returns the validation information for a issue config
|
|
||||||
// produces:
|
|
||||||
// - application/json
|
|
||||||
// parameters:
|
|
||||||
// - name: owner
|
|
||||||
// in: path
|
|
||||||
// description: owner of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// - name: repo
|
|
||||||
// in: path
|
|
||||||
// description: name of the repo
|
|
||||||
// type: string
|
|
||||||
// required: true
|
|
||||||
// responses:
|
|
||||||
// "200":
|
|
||||||
// "$ref": "#/responses/RepoIssueConfigValidation"
|
|
||||||
_, err := ctx.IssueConfigFromDefaultBranch()
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
ctx.JSON(http.StatusOK, api.IssueConfigValidation{Valid: true, Message: ""})
|
|
||||||
} else {
|
|
||||||
ctx.JSON(http.StatusOK, api.IssueConfigValidation{Valid: false, Message: err.Error()})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -41,8 +41,6 @@ type swaggerParameterBodies struct {
|
|||||||
CreateIssueCommentOption api.CreateIssueCommentOption
|
CreateIssueCommentOption api.CreateIssueCommentOption
|
||||||
// in:body
|
// in:body
|
||||||
EditIssueCommentOption api.EditIssueCommentOption
|
EditIssueCommentOption api.EditIssueCommentOption
|
||||||
// in:body
|
|
||||||
IssueMeta api.IssueMeta
|
|
||||||
|
|
||||||
// in:body
|
// in:body
|
||||||
IssueLabelsOption api.IssueLabelsOption
|
IssueLabelsOption api.IssueLabelsOption
|
||||||
|
@ -386,17 +386,3 @@ type swaggerRepoCollaboratorPermission struct {
|
|||||||
// in:body
|
// in:body
|
||||||
Body api.RepoCollaboratorPermission `json:"body"`
|
Body api.RepoCollaboratorPermission `json:"body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RepoIssueConfig
|
|
||||||
// swagger:response RepoIssueConfig
|
|
||||||
type swaggerRepoIssueConfig struct {
|
|
||||||
// in:body
|
|
||||||
Body api.IssueConfig `json:"body"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RepoIssueConfigValidation
|
|
||||||
// swagger:response RepoIssueConfigValidation
|
|
||||||
type swaggerRepoIssueConfigValidation struct {
|
|
||||||
// in:body
|
|
||||||
Body api.IssueConfigValidation `json:"body"`
|
|
||||||
}
|
|
||||||
|
@ -435,7 +435,7 @@ func Issues(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.issues")
|
ctx.Data["Title"] = ctx.Tr("repo.issues")
|
||||||
ctx.Data["PageIsIssueList"] = true
|
ctx.Data["PageIsIssueList"] = true
|
||||||
ctx.Data["NewIssueChooseTemplate"] = ctx.HasIssueTemplatesOrContactLinks()
|
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
issues(ctx, ctx.FormInt64("milestone"), ctx.FormInt64("project"), util.OptionalBoolOf(isPullList))
|
issues(ctx, ctx.FormInt64("milestone"), ctx.FormInt64("project"), util.OptionalBoolOf(isPullList))
|
||||||
@ -848,7 +848,7 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles
|
|||||||
func NewIssue(ctx *context.Context) {
|
func NewIssue(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
||||||
ctx.Data["PageIsIssueList"] = true
|
ctx.Data["PageIsIssueList"] = true
|
||||||
ctx.Data["NewIssueChooseTemplate"] = ctx.HasIssueTemplatesOrContactLinks()
|
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
|
||||||
ctx.Data["RequireTribute"] = true
|
ctx.Data["RequireTribute"] = true
|
||||||
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
|
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
|
||||||
title := ctx.FormString("title")
|
title := ctx.FormString("title")
|
||||||
@ -946,16 +946,12 @@ func NewIssueChooseTemplate(ctx *context.Context) {
|
|||||||
ctx.Flash.Warning(renderErrorOfTemplates(ctx, errs), true)
|
ctx.Flash.Warning(renderErrorOfTemplates(ctx, errs), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.HasIssueTemplatesOrContactLinks() {
|
if len(issueTemplates) == 0 {
|
||||||
// The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if no template here, just redirect to the "issues/new" page with these parameters.
|
// The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if no template here, just redirect to the "issues/new" page with these parameters.
|
||||||
ctx.Redirect(fmt.Sprintf("%s/issues/new?%s", ctx.Repo.Repository.Link(), ctx.Req.URL.RawQuery), http.StatusSeeOther)
|
ctx.Redirect(fmt.Sprintf("%s/issues/new?%s", ctx.Repo.Repository.Link(), ctx.Req.URL.RawQuery), http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
issueConfig, err := ctx.IssueConfigFromDefaultBranch()
|
|
||||||
ctx.Data["IssueConfig"] = issueConfig
|
|
||||||
ctx.Data["IssueConfigError"] = err // ctx.Flash.Err makes problems here
|
|
||||||
|
|
||||||
ctx.Data["milestone"] = ctx.FormInt64("milestone")
|
ctx.Data["milestone"] = ctx.FormInt64("milestone")
|
||||||
ctx.Data["project"] = ctx.FormInt64("project")
|
ctx.Data["project"] = ctx.FormInt64("project")
|
||||||
|
|
||||||
@ -1090,7 +1086,7 @@ func NewIssuePost(ctx *context.Context) {
|
|||||||
form := web.GetForm(ctx).(*forms.CreateIssueForm)
|
form := web.GetForm(ctx).(*forms.CreateIssueForm)
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
||||||
ctx.Data["PageIsIssueList"] = true
|
ctx.Data["PageIsIssueList"] = true
|
||||||
ctx.Data["NewIssueChooseTemplate"] = ctx.HasIssueTemplatesOrContactLinks()
|
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
|
||||||
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
|
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
|
||||||
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
|
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
|
||||||
upload.AddUploadContext(ctx, "comment")
|
upload.AddUploadContext(ctx, "comment")
|
||||||
@ -1284,7 +1280,7 @@ func ViewIssue(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["PageIsIssueList"] = true
|
ctx.Data["PageIsIssueList"] = true
|
||||||
ctx.Data["NewIssueChooseTemplate"] = ctx.HasIssueTemplatesOrContactLinks()
|
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.IsPull && !ctx.Repo.CanRead(unit.TypeIssues) {
|
if issue.IsPull && !ctx.Repo.CanRead(unit.TypeIssues) {
|
||||||
@ -1816,27 +1812,17 @@ func ViewIssue(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get Dependencies
|
// Get Dependencies
|
||||||
blockedBy, err := issue.BlockedByDependencies(ctx, db.ListOptions{})
|
ctx.Data["BlockedByDependencies"], err = issue.BlockedByDependencies(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("BlockedByDependencies", err)
|
ctx.ServerError("BlockedByDependencies", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["BlockedByDependencies"], ctx.Data["BlockedByDependenciesNotPermitted"] = checkBlockedByIssues(ctx, blockedBy)
|
ctx.Data["BlockingDependencies"], err = issue.BlockingDependencies(ctx)
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
blocking, err := issue.BlockingDependencies(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("BlockingDependencies", err)
|
ctx.ServerError("BlockingDependencies", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["BlockingDependencies"], ctx.Data["BlockingByDependenciesNotPermitted"] = checkBlockedByIssues(ctx, blocking)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["Participants"] = participants
|
ctx.Data["Participants"] = participants
|
||||||
ctx.Data["NumParticipants"] = len(participants)
|
ctx.Data["NumParticipants"] = len(participants)
|
||||||
ctx.Data["Issue"] = issue
|
ctx.Data["Issue"] = issue
|
||||||
@ -1865,48 +1851,6 @@ func ViewIssue(ctx *context.Context) {
|
|||||||
ctx.HTML(http.StatusOK, tplIssueView)
|
ctx.HTML(http.StatusOK, tplIssueView)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkBlockedByIssues(ctx *context.Context, blockers []*issues_model.DependencyInfo) (canRead, notPermitted []*issues_model.DependencyInfo) {
|
|
||||||
var lastRepoID int64
|
|
||||||
var lastPerm access_model.Permission
|
|
||||||
for i, blocker := range blockers {
|
|
||||||
// Get the permissions for this repository
|
|
||||||
perm := lastPerm
|
|
||||||
if lastRepoID != blocker.Repository.ID {
|
|
||||||
if blocker.Repository.ID == ctx.Repo.Repository.ID {
|
|
||||||
perm = ctx.Repo.Permission
|
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
perm, err = access_model.GetUserRepoPermission(ctx, &blocker.Repository, ctx.Doer)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("GetUserRepoPermission", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastRepoID = blocker.Repository.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// check permission
|
|
||||||
if !perm.CanReadIssuesOrPulls(blocker.Issue.IsPull) {
|
|
||||||
blockers[len(notPermitted)], blockers[i] = blocker, blockers[len(notPermitted)]
|
|
||||||
notPermitted = blockers[:len(notPermitted)+1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
blockers = blockers[len(notPermitted):]
|
|
||||||
sortDependencyInfo(blockers)
|
|
||||||
sortDependencyInfo(notPermitted)
|
|
||||||
|
|
||||||
return blockers, notPermitted
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortDependencyInfo(blockers []*issues_model.DependencyInfo) {
|
|
||||||
sort.Slice(blockers, func(i, j int) bool {
|
|
||||||
if blockers[i].RepoID == blockers[j].RepoID {
|
|
||||||
return blockers[i].Issue.CreatedUnix < blockers[j].Issue.CreatedUnix
|
|
||||||
}
|
|
||||||
return blockers[i].RepoID < blockers[j].RepoID
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetActionIssue will return the issue which is used in the context.
|
// GetActionIssue will return the issue which is used in the context.
|
||||||
func GetActionIssue(ctx *context.Context) *issues_model.Issue {
|
func GetActionIssue(ctx *context.Context) *issues_model.Issue {
|
||||||
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
@ -45,25 +44,9 @@ func AddDependency(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if both issues are in the same repo if cross repository dependencies is not enabled
|
// Check if both issues are in the same repo if cross repository dependencies is not enabled
|
||||||
if issue.RepoID != dep.RepoID {
|
if issue.RepoID != dep.RepoID && !setting.Service.AllowCrossRepositoryDependencies {
|
||||||
if !setting.Service.AllowCrossRepositoryDependencies {
|
ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_dep_not_same_repo"))
|
||||||
ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_dep_not_same_repo"))
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := dep.LoadRepo(ctx); err != nil {
|
|
||||||
ctx.ServerError("loadRepo", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Can ctx.Doer read issues in the dep repo?
|
|
||||||
depRepoPerm, err := access_model.GetUserRepoPermission(ctx, dep.Repo, ctx.Doer)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("GetUserRepoPermission", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !depRepoPerm.CanReadIssuesOrPulls(dep.IsPull) {
|
|
||||||
// you can't see this dependency
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if issue and dependency is the same
|
// Check if issue and dependency is the same
|
||||||
|
@ -348,9 +348,6 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
|||||||
if ctx.Repo.TreePath == ".editorconfig" {
|
if ctx.Repo.TreePath == ".editorconfig" {
|
||||||
_, editorconfigErr := ctx.Repo.GetEditorconfig(ctx.Repo.Commit)
|
_, editorconfigErr := ctx.Repo.GetEditorconfig(ctx.Repo.Commit)
|
||||||
ctx.Data["FileError"] = editorconfigErr
|
ctx.Data["FileError"] = editorconfigErr
|
||||||
} else if ctx.Repo.IsIssueConfig(ctx.Repo.TreePath) {
|
|
||||||
_, issueConfigErr := ctx.Repo.GetIssueConfig(ctx.Repo.TreePath, ctx.Repo.Commit)
|
|
||||||
ctx.Data["FileError"] = issueConfigErr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isDisplayingSource := ctx.FormString("display") == "source"
|
isDisplayingSource := ctx.FormString("display") == "source"
|
||||||
|
@ -32,15 +32,21 @@ func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
|
|||||||
if err := issue.LoadRepo(ctx); err != nil {
|
if err := issue.LoadRepo(ctx); err != nil {
|
||||||
return &api.Issue{}
|
return &api.Issue{}
|
||||||
}
|
}
|
||||||
|
if err := issue.Repo.LoadOwner(ctx); err != nil {
|
||||||
|
return &api.Issue{}
|
||||||
|
}
|
||||||
|
|
||||||
apiIssue := &api.Issue{
|
apiIssue := &api.Issue{
|
||||||
ID: issue.ID,
|
ID: issue.ID,
|
||||||
|
URL: issue.APIURL(),
|
||||||
|
HTMLURL: issue.HTMLURL(),
|
||||||
Index: issue.Index,
|
Index: issue.Index,
|
||||||
Poster: ToUser(ctx, issue.Poster, nil),
|
Poster: ToUser(ctx, issue.Poster, nil),
|
||||||
Title: issue.Title,
|
Title: issue.Title,
|
||||||
Body: issue.Content,
|
Body: issue.Content,
|
||||||
Attachments: ToAttachments(issue.Attachments),
|
Attachments: ToAttachments(issue.Attachments),
|
||||||
Ref: issue.Ref,
|
Ref: issue.Ref,
|
||||||
|
Labels: ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner),
|
||||||
State: issue.State(),
|
State: issue.State(),
|
||||||
IsLocked: issue.IsLocked,
|
IsLocked: issue.IsLocked,
|
||||||
Comments: issue.NumComments,
|
Comments: issue.NumComments,
|
||||||
@ -48,19 +54,11 @@ func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
|
|||||||
Updated: issue.UpdatedUnix.AsTime(),
|
Updated: issue.UpdatedUnix.AsTime(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.Repo != nil {
|
apiIssue.Repo = &api.RepositoryMeta{
|
||||||
if err := issue.Repo.LoadOwner(ctx); err != nil {
|
ID: issue.Repo.ID,
|
||||||
return &api.Issue{}
|
Name: issue.Repo.Name,
|
||||||
}
|
Owner: issue.Repo.OwnerName,
|
||||||
apiIssue.URL = issue.APIURL()
|
FullName: issue.Repo.FullName(),
|
||||||
apiIssue.HTMLURL = issue.HTMLURL()
|
|
||||||
apiIssue.Labels = ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner)
|
|
||||||
apiIssue.Repo = &api.RepositoryMeta{
|
|
||||||
ID: issue.Repo.ID,
|
|
||||||
Name: issue.Repo.Name,
|
|
||||||
Owner: issue.Repo.OwnerName,
|
|
||||||
FullName: issue.Repo.FullName(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.ClosedUnix != 0 {
|
if issue.ClosedUnix != 0 {
|
||||||
@ -87,13 +85,11 @@ func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
|
|||||||
if err := issue.LoadPullRequest(ctx); err != nil {
|
if err := issue.LoadPullRequest(ctx); err != nil {
|
||||||
return &api.Issue{}
|
return &api.Issue{}
|
||||||
}
|
}
|
||||||
if issue.PullRequest != nil {
|
apiIssue.PullRequest = &api.PullRequestMeta{
|
||||||
apiIssue.PullRequest = &api.PullRequestMeta{
|
HasMerged: issue.PullRequest.HasMerged,
|
||||||
HasMerged: issue.PullRequest.HasMerged,
|
}
|
||||||
}
|
if issue.PullRequest.HasMerged {
|
||||||
if issue.PullRequest.HasMerged {
|
apiIssue.PullRequest.Merged = issue.PullRequest.MergedUnix.AsTimePtr()
|
||||||
apiIssue.PullRequest.Merged = issue.PullRequest.MergedUnix.AsTimePtr()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if issue.DeadlineUnix != 0 {
|
if issue.DeadlineUnix != 0 {
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<label>{{svg "octicon-terminal"}} {{.locale.Tr "packages.generic.download"}}</label>
|
<label>{{svg "octicon-terminal"}} {{.locale.Tr "packages.generic.download"}}</label>
|
||||||
<div class="markup"><pre class="code-block"><code>
|
<div class="markup"><pre class="code-block"><code>
|
||||||
{{- range .PackageDescriptor.Files -}}
|
{{- range .PackageDescriptor.Files -}}
|
||||||
curl <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/generic/{{$.PackageDescriptor.Package.Name}}/{{$.PackageDescriptor.Version.Version}}/{{.File.Name}}"></gitea-origin-url>
|
curl <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/generic/{{$.PackageDescriptor.Package.Name}}/{{$.PackageDescriptor.Version.Version}}/{{.File.Name}}"></gitea-origin-url><br>
|
||||||
{{end -}}
|
{{- end -}}
|
||||||
</code></pre></div>
|
</code></pre></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
@ -20,40 +20,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{range .IssueConfig.ContactLinks}}
|
<div class="ui attached segment">
|
||||||
<div class="ui attached segment">
|
<div class="ui two column grid">
|
||||||
<div class="ui two column grid">
|
<div class="column left aligned">
|
||||||
<div class="column left aligned">
|
<strong>{{.locale.Tr "repo.issues.choose.blank"}}</strong>
|
||||||
<strong>{{.Name | RenderEmojiPlain}}</strong>
|
<br>{{.locale.Tr "repo.issues.choose.blank_about"}}
|
||||||
<br>{{.About | RenderEmojiPlain}}
|
</div>
|
||||||
</div>
|
<div class="column right aligned">
|
||||||
<div class="column right aligned">
|
<a href="{{.RepoLink}}/issues/new?{{if .milestone}}&milestone={{.milestone}}{{end}}{{if $.project}}&project={{$.project}}{{end}}" class="ui green button">{{$.locale.Tr "repo.issues.choose.get_started"}}</a>
|
||||||
<a href="{{.URL}}" class="ui green button">{{svg "octicon-link-external"}} {{$.locale.Tr "repo.issues.choose.open_external_link"}}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
</div>
|
||||||
{{if .IssueConfig.BlankIssuesEnabled}}
|
|
||||||
<div class="ui attached segment">
|
|
||||||
<div class="ui two column grid">
|
|
||||||
<div class="column left aligned">
|
|
||||||
<strong>{{.locale.Tr "repo.issues.choose.blank"}}</strong>
|
|
||||||
<br/>{{.locale.Tr "repo.issues.choose.blank_about"}}
|
|
||||||
</div>
|
|
||||||
<div class="column right aligned">
|
|
||||||
<a href="{{.RepoLink}}/issues/new?{{if .milestone}}&milestone={{.milestone}}{{end}}{{if $.project}}&project={{$.project}}{{end}}" class="ui green button">{{$.locale.Tr "repo.issues.choose.get_started"}}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
{{- if .IssueConfigError}}{{/* normal warning flash makes problems here*/}}
|
|
||||||
<div class="ui warning message">
|
|
||||||
<div class="text left">
|
|
||||||
<div>{{.locale.Tr "repo.issues.choose.invalid_config"}}</div>
|
|
||||||
<diy>{{.IssueConfigError}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
@ -420,7 +420,7 @@
|
|||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
<div class="ui depending">
|
<div class="ui depending">
|
||||||
{{if (and (not .BlockedByDependencies) (not .BlockedByDependenciesNotPermitted) (not .BlockingDependencies) (not .BlockingDependenciesNotPermitted))}}
|
{{if (and (not .BlockedByDependencies) (not .BlockingDependencies))}}
|
||||||
<span class="text"><strong>{{.locale.Tr "repo.issues.dependency.title"}}</strong></span>
|
<span class="text"><strong>{{.locale.Tr "repo.issues.dependency.title"}}</strong></span>
|
||||||
<br>
|
<br>
|
||||||
<p>
|
<p>
|
||||||
@ -432,7 +432,7 @@
|
|||||||
</p>
|
</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if or .BlockingDependencies .BlockingDependenciesNotPermitted}}
|
{{if .BlockingDependencies}}
|
||||||
<span class="text" data-tooltip-content="{{if .Issue.IsPull}}{{.locale.Tr "repo.issues.dependency.pr_close_blocks"}}{{else}}{{.locale.Tr "repo.issues.dependency.issue_close_blocks"}}{{end}}">
|
<span class="text" data-tooltip-content="{{if .Issue.IsPull}}{{.locale.Tr "repo.issues.dependency.pr_close_blocks"}}{{else}}{{.locale.Tr "repo.issues.dependency.issue_close_blocks"}}{{end}}">
|
||||||
<strong>{{.locale.Tr "repo.issues.dependency.blocks_short"}}</strong>
|
<strong>{{.locale.Tr "repo.issues.dependency.blocks_short"}}</strong>
|
||||||
</span>
|
</span>
|
||||||
@ -456,15 +456,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .BlockingDependenciesNotPermitted}}
|
|
||||||
<div class="item gt-df gt-ac gt-sb">
|
|
||||||
<span>{{$.locale.TrN (len .BlockingDependenciesNotPermitted) "repo.issues.dependency.no_permission_1" "repo.issues.dependency.no_permission_n" (len .BlockingDependenciesNotPermitted)}}</span>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if or .BlockedByDependencies .BlockedByDependenciesNotPermitted}}
|
{{if .BlockedByDependencies}}
|
||||||
<span class="text" data-tooltip-content="{{if .Issue.IsPull}}{{.locale.Tr "repo.issues.dependency.pr_closing_blockedby"}}{{else}}{{.locale.Tr "repo.issues.dependency.issue_closing_blockedby"}}{{end}}">
|
<span class="text" data-tooltip-content="{{if .Issue.IsPull}}{{.locale.Tr "repo.issues.dependency.pr_closing_blockedby"}}{{else}}{{.locale.Tr "repo.issues.dependency.issue_closing_blockedby"}}{{end}}">
|
||||||
<strong>{{.locale.Tr "repo.issues.dependency.blocked_by_short"}}</strong>
|
<strong>{{.locale.Tr "repo.issues.dependency.blocked_by_short"}}</strong>
|
||||||
</span>
|
</span>
|
||||||
@ -488,34 +483,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if $.CanCreateIssueDependencies}}
|
|
||||||
{{range .BlockedByDependenciesNotPermitted}}
|
|
||||||
<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
|
|
||||||
<div class="item-left gt-df gt-jc gt-fc gt-f1">
|
|
||||||
<div>
|
|
||||||
<span data-tooltip-content="{{$.locale.Tr "repo.issues.dependency.no_permission.can_remove"}}">{{svg "octicon-lock" 16}}</span>
|
|
||||||
<span class="title" data-tooltip-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
|
|
||||||
#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="text small">
|
|
||||||
{{.Repository.OwnerName}}/{{.Repository.Name}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="item-right gt-df gt-ac">
|
|
||||||
{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
|
|
||||||
<a class="delete-dependency-button ci muted" data-id="{{.Issue.ID}}" data-type="blocking" data-tooltip-content="{{$.locale.Tr "repo.issues.dependency.remove_info"}}">
|
|
||||||
{{svg "octicon-trash" 16}}
|
|
||||||
</a>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
{{else if .BlockedByDependenciesNotPermitted}}
|
|
||||||
<div class="item gt-df gt-ac gt-sb">
|
|
||||||
<span>{{$.locale.TrN (len .BlockedByDependenciesNotPermitted) "repo.issues.dependency.no_permission_1" "repo.issues.dependency.no_permission_n" (len .BlockedByDependenciesNotPermitted)}}</span>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
@ -39,9 +39,6 @@
|
|||||||
</h3>
|
</h3>
|
||||||
<div class="download gt-df gt-ac">
|
<div class="download gt-df gt-ac">
|
||||||
{{if $.Permission.CanRead $.UnitTypeCode}}
|
{{if $.Permission.CanRead $.UnitTypeCode}}
|
||||||
{{if .CreatedUnix}}
|
|
||||||
<span class="gt-mr-3">{{svg "octicon-clock" 16 "gt-mr-2"}}{{TimeSinceUnix .CreatedUnix $.locale}}</span>
|
|
||||||
{{end}}
|
|
||||||
<a class="gt-mr-3 gt-mono muted" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha .Sha1}}</a>
|
<a class="gt-mr-3 gt-mono muted" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha .Sha1}}</a>
|
||||||
{{if not $.DisableDownloadSourceArchives}}
|
{{if not $.DisableDownloadSourceArchives}}
|
||||||
<a class="archive-link gt-mr-3 muted" href="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.zip" rel="nofollow">{{svg "octicon-file-zip" 16 "gt-mr-2"}}ZIP</a>
|
<a class="archive-link gt-mr-3 muted" href="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.zip" rel="nofollow">{{svg "octicon-file-zip" 16 "gt-mr-2"}}ZIP</a>
|
||||||
|
@ -5013,72 +5013,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/repos/{owner}/{repo}/issue_config": {
|
|
||||||
"get": {
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"repository"
|
|
||||||
],
|
|
||||||
"summary": "Returns the issue config for a repo",
|
|
||||||
"operationId": "repoGetIssueConfig",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "owner of the repo",
|
|
||||||
"name": "owner",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "name of the repo",
|
|
||||||
"name": "repo",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"$ref": "#/responses/RepoIssueConfig"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/repos/{owner}/{repo}/issue_config/validate": {
|
|
||||||
"get": {
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"repository"
|
|
||||||
],
|
|
||||||
"summary": "Returns the validation information for a issue config",
|
|
||||||
"operationId": "repoValidateIssueConfig",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "owner of the repo",
|
|
||||||
"name": "owner",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "name of the repo",
|
|
||||||
"name": "repo",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"$ref": "#/responses/RepoIssueConfigValidation"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/repos/{owner}/{repo}/issue_templates": {
|
"/repos/{owner}/{repo}/issue_templates": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
@ -6322,151 +6256,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/repos/{owner}/{repo}/issues/{index}/blocks": {
|
|
||||||
"get": {
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"issue"
|
|
||||||
],
|
|
||||||
"summary": "List issues that are blocked by this issue",
|
|
||||||
"operationId": "issueListBlocks",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "owner of the repo",
|
|
||||||
"name": "owner",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "name of the repo",
|
|
||||||
"name": "repo",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "index of the issue",
|
|
||||||
"name": "index",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"description": "page number of results to return (1-based)",
|
|
||||||
"name": "page",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"description": "page size of results",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"$ref": "#/responses/IssueList"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"post": {
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"issue"
|
|
||||||
],
|
|
||||||
"summary": "Block the issue given in the body by the issue in path",
|
|
||||||
"operationId": "issueCreateIssueBlocking",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "owner of the repo",
|
|
||||||
"name": "owner",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "name of the repo",
|
|
||||||
"name": "repo",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "index of the issue",
|
|
||||||
"name": "index",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"in": "body",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/IssueMeta"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"201": {
|
|
||||||
"$ref": "#/responses/Issue"
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "the issue does not exist"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"delete": {
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"issue"
|
|
||||||
],
|
|
||||||
"summary": "Unblock the issue given in the body by the issue in path",
|
|
||||||
"operationId": "issueRemoveIssueBlocking",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "owner of the repo",
|
|
||||||
"name": "owner",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "name of the repo",
|
|
||||||
"name": "repo",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "index of the issue",
|
|
||||||
"name": "index",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"in": "body",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/IssueMeta"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"$ref": "#/responses/Issue"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/repos/{owner}/{repo}/issues/{index}/comments": {
|
"/repos/{owner}/{repo}/issues/{index}/comments": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
@ -6749,151 +6538,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/repos/{owner}/{repo}/issues/{index}/dependencies": {
|
|
||||||
"get": {
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"issue"
|
|
||||||
],
|
|
||||||
"summary": "List an issue's dependencies, i.e all issues that block this issue.",
|
|
||||||
"operationId": "issueListIssueDependencies",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "owner of the repo",
|
|
||||||
"name": "owner",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "name of the repo",
|
|
||||||
"name": "repo",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "index of the issue",
|
|
||||||
"name": "index",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"description": "page number of results to return (1-based)",
|
|
||||||
"name": "page",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"description": "page size of results",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"$ref": "#/responses/IssueList"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"post": {
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"issue"
|
|
||||||
],
|
|
||||||
"summary": "Make the issue in the url depend on the issue in the form.",
|
|
||||||
"operationId": "issueCreateIssueDependencies",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "owner of the repo",
|
|
||||||
"name": "owner",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "name of the repo",
|
|
||||||
"name": "repo",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "index of the issue",
|
|
||||||
"name": "index",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"in": "body",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/IssueMeta"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"201": {
|
|
||||||
"$ref": "#/responses/Issue"
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "the issue does not exist"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"delete": {
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"issue"
|
|
||||||
],
|
|
||||||
"summary": "Remove an issue dependency",
|
|
||||||
"operationId": "issueRemoveIssueDependencies",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "owner of the repo",
|
|
||||||
"name": "owner",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "name of the repo",
|
|
||||||
"name": "repo",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "index of the issue",
|
|
||||||
"name": "index",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"in": "body",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/IssueMeta"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"$ref": "#/responses/Issue"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/repos/{owner}/{repo}/issues/{index}/labels": {
|
"/repos/{owner}/{repo}/issues/{index}/labels": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
@ -18231,55 +17875,6 @@
|
|||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
},
|
},
|
||||||
"IssueConfig": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"blank_issues_enabled": {
|
|
||||||
"type": "boolean",
|
|
||||||
"x-go-name": "BlankIssuesEnabled"
|
|
||||||
},
|
|
||||||
"contact_links": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/IssueConfigContactLink"
|
|
||||||
},
|
|
||||||
"x-go-name": "ContactLinks"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
|
||||||
},
|
|
||||||
"IssueConfigContactLink": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"about": {
|
|
||||||
"type": "string",
|
|
||||||
"x-go-name": "About"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"x-go-name": "Name"
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"type": "string",
|
|
||||||
"x-go-name": "URL"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
|
||||||
},
|
|
||||||
"IssueConfigValidation": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"message": {
|
|
||||||
"type": "string",
|
|
||||||
"x-go-name": "Message"
|
|
||||||
},
|
|
||||||
"valid": {
|
|
||||||
"type": "boolean",
|
|
||||||
"x-go-name": "Valid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
|
||||||
},
|
|
||||||
"IssueDeadline": {
|
"IssueDeadline": {
|
||||||
"description": "IssueDeadline represents an issue deadline",
|
"description": "IssueDeadline represents an issue deadline",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -18337,26 +17932,6 @@
|
|||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
},
|
},
|
||||||
"IssueMeta": {
|
|
||||||
"description": "IssueMeta basic issue information",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"index": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64",
|
|
||||||
"x-go-name": "Index"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string",
|
|
||||||
"x-go-name": "Owner"
|
|
||||||
},
|
|
||||||
"repo": {
|
|
||||||
"type": "string",
|
|
||||||
"x-go-name": "Name"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
|
||||||
},
|
|
||||||
"IssueTemplate": {
|
"IssueTemplate": {
|
||||||
"description": "IssueTemplate represents an issue template for a repository",
|
"description": "IssueTemplate represents an issue template for a repository",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -21559,18 +21134,6 @@
|
|||||||
"$ref": "#/definitions/RepoCollaboratorPermission"
|
"$ref": "#/definitions/RepoCollaboratorPermission"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"RepoIssueConfig": {
|
|
||||||
"description": "RepoIssueConfig",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/IssueConfig"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RepoIssueConfigValidation": {
|
|
||||||
"description": "RepoIssueConfigValidation",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/IssueConfigValidation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Repository": {
|
"Repository": {
|
||||||
"description": "Repository",
|
"description": "Repository",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package integration
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
|
||||||
"code.gitea.io/gitea/tests"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAPIReposGetDefaultIssueConfig(t *testing.T) {
|
|
||||||
defer tests.PrepareTestEnv(t)()
|
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
||||||
|
|
||||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issue_config", owner.Name, repo.Name)
|
|
||||||
req := NewRequest(t, "GET", urlStr)
|
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
|
||||||
|
|
||||||
var issueConfig api.IssueConfig
|
|
||||||
DecodeJSON(t, resp, &issueConfig)
|
|
||||||
|
|
||||||
assert.True(t, issueConfig.BlankIssuesEnabled)
|
|
||||||
assert.Equal(t, issueConfig.ContactLinks, make([]api.IssueConfigContactLink, 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAPIReposValidateDefaultIssueConfig(t *testing.T) {
|
|
||||||
defer tests.PrepareTestEnv(t)()
|
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
||||||
|
|
||||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issue_config/validate", owner.Name, repo.Name)
|
|
||||||
req := NewRequest(t, "GET", urlStr)
|
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
|
||||||
|
|
||||||
var issueConfigValidation api.IssueConfigValidation
|
|
||||||
DecodeJSON(t, resp, &issueConfigValidation)
|
|
||||||
|
|
||||||
assert.True(t, issueConfigValidation.Valid)
|
|
||||||
assert.Equal(t, issueConfigValidation.Message, "")
|
|
||||||
}
|
|
@ -125,7 +125,6 @@ MINIO_SECRET_ACCESS_KEY = 12345678
|
|||||||
MINIO_BUCKET = gitea
|
MINIO_BUCKET = gitea
|
||||||
MINIO_LOCATION = us-east-1
|
MINIO_LOCATION = us-east-1
|
||||||
MINIO_USE_SSL = false
|
MINIO_USE_SSL = false
|
||||||
MINIO_CHECKSUM_ALGORITHM = md5
|
|
||||||
|
|
||||||
[packages]
|
[packages]
|
||||||
ENABLED = true
|
ENABLED = true
|
||||||
|
@ -2399,107 +2399,9 @@ a.ui.label:hover {
|
|||||||
|
|
||||||
.ui.basic.labels .primary.label,
|
.ui.basic.labels .primary.label,
|
||||||
.ui.ui.ui.basic.primary.label {
|
.ui.ui.ui.basic.primary.label {
|
||||||
background: transparent;
|
background: transparent !important;
|
||||||
border-color: var(--color-primary);
|
border-color: var(--color-primary) !important;
|
||||||
color: var(--color-primary);
|
color: var(--color-primary) !important;
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .secondary.label,
|
|
||||||
.ui.ui.ui.basic.secondary.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-secondary);
|
|
||||||
color: var(--color-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .orange.label,
|
|
||||||
.ui.ui.ui.basic.orange.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-orange);
|
|
||||||
color: var(--color-orange);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .green.label,
|
|
||||||
.ui.ui.ui.basic.green.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-green);
|
|
||||||
color: var(--color-green);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .olive.label,
|
|
||||||
.ui.ui.ui.basic.olive.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-olive);
|
|
||||||
color: var(--color-olive);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .teal.label,
|
|
||||||
.ui.ui.ui.basic.teal.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-teal);
|
|
||||||
color: var(--color-teal);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .blue.label,
|
|
||||||
.ui.ui.ui.basic.blue.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-blue);
|
|
||||||
color: var(--color-blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .violet.label,
|
|
||||||
.ui.ui.ui.basic.violet.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-violet);
|
|
||||||
color: var(--color-violet);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .purple.label,
|
|
||||||
.ui.ui.ui.basic.purple.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-purple);
|
|
||||||
color: var(--color-purple);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .pink.label,
|
|
||||||
.ui.ui.ui.basic.pink.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-pink);
|
|
||||||
color: var(--color-pink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .red.label,
|
|
||||||
.ui.ui.ui.basic.red.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-red);
|
|
||||||
color: var(--color-red);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .brown.label,
|
|
||||||
.ui.ui.ui.basic.brown.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-brown);
|
|
||||||
color: var(--color-brown);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .yellow.label,
|
|
||||||
.ui.ui.ui.basic.yellow.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-yellow);
|
|
||||||
color: var(--color-yellow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .grey.label,
|
|
||||||
.ui.ui.ui.basic.grey.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-grey);
|
|
||||||
color: var(--color-grey);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.basic.labels .black.label,
|
|
||||||
.ui.ui.ui.basic.black.label {
|
|
||||||
background: transparent;
|
|
||||||
border-color: var(--color-black);
|
|
||||||
color: var(--color-black);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.basic.labels .label,
|
.ui.basic.labels .label,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user