mirror of
https://github.com/go-gitea/gitea.git
synced 2024-09-01 14:56:30 +00:00
Merge branch 'main' of https://github.com/go-gitea/gitea into pacman-packages
This commit is contained in:
commit
37805afb3f
@ -29,6 +29,8 @@ run:
|
|||||||
|
|
||||||
output:
|
output:
|
||||||
sort-results: true
|
sort-results: true
|
||||||
|
sort-order: [file]
|
||||||
|
show-stats: true
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
stylecheck:
|
stylecheck:
|
||||||
@ -40,11 +42,7 @@ linters-settings:
|
|||||||
- ifElseChain
|
- ifElseChain
|
||||||
- singleCaseSwitch # Every time this occurred in the code, there was no other way.
|
- singleCaseSwitch # Every time this occurred in the code, there was no other way.
|
||||||
revive:
|
revive:
|
||||||
ignore-generated-header: false
|
severity: error
|
||||||
severity: warning
|
|
||||||
confidence: 0.8
|
|
||||||
errorCode: 1
|
|
||||||
warningCode: 1
|
|
||||||
rules:
|
rules:
|
||||||
- name: atomic
|
- name: atomic
|
||||||
- name: bare-return
|
- name: bare-return
|
||||||
|
@ -91,6 +91,11 @@ var CmdMigrateStorage = &cli.Command{
|
|||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Minio checksum algorithm (default/md5)",
|
Usage: "Minio checksum algorithm (default/md5)",
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-bucket-lookup-type",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio bucket lookup type",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +225,7 @@ func runMigrateStorage(ctx *cli.Context) error {
|
|||||||
UseSSL: ctx.Bool("minio-use-ssl"),
|
UseSSL: ctx.Bool("minio-use-ssl"),
|
||||||
InsecureSkipVerify: ctx.Bool("minio-insecure-skip-verify"),
|
InsecureSkipVerify: ctx.Bool("minio-insecure-skip-verify"),
|
||||||
ChecksumAlgorithm: ctx.String("minio-checksum-algorithm"),
|
ChecksumAlgorithm: ctx.String("minio-checksum-algorithm"),
|
||||||
|
BucketLookUpType: ctx.String("minio-bucket-lookup-type"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
|
@ -1895,6 +1895,9 @@ LEVEL = Info
|
|||||||
;;
|
;;
|
||||||
;; Minio checksum algorithm: default (for MinIO or AWS S3) or md5 (for Cloudflare or Backblaze)
|
;; Minio checksum algorithm: default (for MinIO or AWS S3) or md5 (for Cloudflare or Backblaze)
|
||||||
;MINIO_CHECKSUM_ALGORITHM = default
|
;MINIO_CHECKSUM_ALGORITHM = default
|
||||||
|
;;
|
||||||
|
;; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
|
||||||
|
;MINIO_BUCKET_LOOKUP_TYPE = auto
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@ -2576,6 +2579,9 @@ LEVEL = Info
|
|||||||
;;
|
;;
|
||||||
;; 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 bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
|
||||||
|
;MINIO_BUCKET_LOOKUP_TYPE = auto
|
||||||
|
|
||||||
;[proxy]
|
;[proxy]
|
||||||
;; Enable the proxy, all requests to external via HTTP will be affected
|
;; Enable the proxy, all requests to external via HTTP will be affected
|
||||||
|
@ -851,6 +851,7 @@ Default templates for project boards:
|
|||||||
- `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)
|
- `MINIO_CHECKSUM_ALGORITHM`: **default**: Minio checksum algorithm: `default` (for MinIO or AWS S3) or `md5` (for Cloudflare or Backblaze)
|
||||||
|
- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
|
||||||
|
|
||||||
## Log (`log`)
|
## Log (`log`)
|
||||||
|
|
||||||
@ -1272,6 +1273,7 @@ is `data/lfs` and the default of `MINIO_BASE_PATH` is `lfs/`.
|
|||||||
- `MINIO_BASE_PATH`: **lfs/**: Minio base path on the bucket only available when `STORAGE_TYPE` is `minio`
|
- `MINIO_BASE_PATH`: **lfs/**: 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_BUCKET_LOOKUP_TYPE`: **auto**: Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
|
||||||
|
|
||||||
## Storage (`storage`)
|
## Storage (`storage`)
|
||||||
|
|
||||||
@ -1286,6 +1288,7 @@ Default storage configuration for attachments, lfs, avatars, repo-avatars, repo-
|
|||||||
- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when `STORAGE_TYPE` is `minio`
|
- `MINIO_LOCATION`: **us-east-1**: Minio location to create 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_BUCKET_LOOKUP_TYPE`: **auto**: Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
|
||||||
|
|
||||||
The recommended storage configuration for minio like below:
|
The recommended storage configuration for minio like below:
|
||||||
|
|
||||||
@ -1307,6 +1310,8 @@ MINIO_USE_SSL = false
|
|||||||
; 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
|
||||||
SERVE_DIRECT = true
|
SERVE_DIRECT = true
|
||||||
|
; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
|
||||||
|
MINIO_BUCKET_LOOKUP_TYPE = auto
|
||||||
```
|
```
|
||||||
|
|
||||||
Defaultly every storage has their default base path like below
|
Defaultly every storage has their default base path like below
|
||||||
@ -1353,6 +1358,8 @@ MINIO_LOCATION = us-east-1
|
|||||||
MINIO_USE_SSL = false
|
MINIO_USE_SSL = false
|
||||||
; 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 bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
|
||||||
|
MINIO_BUCKET_LOOKUP_TYPE = auto
|
||||||
```
|
```
|
||||||
|
|
||||||
## Repository Archive Storage (`storage.repo-archive`)
|
## Repository Archive Storage (`storage.repo-archive`)
|
||||||
@ -1372,6 +1379,7 @@ is `data/repo-archive` and the default of `MINIO_BASE_PATH` is `repo-archive/`.
|
|||||||
- `MINIO_BASE_PATH`: **repo-archive/**: Minio base path on the bucket only available when `STORAGE_TYPE` is `minio`
|
- `MINIO_BASE_PATH`: **repo-archive/**: 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_BUCKET_LOOKUP_TYPE`: **auto**: Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
|
||||||
|
|
||||||
## Repository Archives (`repo-archive`)
|
## Repository Archives (`repo-archive`)
|
||||||
|
|
||||||
|
@ -796,6 +796,7 @@ Gitea 创建以下非唯一队列:
|
|||||||
- `MINIO_USE_SSL`: **false**: Minio 启用 SSL,仅当 STORAGE_TYPE 为 `minio` 时可用。
|
- `MINIO_USE_SSL`: **false**: Minio 启用 SSL,仅当 STORAGE_TYPE 为 `minio` 时可用。
|
||||||
- `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio 跳过 SSL 验证,仅当 STORAGE_TYPE 为 `minio` 时可用。
|
- `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio 跳过 SSL 验证,仅当 STORAGE_TYPE 为 `minio` 时可用。
|
||||||
- `MINIO_CHECKSUM_ALGORITHM`: **default**: Minio 校验算法:`default`(适用于 MinIO 或 AWS S3)或 `md5`(适用于 Cloudflare 或 Backblaze)
|
- `MINIO_CHECKSUM_ALGORITHM`: **default**: Minio 校验算法:`default`(适用于 MinIO 或 AWS S3)或 `md5`(适用于 Cloudflare 或 Backblaze)
|
||||||
|
- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio的bucket查找方式默认为`auto`模式,可将其设置为`dns`(虚拟托管样式)或`path`(路径样式),仅当`STORAGE_TYPE`为`minio`时可用。
|
||||||
|
|
||||||
## 日志 (`log`)
|
## 日志 (`log`)
|
||||||
|
|
||||||
@ -1201,6 +1202,7 @@ ALLOW_DATA_URI_IMAGES = true
|
|||||||
- `MINIO_BASE_PATH`:**lfs/**:桶上的 Minio 基本路径,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
- `MINIO_BASE_PATH`:**lfs/**:桶上的 Minio 基本路径,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
||||||
- `MINIO_USE_SSL`:**false**:Minio 启用 ssl,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
- `MINIO_USE_SSL`:**false**:Minio 启用 ssl,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
||||||
- `MINIO_INSECURE_SKIP_VERIFY`:**false**:Minio 跳过 SSL 验证,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
- `MINIO_INSECURE_SKIP_VERIFY`:**false**:Minio 跳过 SSL 验证,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
||||||
|
- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio的bucket查找方式默认为`auto`模式,可将其设置为`dns`(虚拟托管样式)或`path`(路径样式),仅当`STORAGE_TYPE`为`minio`时可用。
|
||||||
|
|
||||||
## 存储 (`storage`)
|
## 存储 (`storage`)
|
||||||
|
|
||||||
@ -1215,6 +1217,7 @@ ALLOW_DATA_URI_IMAGES = true
|
|||||||
- `MINIO_LOCATION`:**us-east-1**:创建桶的 Minio 位置,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
- `MINIO_LOCATION`:**us-east-1**:创建桶的 Minio 位置,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
||||||
- `MINIO_USE_SSL`:**false**:Minio 启用 ssl,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
- `MINIO_USE_SSL`:**false**:Minio 启用 ssl,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
||||||
- `MINIO_INSECURE_SKIP_VERIFY`:**false**:Minio 跳过 SSL 验证,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
- `MINIO_INSECURE_SKIP_VERIFY`:**false**:Minio 跳过 SSL 验证,仅在 `STORAGE_TYPE` 为 `minio` 时可用。
|
||||||
|
- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio的bucket查找方式默认为`auto`模式,可将其设置为`dns`(虚拟托管样式)或`path`(路径样式),仅当`STORAGE_TYPE`为`minio`时可用。
|
||||||
|
|
||||||
建议的 minio 存储配置如下:
|
建议的 minio 存储配置如下:
|
||||||
|
|
||||||
@ -1236,6 +1239,8 @@ MINIO_USE_SSL = false
|
|||||||
; 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
|
||||||
SERVE_DIRECT = true
|
SERVE_DIRECT = true
|
||||||
|
; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
|
||||||
|
MINIO_BUCKET_LOOKUP_TYPE = auto
|
||||||
```
|
```
|
||||||
|
|
||||||
默认情况下,每个存储都有其默认的基本路径,如下所示:
|
默认情况下,每个存储都有其默认的基本路径,如下所示:
|
||||||
@ -1282,6 +1287,8 @@ MINIO_LOCATION = us-east-1
|
|||||||
MINIO_USE_SSL = false
|
MINIO_USE_SSL = false
|
||||||
; 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 bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
|
||||||
|
MINIO_BUCKET_LOOKUP_TYPE = auto
|
||||||
```
|
```
|
||||||
|
|
||||||
### 存储库归档存储 (`storage.repo-archive`)
|
### 存储库归档存储 (`storage.repo-archive`)
|
||||||
@ -1299,6 +1306,7 @@ MINIO_INSECURE_SKIP_VERIFY = false
|
|||||||
- `MINIO_BASE_PATH`: **repo-archive/**:存储桶上的Minio基本路径,仅在`STORAGE_TYPE`为`minio`时可用。
|
- `MINIO_BASE_PATH`: **repo-archive/**:存储桶上的Minio基本路径,仅在`STORAGE_TYPE`为`minio`时可用。
|
||||||
- `MINIO_USE_SSL`: **false**:启用Minio的SSL,仅在`STORAGE_TYPE`为`minio`时可用。
|
- `MINIO_USE_SSL`: **false**:启用Minio的SSL,仅在`STORAGE_TYPE`为`minio`时可用。
|
||||||
- `MINIO_INSECURE_SKIP_VERIFY`: **false**:跳过Minio的SSL验证,仅在`STORAGE_TYPE`为`minio`时可用。
|
- `MINIO_INSECURE_SKIP_VERIFY`: **false**:跳过Minio的SSL验证,仅在`STORAGE_TYPE`为`minio`时可用。
|
||||||
|
- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio的bucket查找方式默认为`auto`模式,可将其设置为`dns`(虚拟托管样式)或`path`(路径样式),仅当`STORAGE_TYPE`为`minio`时可用。
|
||||||
|
|
||||||
### 存储库归档 (`repo-archive`)
|
### 存储库归档 (`repo-archive`)
|
||||||
|
|
||||||
|
@ -17,15 +17,35 @@ menu:
|
|||||||
|
|
||||||
# Reverse Proxies
|
# Reverse Proxies
|
||||||
|
|
||||||
|
## General configuration
|
||||||
|
|
||||||
|
1. Set `[server] ROOT_URL = https://git.example.com/` in your `app.ini` file.
|
||||||
|
2. Make the reverse-proxy pass `https://git.example.com/foo` to `http://gitea:3000/foo`.
|
||||||
|
3. Make sure the reverse-proxy does not decode the URI. The request `https://git.example.com/a%2Fb` should be passed as `http://gitea:3000/a%2Fb`.
|
||||||
|
4. Make sure `Host` and `X-Fowarded-Proto` headers are correctly passed to Gitea to make Gitea see the real URL being visited.
|
||||||
|
|
||||||
|
### Use a sub-path
|
||||||
|
|
||||||
|
Usually it's **not recommended** to put Gitea in a sub-path, it's not widely used and may have some issues in rare cases.
|
||||||
|
|
||||||
|
To make Gitea work with a sub-path (eg: `https://common.example.com/gitea/`),
|
||||||
|
there are some extra requirements besides the general configuration above:
|
||||||
|
|
||||||
|
1. Use `[server] ROOT_URL = https://common.example.com/gitea/` in your `app.ini` file.
|
||||||
|
2. Make the reverse-proxy pass `https://common.example.com/gitea/foo` to `http://gitea:3000/foo`.
|
||||||
|
3. The container registry requires a fixed sub-path `/v2` at the root level which must be configured:
|
||||||
|
- Make the reverse-proxy pass `https://common.example.com/v2` to `http://gitea:3000/v2`.
|
||||||
|
- Make sure the URI and headers are also correctly passed (see the general configuration above).
|
||||||
|
|
||||||
## Nginx
|
## Nginx
|
||||||
|
|
||||||
If you want Nginx to serve your Gitea instance, add the following `server` section to the `http` section of `nginx.conf`:
|
If you want Nginx to serve your Gitea instance, add the following `server` section to the `http` section of `nginx.conf`.
|
||||||
|
|
||||||
```
|
Make sure `client_max_body_size` is large enough, otherwise there would be "413 Request Entity Too Large" error when uploading large files.
|
||||||
|
|
||||||
|
```nginx
|
||||||
server {
|
server {
|
||||||
listen 80;
|
...
|
||||||
server_name git.example.com;
|
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
client_max_body_size 512M;
|
client_max_body_size 512M;
|
||||||
proxy_pass http://localhost:3000;
|
proxy_pass http://localhost:3000;
|
||||||
@ -39,37 +59,35 @@ server {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Resolving Error: 413 Request Entity Too Large
|
|
||||||
|
|
||||||
This error indicates nginx is configured to restrict the file upload size,
|
|
||||||
it affects attachment uploading, form posting, package uploading and LFS pushing, etc.
|
|
||||||
You can fine tune the `client_max_body_size` option according to [nginx document](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size).
|
|
||||||
|
|
||||||
## Nginx with a sub-path
|
## Nginx with a sub-path
|
||||||
|
|
||||||
In case you already have a site, and you want Gitea to share the domain name, you can setup Nginx to serve Gitea under a sub-path by adding the following `server` section inside the `http` section of `nginx.conf`:
|
In case you already have a site, and you want Gitea to share the domain name,
|
||||||
|
you can setup Nginx to serve Gitea under a sub-path by adding the following `server` section
|
||||||
|
into the `http` section of `nginx.conf`:
|
||||||
|
|
||||||
```
|
```nginx
|
||||||
server {
|
server {
|
||||||
listen 80;
|
...
|
||||||
server_name git.example.com;
|
location ~ ^/(gitea|v2)($|/) {
|
||||||
|
|
||||||
# Note: Trailing slash
|
|
||||||
location /gitea/ {
|
|
||||||
client_max_body_size 512M;
|
client_max_body_size 512M;
|
||||||
|
|
||||||
# make nginx use unescaped URI, keep "%2F" as is
|
# make nginx use unescaped URI, keep "%2F" as-is, remove the "/gitea" sub-path prefix, pass "/v2" as-is.
|
||||||
rewrite ^ $request_uri;
|
rewrite ^ $request_uri;
|
||||||
rewrite ^/gitea(/.*) $1 break;
|
rewrite ^(/gitea)?(/.*) $2 break;
|
||||||
proxy_pass http://127.0.0.1:3000$uri;
|
proxy_pass http://127.0.0.1:3000$uri;
|
||||||
|
|
||||||
# other common HTTP headers, see the "Nginx" config section above
|
# other common HTTP headers, see the "Nginx" config section above
|
||||||
proxy_set_header ...
|
proxy_set_header Connection $http_connection;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Then you **MUST** set something like `[server] ROOT_URL = http://git.example.com/git/` correctly in your configuration.
|
Then you **MUST** set something like `[server] ROOT_URL = http://git.example.com/gitea/` correctly in your configuration.
|
||||||
|
|
||||||
## Nginx and serve static resources directly
|
## Nginx and serve static resources directly
|
||||||
|
|
||||||
@ -93,7 +111,7 @@ or use a cdn for the static files.
|
|||||||
|
|
||||||
Set `[server] STATIC_URL_PREFIX = /_/static` in your configuration.
|
Set `[server] STATIC_URL_PREFIX = /_/static` in your configuration.
|
||||||
|
|
||||||
```apacheconf
|
```nginx
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name git.example.com;
|
server_name git.example.com;
|
||||||
@ -112,7 +130,7 @@ server {
|
|||||||
|
|
||||||
Set `[server] STATIC_URL_PREFIX = http://cdn.example.com/gitea` in your configuration.
|
Set `[server] STATIC_URL_PREFIX = http://cdn.example.com/gitea` in your configuration.
|
||||||
|
|
||||||
```apacheconf
|
```nginx
|
||||||
# application server running Gitea
|
# application server running Gitea
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
@ -124,7 +142,7 @@ server {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```apacheconf
|
```nginx
|
||||||
# static content delivery server
|
# static content delivery server
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
@ -151,6 +169,8 @@ If you want Apache HTTPD to serve your Gitea instance, you can add the following
|
|||||||
ProxyRequests off
|
ProxyRequests off
|
||||||
AllowEncodedSlashes NoDecode
|
AllowEncodedSlashes NoDecode
|
||||||
ProxyPass / http://localhost:3000/ nocanon
|
ProxyPass / http://localhost:3000/ nocanon
|
||||||
|
ProxyPreserveHost On
|
||||||
|
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -172,6 +192,8 @@ In case you already have a site, and you want Gitea to share the domain name, yo
|
|||||||
AllowEncodedSlashes NoDecode
|
AllowEncodedSlashes NoDecode
|
||||||
# Note: no trailing slash after either /git or port
|
# Note: no trailing slash after either /git or port
|
||||||
ProxyPass /git http://localhost:3000 nocanon
|
ProxyPass /git http://localhost:3000 nocanon
|
||||||
|
ProxyPreserveHost On
|
||||||
|
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -183,7 +205,7 @@ Note: The following Apache HTTPD mods must be enabled: `proxy`, `proxy_http`.
|
|||||||
|
|
||||||
If you want Caddy to serve your Gitea instance, you can add the following server block to your Caddyfile:
|
If you want Caddy to serve your Gitea instance, you can add the following server block to your Caddyfile:
|
||||||
|
|
||||||
```apacheconf
|
```
|
||||||
git.example.com {
|
git.example.com {
|
||||||
reverse_proxy localhost:3000
|
reverse_proxy localhost:3000
|
||||||
}
|
}
|
||||||
@ -193,7 +215,7 @@ git.example.com {
|
|||||||
|
|
||||||
In case you already have a site, and you want Gitea to share the domain name, you can setup Caddy to serve Gitea under a sub-path by adding the following to your server block in your Caddyfile:
|
In case you already have a site, and you want Gitea to share the domain name, you can setup Caddy to serve Gitea under a sub-path by adding the following to your server block in your Caddyfile:
|
||||||
|
|
||||||
```apacheconf
|
```
|
||||||
git.example.com {
|
git.example.com {
|
||||||
route /git/* {
|
route /git/* {
|
||||||
uri strip_prefix /git
|
uri strip_prefix /git
|
||||||
@ -371,19 +393,3 @@ gitea:
|
|||||||
This config assumes that you are handling HTTPS on the traefik side and using HTTP between Gitea and traefik.
|
This config assumes that you are handling HTTPS on the traefik side and using HTTP between Gitea and traefik.
|
||||||
|
|
||||||
Then you **MUST** set something like `[server] ROOT_URL = http://example.com/gitea/` correctly in your configuration.
|
Then you **MUST** set something like `[server] ROOT_URL = http://example.com/gitea/` correctly in your configuration.
|
||||||
|
|
||||||
## General sub-path configuration
|
|
||||||
|
|
||||||
Usually it's not recommended to put Gitea in a sub-path, it's not widely used and may have some issues in rare cases.
|
|
||||||
|
|
||||||
If you really need to do so, to make Gitea works with sub-path (eg: `http://example.com/gitea/`), here are the requirements:
|
|
||||||
|
|
||||||
1. Set `[server] ROOT_URL = http://example.com/gitea/` in your `app.ini` file.
|
|
||||||
2. Make the reverse-proxy pass `http://example.com/gitea/foo` to `http://gitea-server:3000/foo`.
|
|
||||||
3. Make sure the reverse-proxy not decode the URI, the request `http://example.com/gitea/a%2Fb` should be passed as `http://gitea-server:3000/a%2Fb`.
|
|
||||||
|
|
||||||
## Docker / Container Registry
|
|
||||||
|
|
||||||
The container registry uses a fixed sub-path `/v2` which can't be changed.
|
|
||||||
Even if you deploy Gitea with a different sub-path, `/v2` will be used by the `docker` client.
|
|
||||||
Therefore you may need to add an additional route to your reverse proxy configuration.
|
|
||||||
|
@ -30,7 +30,7 @@ The following examples use the `npm` tool with the scope `@test`.
|
|||||||
To register the package registry you need to configure a new package source.
|
To register the package registry you need to configure a new package source.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
npm config set {scope}:registry https://gitea.example.com/api/packages/{owner}/npm/
|
npm config set {scope}:registry=https://gitea.example.com/api/packages/{owner}/npm/
|
||||||
npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{token}"
|
npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{token}"
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{t
|
|||||||
For example:
|
For example:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
npm config set @test:registry https://gitea.example.com/api/packages/testuser/npm/
|
npm config set @test:registry=https://gitea.example.com/api/packages/testuser/npm/
|
||||||
npm config set -- '//gitea.example.com/api/packages/testuser/npm/:_authToken' "personal_access_token"
|
npm config set -- '//gitea.example.com/api/packages/testuser/npm/:_authToken' "personal_access_token"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ menu:
|
|||||||
要注册软件包注册表,您需要配置一个新的软件包源。
|
要注册软件包注册表,您需要配置一个新的软件包源。
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
npm config set {scope}:registry https://gitea.example.com/api/packages/{owner}/npm/
|
npm config set {scope}:registry=https://gitea.example.com/api/packages/{owner}/npm/
|
||||||
npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{token}"
|
npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{token}"
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{t
|
|||||||
例如:
|
例如:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
npm config set @test:registry https://gitea.example.com/api/packages/testuser/npm/
|
npm config set @test:registry=https://gitea.example.com/api/packages/testuser/npm/
|
||||||
npm config set -- '//gitea.example.com/api/packages/testuser/npm/:_authToken' "personal_access_token"
|
npm config set -- '//gitea.example.com/api/packages/testuser/npm/:_authToken' "personal_access_token"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -524,7 +524,12 @@ func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.RequestedRepo != nil {
|
if opts.RequestedRepo != nil {
|
||||||
cond = cond.And(builder.Eq{"repo_id": opts.RequestedRepo.ID})
|
// repo's actions could have duplicate items, see the comment of NotifyWatchers
|
||||||
|
// so here we only filter the "original items", aka: user_id == act_user_id
|
||||||
|
cond = cond.And(
|
||||||
|
builder.Eq{"`action`.repo_id": opts.RequestedRepo.ID},
|
||||||
|
builder.Expr("`action`.user_id = `action`.act_user_id"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.RequestedTeam != nil {
|
if opts.RequestedTeam != nil {
|
||||||
@ -577,6 +582,10 @@ func DeleteOldActions(ctx context.Context, olderThan time.Duration) (err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NotifyWatchers creates batch of actions for every watcher.
|
// NotifyWatchers creates batch of actions for every watcher.
|
||||||
|
// It could insert duplicate actions for a repository action, like this:
|
||||||
|
// * Original action: UserID=1 (the real actor), ActUserID=1
|
||||||
|
// * Organization action: UserID=100 (the repo's org), ActUserID=1
|
||||||
|
// * Watcher action: UserID=20 (a user who is watching a repo), ActUserID=1
|
||||||
func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||||
var watchers []*repo_model.Watch
|
var watchers []*repo_model.Watch
|
||||||
var repo *repo_model.Repository
|
var repo *repo_model.Repository
|
||||||
|
@ -318,3 +318,24 @@ func TestDeleteIssueActions(t *testing.T) {
|
|||||||
assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index))
|
assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index))
|
||||||
unittest.AssertCount(t, &activities_model.Action{}, 0)
|
unittest.AssertCount(t, &activities_model.Action{}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRepoActions(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
|
_ = db.TruncateBeans(db.DefaultContext, &activities_model.Action{})
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
_ = db.Insert(db.DefaultContext, &activities_model.Action{
|
||||||
|
UserID: 2 + int64(i),
|
||||||
|
ActUserID: 2,
|
||||||
|
RepoID: repo.ID,
|
||||||
|
OpType: activities_model.ActionCommentIssue,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
count, _ := db.Count[activities_model.Action](db.DefaultContext, &db.ListOptions{})
|
||||||
|
assert.EqualValues(t, 3, count)
|
||||||
|
actions, _, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedRepo: repo,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 1)
|
||||||
|
}
|
||||||
|
24
models/fixtures/protected_tag.yml
Normal file
24
models/fixtures/protected_tag.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
-
|
||||||
|
id: 1
|
||||||
|
repo_id: 4
|
||||||
|
name_pattern: /v.+/
|
||||||
|
allowlist_user_i_ds: []
|
||||||
|
allowlist_team_i_ds: []
|
||||||
|
created_unix: 1715596037
|
||||||
|
updated_unix: 1715596037
|
||||||
|
-
|
||||||
|
id: 2
|
||||||
|
repo_id: 1
|
||||||
|
name_pattern: v-*
|
||||||
|
allowlist_user_i_ds: []
|
||||||
|
allowlist_team_i_ds: []
|
||||||
|
created_unix: 1715596037
|
||||||
|
updated_unix: 1715596037
|
||||||
|
-
|
||||||
|
id: 3
|
||||||
|
repo_id: 1
|
||||||
|
name_pattern: v-1.1
|
||||||
|
allowlist_user_i_ds: [2]
|
||||||
|
allowlist_team_i_ds: []
|
||||||
|
created_unix: 1715596037
|
||||||
|
updated_unix: 1715596037
|
@ -7,6 +7,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
@ -106,10 +107,23 @@ var (
|
|||||||
TypeExternalTracker,
|
TypeExternalTracker,
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisabledRepoUnits contains the units that have been globally disabled
|
disabledRepoUnitsAtomic atomic.Pointer[[]Type] // the units that have been globally disabled
|
||||||
DisabledRepoUnits = []Type{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DisabledRepoUnitsGet returns the globally disabled units, it is a quick patch to fix data-race during testing.
|
||||||
|
// Because the queue worker might read when a test is mocking the value. FIXME: refactor to a clear solution later.
|
||||||
|
func DisabledRepoUnitsGet() []Type {
|
||||||
|
v := disabledRepoUnitsAtomic.Load()
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
|
||||||
|
func DisabledRepoUnitsSet(v []Type) {
|
||||||
|
disabledRepoUnitsAtomic.Store(&v)
|
||||||
|
}
|
||||||
|
|
||||||
// Get valid set of default repository units from settings
|
// Get valid set of default repository units from settings
|
||||||
func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
|
func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
|
||||||
units := defaultUnits
|
units := defaultUnits
|
||||||
@ -127,7 +141,7 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove disabled units
|
// Remove disabled units
|
||||||
for _, disabledUnit := range DisabledRepoUnits {
|
for _, disabledUnit := range DisabledRepoUnitsGet() {
|
||||||
for i, unit := range units {
|
for i, unit := range units {
|
||||||
if unit == disabledUnit {
|
if unit == disabledUnit {
|
||||||
units = append(units[:i], units[i+1:]...)
|
units = append(units[:i], units[i+1:]...)
|
||||||
@ -140,11 +154,11 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
|
|||||||
|
|
||||||
// LoadUnitConfig load units from settings
|
// LoadUnitConfig load units from settings
|
||||||
func LoadUnitConfig() error {
|
func LoadUnitConfig() error {
|
||||||
var invalidKeys []string
|
disabledRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DisabledRepoUnits...)
|
||||||
DisabledRepoUnits, invalidKeys = FindUnitTypes(setting.Repository.DisabledRepoUnits...)
|
|
||||||
if len(invalidKeys) > 0 {
|
if len(invalidKeys) > 0 {
|
||||||
log.Warn("Invalid keys in disabled repo units: %s", strings.Join(invalidKeys, ", "))
|
log.Warn("Invalid keys in disabled repo units: %s", strings.Join(invalidKeys, ", "))
|
||||||
}
|
}
|
||||||
|
DisabledRepoUnitsSet(disabledRepoUnits)
|
||||||
|
|
||||||
setDefaultRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultRepoUnits...)
|
setDefaultRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultRepoUnits...)
|
||||||
if len(invalidKeys) > 0 {
|
if len(invalidKeys) > 0 {
|
||||||
@ -167,7 +181,7 @@ func LoadUnitConfig() error {
|
|||||||
|
|
||||||
// UnitGlobalDisabled checks if unit type is global disabled
|
// UnitGlobalDisabled checks if unit type is global disabled
|
||||||
func (u Type) UnitGlobalDisabled() bool {
|
func (u Type) UnitGlobalDisabled() bool {
|
||||||
for _, ud := range DisabledRepoUnits {
|
for _, ud := range DisabledRepoUnitsGet() {
|
||||||
if u == ud {
|
if u == ud {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,10 @@ import (
|
|||||||
func TestLoadUnitConfig(t *testing.T) {
|
func TestLoadUnitConfig(t *testing.T) {
|
||||||
t.Run("regular", func(t *testing.T) {
|
t.Run("regular", func(t *testing.T) {
|
||||||
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
|
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
|
||||||
DisabledRepoUnits = disabledRepoUnits
|
DisabledRepoUnitsSet(disabledRepoUnits)
|
||||||
DefaultRepoUnits = defaultRepoUnits
|
DefaultRepoUnits = defaultRepoUnits
|
||||||
DefaultForkRepoUnits = defaultForkRepoUnits
|
DefaultForkRepoUnits = defaultForkRepoUnits
|
||||||
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits)
|
}(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits)
|
||||||
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
|
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
|
||||||
setting.Repository.DisabledRepoUnits = disabledRepoUnits
|
setting.Repository.DisabledRepoUnits = disabledRepoUnits
|
||||||
setting.Repository.DefaultRepoUnits = defaultRepoUnits
|
setting.Repository.DefaultRepoUnits = defaultRepoUnits
|
||||||
@ -28,16 +28,16 @@ func TestLoadUnitConfig(t *testing.T) {
|
|||||||
setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls"}
|
setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls"}
|
||||||
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases"}
|
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases"}
|
||||||
assert.NoError(t, LoadUnitConfig())
|
assert.NoError(t, LoadUnitConfig())
|
||||||
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
|
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet())
|
||||||
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
|
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
|
||||||
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
|
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
|
||||||
})
|
})
|
||||||
t.Run("invalid", func(t *testing.T) {
|
t.Run("invalid", func(t *testing.T) {
|
||||||
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
|
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
|
||||||
DisabledRepoUnits = disabledRepoUnits
|
DisabledRepoUnitsSet(disabledRepoUnits)
|
||||||
DefaultRepoUnits = defaultRepoUnits
|
DefaultRepoUnits = defaultRepoUnits
|
||||||
DefaultForkRepoUnits = defaultForkRepoUnits
|
DefaultForkRepoUnits = defaultForkRepoUnits
|
||||||
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits)
|
}(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits)
|
||||||
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
|
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
|
||||||
setting.Repository.DisabledRepoUnits = disabledRepoUnits
|
setting.Repository.DisabledRepoUnits = disabledRepoUnits
|
||||||
setting.Repository.DefaultRepoUnits = defaultRepoUnits
|
setting.Repository.DefaultRepoUnits = defaultRepoUnits
|
||||||
@ -48,16 +48,16 @@ func TestLoadUnitConfig(t *testing.T) {
|
|||||||
setting.Repository.DefaultRepoUnits = []string{"repo.code", "invalid.2", "repo.releases", "repo.issues", "repo.pulls"}
|
setting.Repository.DefaultRepoUnits = []string{"repo.code", "invalid.2", "repo.releases", "repo.issues", "repo.pulls"}
|
||||||
setting.Repository.DefaultForkRepoUnits = []string{"invalid.3", "repo.releases"}
|
setting.Repository.DefaultForkRepoUnits = []string{"invalid.3", "repo.releases"}
|
||||||
assert.NoError(t, LoadUnitConfig())
|
assert.NoError(t, LoadUnitConfig())
|
||||||
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
|
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet())
|
||||||
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
|
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
|
||||||
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
|
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
|
||||||
})
|
})
|
||||||
t.Run("duplicate", func(t *testing.T) {
|
t.Run("duplicate", func(t *testing.T) {
|
||||||
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
|
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
|
||||||
DisabledRepoUnits = disabledRepoUnits
|
DisabledRepoUnitsSet(disabledRepoUnits)
|
||||||
DefaultRepoUnits = defaultRepoUnits
|
DefaultRepoUnits = defaultRepoUnits
|
||||||
DefaultForkRepoUnits = defaultForkRepoUnits
|
DefaultForkRepoUnits = defaultForkRepoUnits
|
||||||
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits)
|
}(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits)
|
||||||
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
|
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
|
||||||
setting.Repository.DisabledRepoUnits = disabledRepoUnits
|
setting.Repository.DisabledRepoUnits = disabledRepoUnits
|
||||||
setting.Repository.DefaultRepoUnits = defaultRepoUnits
|
setting.Repository.DefaultRepoUnits = defaultRepoUnits
|
||||||
@ -68,16 +68,16 @@ func TestLoadUnitConfig(t *testing.T) {
|
|||||||
setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls", "repo.code"}
|
setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls", "repo.code"}
|
||||||
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"}
|
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"}
|
||||||
assert.NoError(t, LoadUnitConfig())
|
assert.NoError(t, LoadUnitConfig())
|
||||||
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
|
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet())
|
||||||
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
|
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
|
||||||
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
|
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
|
||||||
})
|
})
|
||||||
t.Run("empty_default", func(t *testing.T) {
|
t.Run("empty_default", func(t *testing.T) {
|
||||||
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
|
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
|
||||||
DisabledRepoUnits = disabledRepoUnits
|
DisabledRepoUnitsSet(disabledRepoUnits)
|
||||||
DefaultRepoUnits = defaultRepoUnits
|
DefaultRepoUnits = defaultRepoUnits
|
||||||
DefaultForkRepoUnits = defaultForkRepoUnits
|
DefaultForkRepoUnits = defaultForkRepoUnits
|
||||||
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits)
|
}(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits)
|
||||||
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
|
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
|
||||||
setting.Repository.DisabledRepoUnits = disabledRepoUnits
|
setting.Repository.DisabledRepoUnits = disabledRepoUnits
|
||||||
setting.Repository.DefaultRepoUnits = defaultRepoUnits
|
setting.Repository.DefaultRepoUnits = defaultRepoUnits
|
||||||
@ -88,7 +88,7 @@ func TestLoadUnitConfig(t *testing.T) {
|
|||||||
setting.Repository.DefaultRepoUnits = []string{}
|
setting.Repository.DefaultRepoUnits = []string{}
|
||||||
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"}
|
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"}
|
||||||
assert.NoError(t, LoadUnitConfig())
|
assert.NoError(t, LoadUnitConfig())
|
||||||
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
|
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet())
|
||||||
assert.ElementsMatch(t, []Type{TypeCode, TypePullRequests, TypeReleases, TypeWiki, TypePackages, TypeProjects, TypeActions}, DefaultRepoUnits)
|
assert.ElementsMatch(t, []Type{TypeCode, TypePullRequests, TypeReleases, TypeWiki, TypePackages, TypeProjects, TypeActions}, DefaultRepoUnits)
|
||||||
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
|
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
|
||||||
})
|
})
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"net/mail"
|
"net/mail"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
@ -353,14 +354,12 @@ func ChangeInactivePrimaryEmail(ctx context.Context, uid int64, oldEmailAddr, ne
|
|||||||
|
|
||||||
// VerifyActiveEmailCode verifies active email code when active account
|
// VerifyActiveEmailCode verifies active email code when active account
|
||||||
func VerifyActiveEmailCode(ctx context.Context, code, email string) *EmailAddress {
|
func VerifyActiveEmailCode(ctx context.Context, code, email string) *EmailAddress {
|
||||||
minutes := setting.Service.ActiveCodeLives
|
|
||||||
|
|
||||||
if user := GetVerifyUser(ctx, code); user != nil {
|
if user := GetVerifyUser(ctx, code); user != nil {
|
||||||
// time limit code
|
// time limit code
|
||||||
prefix := code[:base.TimeLimitCodeLength]
|
prefix := code[:base.TimeLimitCodeLength]
|
||||||
data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands)
|
data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands)
|
||||||
|
|
||||||
if base.VerifyTimeLimitCode(data, minutes, prefix) {
|
if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) {
|
||||||
emailAddress := &EmailAddress{UID: user.ID, Email: email}
|
emailAddress := &EmailAddress{UID: user.ID, Email: email}
|
||||||
if has, _ := db.GetEngine(ctx).Get(emailAddress); has {
|
if has, _ := db.GetEngine(ctx).Get(emailAddress); has {
|
||||||
return emailAddress
|
return emailAddress
|
||||||
|
@ -304,7 +304,7 @@ func (u *User) OrganisationLink() string {
|
|||||||
func (u *User) GenerateEmailActivateCode(email string) string {
|
func (u *User) GenerateEmailActivateCode(email string) string {
|
||||||
code := base.CreateTimeLimitCode(
|
code := base.CreateTimeLimitCode(
|
||||||
fmt.Sprintf("%d%s%s%s%s", u.ID, email, u.LowerName, u.Passwd, u.Rands),
|
fmt.Sprintf("%d%s%s%s%s", u.ID, email, u.LowerName, u.Passwd, u.Rands),
|
||||||
setting.Service.ActiveCodeLives, nil)
|
setting.Service.ActiveCodeLives, time.Now(), nil)
|
||||||
|
|
||||||
// Add tail hex username
|
// Add tail hex username
|
||||||
code += hex.EncodeToString([]byte(u.LowerName))
|
code += hex.EncodeToString([]byte(u.LowerName))
|
||||||
@ -791,14 +791,11 @@ func GetVerifyUser(ctx context.Context, code string) (user *User) {
|
|||||||
|
|
||||||
// VerifyUserActiveCode verifies active code when active account
|
// VerifyUserActiveCode verifies active code when active account
|
||||||
func VerifyUserActiveCode(ctx context.Context, code string) (user *User) {
|
func VerifyUserActiveCode(ctx context.Context, code string) (user *User) {
|
||||||
minutes := setting.Service.ActiveCodeLives
|
|
||||||
|
|
||||||
if user = GetVerifyUser(ctx, code); user != nil {
|
if user = GetVerifyUser(ctx, code); user != nil {
|
||||||
// time limit code
|
// time limit code
|
||||||
prefix := code[:base.TimeLimitCodeLength]
|
prefix := code[:base.TimeLimitCodeLength]
|
||||||
data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands)
|
data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands)
|
||||||
|
if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) {
|
||||||
if base.VerifyTimeLimitCode(data, minutes, prefix) {
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,15 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"crypto/subtle"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"hash"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -25,13 +28,6 @@ import (
|
|||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EncodeSha1 string to sha1 hex value.
|
|
||||||
func EncodeSha1(str string) string {
|
|
||||||
h := sha1.New()
|
|
||||||
_, _ = h.Write([]byte(str))
|
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeSha256 string to sha256 hex value.
|
// EncodeSha256 string to sha256 hex value.
|
||||||
func EncodeSha256(str string) string {
|
func EncodeSha256(str string) string {
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
@ -62,63 +58,62 @@ func BasicAuthDecode(encoded string) (string, string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VerifyTimeLimitCode verify time limit code
|
// VerifyTimeLimitCode verify time limit code
|
||||||
func VerifyTimeLimitCode(data string, minutes int, code string) bool {
|
func VerifyTimeLimitCode(now time.Time, data string, minutes int, code string) bool {
|
||||||
if len(code) <= 18 {
|
if len(code) <= 18 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// split code
|
startTimeStr := code[:12]
|
||||||
start := code[:12]
|
aliveTimeStr := code[12:18]
|
||||||
lives := code[12:18]
|
aliveTime, _ := strconv.Atoi(aliveTimeStr) // no need to check err, if anything wrong, the following code check will fail soon
|
||||||
if d, err := strconv.ParseInt(lives, 10, 0); err == nil {
|
|
||||||
minutes = int(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
// right active code
|
|
||||||
retCode := CreateTimeLimitCode(data, minutes, start)
|
|
||||||
if retCode == code && minutes > 0 {
|
|
||||||
// check time is expired or not
|
|
||||||
before, _ := time.ParseInLocation("200601021504", start, time.Local)
|
|
||||||
now := time.Now()
|
|
||||||
if before.Add(time.Minute*time.Duration(minutes)).Unix() > now.Unix() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// check code
|
||||||
|
retCode := CreateTimeLimitCode(data, aliveTime, startTimeStr, nil)
|
||||||
|
if subtle.ConstantTimeCompare([]byte(retCode), []byte(code)) != 1 {
|
||||||
|
retCode = CreateTimeLimitCode(data, aliveTime, startTimeStr, sha1.New()) // TODO: this is only for the support of legacy codes, remove this in/after 1.23
|
||||||
|
if subtle.ConstantTimeCompare([]byte(retCode), []byte(code)) != 1 {
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check time is expired or not: startTime <= now && now < startTime + minutes
|
||||||
|
startTime, _ := time.ParseInLocation("200601021504", startTimeStr, time.Local)
|
||||||
|
return (startTime.Before(now) || startTime.Equal(now)) && now.Before(startTime.Add(time.Minute*time.Duration(minutes)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TimeLimitCodeLength default value for time limit code
|
// TimeLimitCodeLength default value for time limit code
|
||||||
const TimeLimitCodeLength = 12 + 6 + 40
|
const TimeLimitCodeLength = 12 + 6 + 40
|
||||||
|
|
||||||
// CreateTimeLimitCode create a time limit code
|
// CreateTimeLimitCode create a time-limited code.
|
||||||
// code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string
|
// Format: 12 length date time string + 6 minutes string (not used) + 40 hash string, some other code depends on this fixed length
|
||||||
func CreateTimeLimitCode(data string, minutes int, startInf any) string {
|
// If h is nil, then use the default hmac hash.
|
||||||
format := "200601021504"
|
func CreateTimeLimitCode[T time.Time | string](data string, minutes int, startTimeGeneric T, h hash.Hash) string {
|
||||||
|
const format = "200601021504"
|
||||||
|
|
||||||
var start, end time.Time
|
var start time.Time
|
||||||
var startStr, endStr string
|
var startTimeAny any = startTimeGeneric
|
||||||
|
if t, ok := startTimeAny.(time.Time); ok {
|
||||||
if startInf == nil {
|
start = t
|
||||||
// Use now time create code
|
|
||||||
start = time.Now()
|
|
||||||
startStr = start.Format(format)
|
|
||||||
} else {
|
} else {
|
||||||
// use start string create code
|
var err error
|
||||||
startStr = startInf.(string)
|
start, err = time.ParseInLocation(format, startTimeAny.(string), time.Local)
|
||||||
start, _ = time.ParseInLocation(format, startStr, time.Local)
|
if err != nil {
|
||||||
startStr = start.Format(format)
|
return "" // return an invalid code because the "parse" failed
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
startStr := start.Format(format)
|
||||||
|
end := start.Add(time.Minute * time.Duration(minutes))
|
||||||
|
|
||||||
end = start.Add(time.Minute * time.Duration(minutes))
|
if h == nil {
|
||||||
endStr = end.Format(format)
|
h = hmac.New(sha1.New, setting.GetGeneralTokenSigningSecret())
|
||||||
|
}
|
||||||
// create sha1 encode string
|
_, _ = fmt.Fprintf(h, "%s%s%s%s%d", data, hex.EncodeToString(setting.GetGeneralTokenSigningSecret()), startStr, end.Format(format), minutes)
|
||||||
sh := sha1.New()
|
encoded := hex.EncodeToString(h.Sum(nil))
|
||||||
_, _ = sh.Write([]byte(fmt.Sprintf("%s%s%s%s%d", data, hex.EncodeToString(setting.GetGeneralTokenSigningSecret()), startStr, endStr, minutes)))
|
|
||||||
encoded := hex.EncodeToString(sh.Sum(nil))
|
|
||||||
|
|
||||||
code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded)
|
code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded)
|
||||||
|
if len(code) != TimeLimitCodeLength {
|
||||||
|
panic("there is a hard requirement for the length of time-limited code") // it shouldn't happen
|
||||||
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,20 +4,18 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncodeSha1(t *testing.T) {
|
|
||||||
assert.Equal(t,
|
|
||||||
"8843d7f92416211de9ebb963ff4ce28125932878",
|
|
||||||
EncodeSha1("foobar"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncodeSha256(t *testing.T) {
|
func TestEncodeSha256(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2",
|
"c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2",
|
||||||
@ -46,43 +44,54 @@ func TestBasicAuthDecode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestVerifyTimeLimitCode(t *testing.T) {
|
func TestVerifyTimeLimitCode(t *testing.T) {
|
||||||
tc := []struct {
|
defer test.MockVariableValue(&setting.InstallLock, true)()
|
||||||
data string
|
initGeneralSecret := func(secret string) {
|
||||||
minutes int
|
setting.InstallLock = true
|
||||||
code string
|
setting.CfgProvider, _ = setting.NewConfigProviderFromData(fmt.Sprintf(`
|
||||||
valid bool
|
[oauth2]
|
||||||
}{{
|
JWT_SECRET = %s
|
||||||
data: "data",
|
`, secret))
|
||||||
minutes: 2,
|
setting.LoadCommonSettings()
|
||||||
code: testCreateTimeLimitCode(t, "data", 2),
|
|
||||||
valid: true,
|
|
||||||
}, {
|
|
||||||
data: "abc123-ß",
|
|
||||||
minutes: 1,
|
|
||||||
code: testCreateTimeLimitCode(t, "abc123-ß", 1),
|
|
||||||
valid: true,
|
|
||||||
}, {
|
|
||||||
data: "data",
|
|
||||||
minutes: 2,
|
|
||||||
code: "2021012723240000005928251dac409d2c33a6eb82c63410aaad569bed",
|
|
||||||
valid: false,
|
|
||||||
}}
|
|
||||||
for _, test := range tc {
|
|
||||||
actualValid := VerifyTimeLimitCode(test.data, test.minutes, test.code)
|
|
||||||
assert.Equal(t, test.valid, actualValid, "data: '%s' code: '%s' should be valid: %t", test.data, test.code, test.valid)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func testCreateTimeLimitCode(t *testing.T, data string, m int) string {
|
initGeneralSecret("KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko")
|
||||||
result0 := CreateTimeLimitCode(data, m, nil)
|
now := time.Now()
|
||||||
result1 := CreateTimeLimitCode(data, m, time.Now().Format("200601021504"))
|
|
||||||
result2 := CreateTimeLimitCode(data, m, time.Unix(time.Now().Unix()+int64(time.Minute)*int64(m), 0).Format("200601021504"))
|
|
||||||
|
|
||||||
assert.Equal(t, result0, result1)
|
t.Run("TestGenericParameter", func(t *testing.T) {
|
||||||
assert.NotEqual(t, result0, result2)
|
time2000 := time.Date(2000, 1, 2, 3, 4, 5, 0, time.Local)
|
||||||
|
assert.Equal(t, "2000010203040000026fa5221b2731b7cf80b1b506f5e39e38c115fee5", CreateTimeLimitCode("test-sha1", 2, time2000, sha1.New()))
|
||||||
|
assert.Equal(t, "2000010203040000026fa5221b2731b7cf80b1b506f5e39e38c115fee5", CreateTimeLimitCode("test-sha1", 2, "200001020304", sha1.New()))
|
||||||
|
assert.Equal(t, "2000010203040000024842227a2f87041ff82025199c0187410a9297bf", CreateTimeLimitCode("test-hmac", 2, time2000, nil))
|
||||||
|
assert.Equal(t, "2000010203040000024842227a2f87041ff82025199c0187410a9297bf", CreateTimeLimitCode("test-hmac", 2, "200001020304", nil))
|
||||||
|
})
|
||||||
|
|
||||||
assert.True(t, len(result0) != 0)
|
t.Run("TestInvalidCode", func(t *testing.T) {
|
||||||
return result0
|
assert.False(t, VerifyTimeLimitCode(now, "data", 2, ""))
|
||||||
|
assert.False(t, VerifyTimeLimitCode(now, "data", 2, "invalid code"))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("TestCreateAndVerify", func(t *testing.T) {
|
||||||
|
code := CreateTimeLimitCode("data", 2, now, nil)
|
||||||
|
assert.False(t, VerifyTimeLimitCode(now.Add(-time.Minute), "data", 2, code)) // not started yet
|
||||||
|
assert.True(t, VerifyTimeLimitCode(now, "data", 2, code))
|
||||||
|
assert.True(t, VerifyTimeLimitCode(now.Add(time.Minute), "data", 2, code))
|
||||||
|
assert.False(t, VerifyTimeLimitCode(now.Add(time.Minute), "DATA", 2, code)) // invalid data
|
||||||
|
assert.False(t, VerifyTimeLimitCode(now.Add(2*time.Minute), "data", 2, code)) // expired
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("TestDifferentSecret", func(t *testing.T) {
|
||||||
|
// use another secret to ensure the code is invalid for different secret
|
||||||
|
verifyDataCode := func(c string) bool {
|
||||||
|
return VerifyTimeLimitCode(now, "data", 2, c)
|
||||||
|
}
|
||||||
|
code1 := CreateTimeLimitCode("data", 2, now, sha1.New())
|
||||||
|
code2 := CreateTimeLimitCode("data", 2, now, nil)
|
||||||
|
assert.True(t, verifyDataCode(code1))
|
||||||
|
assert.True(t, verifyDataCode(code2))
|
||||||
|
initGeneralSecret("000_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko")
|
||||||
|
assert.False(t, verifyDataCode(code1))
|
||||||
|
assert.False(t, verifyDataCode(code2))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFileSize(t *testing.T) {
|
func TestFileSize(t *testing.T) {
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@ -128,3 +130,9 @@ func (l *LimitedReaderCloser) Read(p []byte) (n int, err error) {
|
|||||||
func (l *LimitedReaderCloser) Close() error {
|
func (l *LimitedReaderCloser) Close() error {
|
||||||
return l.C.Close()
|
return l.C.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HashFilePathForWebUI(s string) string {
|
||||||
|
h := sha1.New()
|
||||||
|
_, _ = h.Write([]byte(s))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
17
modules/git/utils_test.go
Normal file
17
modules/git/utils_test.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHashFilePathForWebUI(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
"8843d7f92416211de9ebb963ff4ce28125932878",
|
||||||
|
HashFilePathForWebUI("foobar"),
|
||||||
|
)
|
||||||
|
}
|
@ -32,7 +32,7 @@ func IsRelativeURL(s string) bool {
|
|||||||
return err == nil && urlIsRelative(s, u)
|
return err == nil && urlIsRelative(s, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func guessRequestScheme(req *http.Request, def string) string {
|
func getRequestScheme(req *http.Request) string {
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
|
||||||
if s := req.Header.Get("X-Forwarded-Proto"); s != "" {
|
if s := req.Header.Get("X-Forwarded-Proto"); s != "" {
|
||||||
return s
|
return s
|
||||||
@ -49,10 +49,10 @@ func guessRequestScheme(req *http.Request, def string) string {
|
|||||||
if s := req.Header.Get("X-Forwarded-Ssl"); s != "" {
|
if s := req.Header.Get("X-Forwarded-Ssl"); s != "" {
|
||||||
return util.Iif(s == "on", "https", "http")
|
return util.Iif(s == "on", "https", "http")
|
||||||
}
|
}
|
||||||
return def
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func guessForwardedHost(req *http.Request) string {
|
func getForwardedHost(req *http.Request) string {
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host
|
||||||
return req.Header.Get("X-Forwarded-Host")
|
return req.Header.Get("X-Forwarded-Host")
|
||||||
}
|
}
|
||||||
@ -63,15 +63,24 @@ func GuessCurrentAppURL(ctx context.Context) string {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return setting.AppURL
|
return setting.AppURL
|
||||||
}
|
}
|
||||||
if host := guessForwardedHost(req); host != "" {
|
// If no scheme provided by reverse proxy, then do not guess the AppURL, use the configured one.
|
||||||
// if it is behind a reverse proxy, use "https" as default scheme in case the site admin forgets to set the correct forwarded-protocol headers
|
// At the moment, if site admin doesn't configure the proxy headers correctly, then Gitea would guess wrong.
|
||||||
return guessRequestScheme(req, "https") + "://" + host + setting.AppSubURL + "/"
|
// There are some cases:
|
||||||
} else if req.Host != "" {
|
// 1. The reverse proxy is configured correctly, it passes "X-Forwarded-Proto/Host" headers. Perfect, Gitea can handle it correctly.
|
||||||
// if it is not behind a reverse proxy, use the scheme from config options, meanwhile use "https" as much as possible
|
// 2. The reverse proxy is not configured correctly, doesn't pass "X-Forwarded-Proto/Host" headers, eg: only one "proxy_pass http://gitea:3000" in Nginx.
|
||||||
defaultScheme := util.Iif(setting.Protocol == "http", "http", "https")
|
// 3. There is no reverse proxy.
|
||||||
return guessRequestScheme(req, defaultScheme) + "://" + req.Host + setting.AppSubURL + "/"
|
// Without an extra config option, Gitea is impossible to distinguish between case 2 and case 3,
|
||||||
}
|
// then case 2 would result in wrong guess like guessed AppURL becomes "http://gitea:3000/", which is not accessible by end users.
|
||||||
|
// So in the future maybe it should introduce a new config option, to let site admin decide how to guess the AppURL.
|
||||||
|
reqScheme := getRequestScheme(req)
|
||||||
|
if reqScheme == "" {
|
||||||
return setting.AppURL
|
return setting.AppURL
|
||||||
|
}
|
||||||
|
reqHost := getForwardedHost(req)
|
||||||
|
if reqHost == "" {
|
||||||
|
reqHost = req.Host
|
||||||
|
}
|
||||||
|
return reqScheme + "://" + reqHost + setting.AppSubURL + "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeAbsoluteURL(ctx context.Context, s string) string {
|
func MakeAbsoluteURL(ctx context.Context, s string) string {
|
||||||
|
@ -41,19 +41,19 @@ func TestIsRelativeURL(t *testing.T) {
|
|||||||
|
|
||||||
func TestMakeAbsoluteURL(t *testing.T) {
|
func TestMakeAbsoluteURL(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.Protocol, "http")()
|
defer test.MockVariableValue(&setting.Protocol, "http")()
|
||||||
defer test.MockVariableValue(&setting.AppURL, "http://the-host/sub/")()
|
defer test.MockVariableValue(&setting.AppURL, "http://cfg-host/sub/")()
|
||||||
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
assert.Equal(t, "http://the-host/sub/", MakeAbsoluteURL(ctx, ""))
|
assert.Equal(t, "http://cfg-host/sub/", MakeAbsoluteURL(ctx, ""))
|
||||||
assert.Equal(t, "http://the-host/sub/foo", MakeAbsoluteURL(ctx, "foo"))
|
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "foo"))
|
||||||
assert.Equal(t, "http://the-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
||||||
assert.Equal(t, "http://other/foo", MakeAbsoluteURL(ctx, "http://other/foo"))
|
assert.Equal(t, "http://other/foo", MakeAbsoluteURL(ctx, "http://other/foo"))
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
||||||
Host: "user-host",
|
Host: "user-host",
|
||||||
})
|
})
|
||||||
assert.Equal(t, "http://user-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
||||||
Host: "user-host",
|
Host: "user-host",
|
||||||
@ -61,7 +61,7 @@ func TestMakeAbsoluteURL(t *testing.T) {
|
|||||||
"X-Forwarded-Host": {"forwarded-host"},
|
"X-Forwarded-Host": {"forwarded-host"},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
assert.Equal(t, "https://forwarded-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
||||||
Host: "user-host",
|
Host: "user-host",
|
||||||
|
@ -126,16 +126,15 @@ func loadOAuth2From(rootCfg ConfigProvider) {
|
|||||||
OAuth2.Enabled = sec.Key("ENABLE").MustBool(OAuth2.Enabled)
|
OAuth2.Enabled = sec.Key("ENABLE").MustBool(OAuth2.Enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !OAuth2.Enabled {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
jwtSecretBase64 := loadSecret(sec, "JWT_SECRET_URI", "JWT_SECRET")
|
|
||||||
|
|
||||||
if !filepath.IsAbs(OAuth2.JWTSigningPrivateKeyFile) {
|
if !filepath.IsAbs(OAuth2.JWTSigningPrivateKeyFile) {
|
||||||
OAuth2.JWTSigningPrivateKeyFile = filepath.Join(AppDataPath, OAuth2.JWTSigningPrivateKeyFile)
|
OAuth2.JWTSigningPrivateKeyFile = filepath.Join(AppDataPath, OAuth2.JWTSigningPrivateKeyFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: at the moment, no matter oauth2 is enabled or not, it must generate a "oauth2 JWT_SECRET"
|
||||||
|
// Because this secret is also used as GeneralTokenSigningSecret (as a quick not-that-breaking fix for some legacy problems).
|
||||||
|
// Including: CSRF token, account validation token, etc ...
|
||||||
|
// In main branch, the signing token should be refactored (eg: one unique for LFS/OAuth2/etc ...)
|
||||||
|
jwtSecretBase64 := loadSecret(sec, "JWT_SECRET_URI", "JWT_SECRET")
|
||||||
if InstallLock {
|
if InstallLock {
|
||||||
jwtSecretBytes, err := generate.DecodeJwtSecretBase64(jwtSecretBase64)
|
jwtSecretBytes, err := generate.DecodeJwtSecretBase64(jwtSecretBase64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -157,8 +156,6 @@ func loadOAuth2From(rootCfg ConfigProvider) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generalSigningSecret is used as container for a []byte value
|
|
||||||
// instead of an additional mutex, we use CompareAndSwap func to change the value thread save
|
|
||||||
var generalSigningSecret atomic.Pointer[[]byte]
|
var generalSigningSecret atomic.Pointer[[]byte]
|
||||||
|
|
||||||
func GetGeneralTokenSigningSecret() []byte {
|
func GetGeneralTokenSigningSecret() []byte {
|
||||||
@ -166,11 +163,9 @@ func GetGeneralTokenSigningSecret() []byte {
|
|||||||
if old == nil || len(*old) == 0 {
|
if old == nil || len(*old) == 0 {
|
||||||
jwtSecret, _, err := generate.NewJwtSecretWithBase64()
|
jwtSecret, _, err := generate.NewJwtSecretWithBase64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Unable to generate general JWT secret: %s", err.Error())
|
log.Fatal("Unable to generate general JWT secret: %v", err)
|
||||||
}
|
}
|
||||||
if generalSigningSecret.CompareAndSwap(old, &jwtSecret) {
|
if generalSigningSecret.CompareAndSwap(old, &jwtSecret) {
|
||||||
// FIXME: in main branch, the signing token should be refactored (eg: one unique for LFS/OAuth2/etc ...)
|
|
||||||
LogStartupProblem(1, log.WARN, "OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes")
|
|
||||||
return jwtSecret
|
return jwtSecret
|
||||||
}
|
}
|
||||||
return *generalSigningSecret.Load()
|
return *generalSigningSecret.Load()
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
package setting
|
package setting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/generate"
|
"code.gitea.io/gitea/modules/generate"
|
||||||
@ -14,7 +15,7 @@ import (
|
|||||||
|
|
||||||
func TestGetGeneralSigningSecret(t *testing.T) {
|
func TestGetGeneralSigningSecret(t *testing.T) {
|
||||||
// when there is no general signing secret, it should be generated, and keep the same value
|
// when there is no general signing secret, it should be generated, and keep the same value
|
||||||
assert.Nil(t, generalSigningSecret.Load())
|
generalSigningSecret.Store(nil)
|
||||||
s1 := GetGeneralTokenSigningSecret()
|
s1 := GetGeneralTokenSigningSecret()
|
||||||
assert.NotNil(t, s1)
|
assert.NotNil(t, s1)
|
||||||
s2 := GetGeneralTokenSigningSecret()
|
s2 := GetGeneralTokenSigningSecret()
|
||||||
@ -33,6 +34,31 @@ JWT_SECRET = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
|
|||||||
assert.EqualValues(t, expected, actual)
|
assert.EqualValues(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetGeneralSigningSecretSave(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&InstallLock, true)()
|
||||||
|
|
||||||
|
old := GetGeneralTokenSigningSecret()
|
||||||
|
assert.Len(t, old, 32)
|
||||||
|
|
||||||
|
tmpFile := t.TempDir() + "/app.ini"
|
||||||
|
_ = os.WriteFile(tmpFile, nil, 0o644)
|
||||||
|
cfg, _ := NewConfigProviderFromFile(tmpFile)
|
||||||
|
loadOAuth2From(cfg)
|
||||||
|
generated := GetGeneralTokenSigningSecret()
|
||||||
|
assert.Len(t, generated, 32)
|
||||||
|
assert.NotEqual(t, old, generated)
|
||||||
|
|
||||||
|
generalSigningSecret.Store(nil)
|
||||||
|
cfg, _ = NewConfigProviderFromFile(tmpFile)
|
||||||
|
loadOAuth2From(cfg)
|
||||||
|
again := GetGeneralTokenSigningSecret()
|
||||||
|
assert.Equal(t, generated, again)
|
||||||
|
|
||||||
|
iniContent, err := os.ReadFile(tmpFile)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Contains(t, string(iniContent), "JWT_SECRET = ")
|
||||||
|
}
|
||||||
|
|
||||||
func TestOauth2DefaultApplications(t *testing.T) {
|
func TestOauth2DefaultApplications(t *testing.T) {
|
||||||
cfg, _ := NewConfigProviderFromData(``)
|
cfg, _ := NewConfigProviderFromData(``)
|
||||||
loadOAuth2From(cfg)
|
loadOAuth2From(cfg)
|
||||||
|
@ -47,6 +47,7 @@ type MinioStorageConfig struct {
|
|||||||
InsecureSkipVerify bool `ini:"MINIO_INSECURE_SKIP_VERIFY"`
|
InsecureSkipVerify bool `ini:"MINIO_INSECURE_SKIP_VERIFY"`
|
||||||
ChecksumAlgorithm string `ini:"MINIO_CHECKSUM_ALGORITHM" json:",omitempty"`
|
ChecksumAlgorithm string `ini:"MINIO_CHECKSUM_ALGORITHM" json:",omitempty"`
|
||||||
ServeDirect bool `ini:"SERVE_DIRECT"`
|
ServeDirect bool `ini:"SERVE_DIRECT"`
|
||||||
|
BucketLookUpType string `ini:"MINIO_BUCKET_LOOKUP_TYPE" json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storage represents configuration of storages
|
// Storage represents configuration of storages
|
||||||
@ -82,6 +83,7 @@ func getDefaultStorageSection(rootCfg ConfigProvider) ConfigSection {
|
|||||||
storageSec.Key("MINIO_USE_SSL").MustBool(false)
|
storageSec.Key("MINIO_USE_SSL").MustBool(false)
|
||||||
storageSec.Key("MINIO_INSECURE_SKIP_VERIFY").MustBool(false)
|
storageSec.Key("MINIO_INSECURE_SKIP_VERIFY").MustBool(false)
|
||||||
storageSec.Key("MINIO_CHECKSUM_ALGORITHM").MustString("default")
|
storageSec.Key("MINIO_CHECKSUM_ALGORITHM").MustString("default")
|
||||||
|
storageSec.Key("MINIO_BUCKET_LOOKUP_TYPE").MustString("auto")
|
||||||
return storageSec
|
return storageSec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,11 +85,23 @@ func NewMinioStorage(ctx context.Context, cfg *setting.Storage) (ObjectStorage,
|
|||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
var lookup minio.BucketLookupType
|
||||||
|
if config.BucketLookUpType == "auto" || config.BucketLookUpType == "" {
|
||||||
|
lookup = minio.BucketLookupAuto
|
||||||
|
} else if config.BucketLookUpType == "dns" {
|
||||||
|
lookup = minio.BucketLookupDNS
|
||||||
|
} else if config.BucketLookUpType == "path" {
|
||||||
|
lookup = minio.BucketLookupPath
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("invalid minio bucket lookup type: %s", config.BucketLookUpType)
|
||||||
|
}
|
||||||
|
|
||||||
minioClient, err := minio.New(config.Endpoint, &minio.Options{
|
minioClient, err := minio.New(config.Endpoint, &minio.Options{
|
||||||
Creds: credentials.NewStaticV4(config.AccessKeyID, config.SecretAccessKey, ""),
|
Creds: credentials.NewStaticV4(config.AccessKeyID, config.SecretAccessKey, ""),
|
||||||
Secure: config.UseSSL,
|
Secure: config.UseSSL,
|
||||||
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify}},
|
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify}},
|
||||||
Region: config.Location,
|
Region: config.Location,
|
||||||
|
BucketLookup: lookup,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, convertMinioErr(err)
|
return nil, convertMinioErr(err)
|
||||||
|
@ -217,7 +217,7 @@ type EditRepoOption struct {
|
|||||||
Archived *bool `json:"archived,omitempty"`
|
Archived *bool `json:"archived,omitempty"`
|
||||||
// set to a string like `8h30m0s` to set the mirror interval time
|
// set to a string like `8h30m0s` to set the mirror interval time
|
||||||
MirrorInterval *string `json:"mirror_interval,omitempty"`
|
MirrorInterval *string `json:"mirror_interval,omitempty"`
|
||||||
// enable prune - remove obsolete remote-tracking references
|
// enable prune - remove obsolete remote-tracking references when mirroring
|
||||||
EnablePrune *bool `json:"enable_prune,omitempty"`
|
EnablePrune *bool `json:"enable_prune,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -8,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get color as RGB values in 0..255 range from the hex color string (with or without #)
|
// HexToRBGColor parses color as RGB values in 0..255 range from the hex color string (with or without #)
|
||||||
func HexToRBGColor(colorString string) (float64, float64, float64) {
|
func HexToRBGColor(colorString string) (float64, float64, float64) {
|
||||||
hexString := colorString
|
hexString := colorString
|
||||||
if strings.HasPrefix(colorString, "#") {
|
if strings.HasPrefix(colorString, "#") {
|
||||||
@ -35,7 +36,7 @@ func HexToRBGColor(colorString string) (float64, float64, float64) {
|
|||||||
return r, g, b
|
return r, g, b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns relative luminance for a SRGB color - https://en.wikipedia.org/wiki/Relative_luminance
|
// GetRelativeLuminance returns relative luminance for a SRGB color - https://en.wikipedia.org/wiki/Relative_luminance
|
||||||
// Keep this in sync with web_src/js/utils/color.js
|
// Keep this in sync with web_src/js/utils/color.js
|
||||||
func GetRelativeLuminance(color string) float64 {
|
func GetRelativeLuminance(color string) float64 {
|
||||||
r, g, b := HexToRBGColor(color)
|
r, g, b := HexToRBGColor(color)
|
||||||
@ -46,8 +47,8 @@ func UseLightText(backgroundColor string) bool {
|
|||||||
return GetRelativeLuminance(backgroundColor) < 0.453
|
return GetRelativeLuminance(backgroundColor) < 0.453
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a background color, returns a black or white foreground color that the highest
|
// ContrastColor returns a black or white foreground color that the highest contrast ratio.
|
||||||
// contrast ratio. In the future, the APCA contrast function, or CSS `contrast-color` will be better.
|
// In the future, the APCA contrast function, or CSS `contrast-color` will be better.
|
||||||
// https://github.com/color-js/color.js/blob/eb7b53f7a13bb716ec8b28c7a56f052cd599acd9/src/contrast/APCA.js#L42
|
// https://github.com/color-js/color.js/blob/eb7b53f7a13bb716ec8b28c7a56f052cd599acd9/src/contrast/APCA.js#L42
|
||||||
func ContrastColor(backgroundColor string) string {
|
func ContrastColor(backgroundColor string) string {
|
||||||
if UseLightText(backgroundColor) {
|
if UseLightText(backgroundColor) {
|
||||||
|
190
options/license/3D-Slicer-1.0
Normal file
190
options/license/3D-Slicer-1.0
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
3D Slicer Contribution and Software License Agreement ("Agreement")
|
||||||
|
Version 1.0 (December 20, 2005)
|
||||||
|
|
||||||
|
This Agreement covers contributions to and downloads from the 3D
|
||||||
|
Slicer project ("Slicer") maintained by The Brigham and Women's
|
||||||
|
Hospital, Inc. ("Brigham"). Part A of this Agreement applies to
|
||||||
|
contributions of software and/or data to Slicer (including making
|
||||||
|
revisions of or additions to code and/or data already in Slicer). Part
|
||||||
|
B of this Agreement applies to downloads of software and/or data from
|
||||||
|
Slicer. Part C of this Agreement applies to all transactions with
|
||||||
|
Slicer. If you distribute Software (as defined below) downloaded from
|
||||||
|
Slicer, all of the paragraphs of Part B of this Agreement must be
|
||||||
|
included with and apply to such Software.
|
||||||
|
|
||||||
|
Your contribution of software and/or data to Slicer (including prior
|
||||||
|
to the date of the first publication of this Agreement, each a
|
||||||
|
"Contribution") and/or downloading, copying, modifying, displaying,
|
||||||
|
distributing or use of any software and/or data from Slicer
|
||||||
|
(collectively, the "Software") constitutes acceptance of all of the
|
||||||
|
terms and conditions of this Agreement. If you do not agree to such
|
||||||
|
terms and conditions, you have no right to contribute your
|
||||||
|
Contribution, or to download, copy, modify, display, distribute or use
|
||||||
|
the Software.
|
||||||
|
|
||||||
|
PART A. CONTRIBUTION AGREEMENT - License to Brigham with Right to
|
||||||
|
Sublicense ("Contribution Agreement").
|
||||||
|
|
||||||
|
1. As used in this Contribution Agreement, "you" means the individual
|
||||||
|
contributing the Contribution to Slicer and the institution or
|
||||||
|
entity which employs or is otherwise affiliated with such
|
||||||
|
individual in connection with such Contribution.
|
||||||
|
|
||||||
|
2. This Contribution Agreement applies to all Contributions made to
|
||||||
|
Slicer, including without limitation Contributions made prior to
|
||||||
|
the date of first publication of this Agreement. If at any time you
|
||||||
|
make a Contribution to Slicer, you represent that (i) you are
|
||||||
|
legally authorized and entitled to make such Contribution and to
|
||||||
|
grant all licenses granted in this Contribution Agreement with
|
||||||
|
respect to such Contribution; (ii) if your Contribution includes
|
||||||
|
any patient data, all such data is de-identified in accordance with
|
||||||
|
U.S. confidentiality and security laws and requirements, including
|
||||||
|
but not limited to the Health Insurance Portability and
|
||||||
|
Accountability Act (HIPAA) and its regulations, and your disclosure
|
||||||
|
of such data for the purposes contemplated by this Agreement is
|
||||||
|
properly authorized and in compliance with all applicable laws and
|
||||||
|
regulations; and (iii) you have preserved in the Contribution all
|
||||||
|
applicable attributions, copyright notices and licenses for any
|
||||||
|
third party software or data included in the Contribution.
|
||||||
|
|
||||||
|
3. Except for the licenses granted in this Agreement, you reserve all
|
||||||
|
right, title and interest in your Contribution.
|
||||||
|
|
||||||
|
4. You hereby grant to Brigham, with the right to sublicense, a
|
||||||
|
perpetual, worldwide, non-exclusive, no charge, royalty-free,
|
||||||
|
irrevocable license to use, reproduce, make derivative works of,
|
||||||
|
display and distribute the Contribution. If your Contribution is
|
||||||
|
protected by patent, you hereby grant to Brigham, with the right to
|
||||||
|
sublicense, a perpetual, worldwide, non-exclusive, no-charge,
|
||||||
|
royalty-free, irrevocable license under your interest in patent
|
||||||
|
rights covering the Contribution, to make, have made, use, sell and
|
||||||
|
otherwise transfer your Contribution, alone or in combination with
|
||||||
|
any other code.
|
||||||
|
|
||||||
|
5. You acknowledge and agree that Brigham may incorporate your
|
||||||
|
Contribution into Slicer and may make Slicer available to members
|
||||||
|
of the public on an open source basis under terms substantially in
|
||||||
|
accordance with the Software License set forth in Part B of this
|
||||||
|
Agreement. You further acknowledge and agree that Brigham shall
|
||||||
|
have no liability arising in connection with claims resulting from
|
||||||
|
your breach of any of the terms of this Agreement.
|
||||||
|
|
||||||
|
6. YOU WARRANT THAT TO THE BEST OF YOUR KNOWLEDGE YOUR CONTRIBUTION
|
||||||
|
DOES NOT CONTAIN ANY CODE THAT REQUIRES OR PRESCRIBES AN "OPEN
|
||||||
|
SOURCE LICENSE" FOR DERIVATIVE WORKS (by way of non-limiting
|
||||||
|
example, the GNU General Public License or other so-called
|
||||||
|
"reciprocal" license that requires any derived work to be licensed
|
||||||
|
under the GNU General Public License or other "open source
|
||||||
|
license").
|
||||||
|
|
||||||
|
PART B. DOWNLOADING AGREEMENT - License from Brigham with Right to
|
||||||
|
Sublicense ("Software License").
|
||||||
|
|
||||||
|
1. As used in this Software License, "you" means the individual
|
||||||
|
downloading and/or using, reproducing, modifying, displaying and/or
|
||||||
|
distributing the Software and the institution or entity which
|
||||||
|
employs or is otherwise affiliated with such individual in
|
||||||
|
connection therewith. The Brigham and Women's Hospital,
|
||||||
|
Inc. ("Brigham") hereby grants you, with right to sublicense, with
|
||||||
|
respect to Brigham's rights in the software, and data, if any,
|
||||||
|
which is the subject of this Software License (collectively, the
|
||||||
|
"Software"), a royalty-free, non-exclusive license to use,
|
||||||
|
reproduce, make derivative works of, display and distribute the
|
||||||
|
Software, provided that:
|
||||||
|
|
||||||
|
(a) you accept and adhere to all of the terms and conditions of this
|
||||||
|
Software License;
|
||||||
|
|
||||||
|
(b) in connection with any copy of or sublicense of all or any portion
|
||||||
|
of the Software, all of the terms and conditions in this Software
|
||||||
|
License shall appear in and shall apply to such copy and such
|
||||||
|
sublicense, including without limitation all source and executable
|
||||||
|
forms and on any user documentation, prefaced with the following
|
||||||
|
words: "All or portions of this licensed product (such portions are
|
||||||
|
the "Software") have been obtained under license from The Brigham and
|
||||||
|
Women's Hospital, Inc. and are subject to the following terms and
|
||||||
|
conditions:"
|
||||||
|
|
||||||
|
(c) you preserve and maintain all applicable attributions, copyright
|
||||||
|
notices and licenses included in or applicable to the Software;
|
||||||
|
|
||||||
|
(d) modified versions of the Software must be clearly identified and
|
||||||
|
marked as such, and must not be misrepresented as being the original
|
||||||
|
Software; and
|
||||||
|
|
||||||
|
(e) you consider making, but are under no obligation to make, the
|
||||||
|
source code of any of your modifications to the Software freely
|
||||||
|
available to others on an open source basis.
|
||||||
|
|
||||||
|
2. The license granted in this Software License includes without
|
||||||
|
limitation the right to (i) incorporate the Software into
|
||||||
|
proprietary programs (subject to any restrictions applicable to
|
||||||
|
such programs), (ii) add your own copyright statement to your
|
||||||
|
modifications of the Software, and (iii) provide additional or
|
||||||
|
different license terms and conditions in your sublicenses of
|
||||||
|
modifications of the Software; provided that in each case your use,
|
||||||
|
reproduction or distribution of such modifications otherwise
|
||||||
|
complies with the conditions stated in this Software License.
|
||||||
|
|
||||||
|
3. This Software License does not grant any rights with respect to
|
||||||
|
third party software, except those rights that Brigham has been
|
||||||
|
authorized by a third party to grant to you, and accordingly you
|
||||||
|
are solely responsible for (i) obtaining any permissions from third
|
||||||
|
parties that you need to use, reproduce, make derivative works of,
|
||||||
|
display and distribute the Software, and (ii) informing your
|
||||||
|
sublicensees, including without limitation your end-users, of their
|
||||||
|
obligations to secure any such required permissions.
|
||||||
|
|
||||||
|
4. The Software has been designed for research purposes only and has
|
||||||
|
not been reviewed or approved by the Food and Drug Administration
|
||||||
|
or by any other agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL
|
||||||
|
APPLICATIONS ARE NEITHER RECOMMENDED NOR ADVISED. Any
|
||||||
|
commercialization of the Software is at the sole risk of the party
|
||||||
|
or parties engaged in such commercialization. You further agree to
|
||||||
|
use, reproduce, make derivative works of, display and distribute
|
||||||
|
the Software in compliance with all applicable governmental laws,
|
||||||
|
regulations and orders, including without limitation those relating
|
||||||
|
to export and import control.
|
||||||
|
|
||||||
|
5. The Software is provided "AS IS" and neither Brigham nor any
|
||||||
|
contributor to the software (each a "Contributor") shall have any
|
||||||
|
obligation to provide maintenance, support, updates, enhancements
|
||||||
|
or modifications thereto. BRIGHAM AND ALL CONTRIBUTORS SPECIFICALLY
|
||||||
|
DISCLAIM ALL EXPRESS AND IMPLIED WARRANTIES OF ANY KIND INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
BRIGHAM OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR DIRECT,
|
||||||
|
INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY
|
||||||
|
RELATED TO THE SOFTWARE, EVEN IF BRIGHAM OR ANY CONTRIBUTOR HAS
|
||||||
|
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM
|
||||||
|
EXTENT NOT PROHIBITED BY LAW OR REGULATION, YOU FURTHER ASSUME ALL
|
||||||
|
LIABILITY FOR YOUR USE, REPRODUCTION, MAKING OF DERIVATIVE WORKS,
|
||||||
|
DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE AND AGREE TO
|
||||||
|
INDEMNIFY AND HOLD HARMLESS BRIGHAM AND ALL CONTRIBUTORS FROM AND
|
||||||
|
AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS
|
||||||
|
ARISING THEREFROM.
|
||||||
|
|
||||||
|
6. None of the names, logos or trademarks of Brigham or any of
|
||||||
|
Brigham's affiliates or any of the Contributors, or any funding
|
||||||
|
agency, may be used to endorse or promote products produced in
|
||||||
|
whole or in part by operation of the Software or derived from or
|
||||||
|
based on the Software without specific prior written permission
|
||||||
|
from the applicable party.
|
||||||
|
|
||||||
|
7. Any use, reproduction or distribution of the Software which is not
|
||||||
|
in accordance with this Software License shall automatically revoke
|
||||||
|
all rights granted to you under this Software License and render
|
||||||
|
Paragraphs 1 and 2 of this Software License null and void.
|
||||||
|
|
||||||
|
8. This Software License does not grant any rights in or to any
|
||||||
|
intellectual property owned by Brigham or any Contributor except
|
||||||
|
those rights expressly granted hereunder.
|
||||||
|
|
||||||
|
PART C. MISCELLANEOUS
|
||||||
|
|
||||||
|
This Agreement shall be governed by and construed in accordance with
|
||||||
|
the laws of The Commonwealth of Massachusetts without regard to
|
||||||
|
principles of conflicts of law. This Agreement shall supercede and
|
||||||
|
replace any license terms that you may have agreed to previously with
|
||||||
|
respect to Slicer.
|
13
options/license/Asterisk-linking-protocols-exception
Normal file
13
options/license/Asterisk-linking-protocols-exception
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Specific permission is also granted to link Asterisk with OpenSSL, OpenH323
|
||||||
|
UniMRCP, and/or the UW IMAP Toolkit and distribute the resulting binary files.
|
||||||
|
|
||||||
|
In addition, Asterisk implements several management/control protocols.
|
||||||
|
This includes the Asterisk Manager Interface (AMI), the Asterisk Gateway
|
||||||
|
Interface (AGI), and the Asterisk REST Interface (ARI). It is our belief
|
||||||
|
that applications using these protocols to manage or control an Asterisk
|
||||||
|
instance do not have to be licensed under the GPL or a compatible license,
|
||||||
|
as we believe these protocols do not create a 'derivative work' as referred
|
||||||
|
to in the GPL. However, should any court or other judiciary body find that
|
||||||
|
these protocols do fall under the terms of the GPL, then we hereby grant you a
|
||||||
|
license to use these protocols in combination with Asterisk in external
|
||||||
|
applications licensed under any license you wish.
|
25
options/license/HPND-Intel
Normal file
25
options/license/HPND-Intel
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 1993 Intel Corporation
|
||||||
|
|
||||||
|
Intel hereby grants you permission to copy, modify, and distribute this
|
||||||
|
software and its documentation. Intel grants this permission provided
|
||||||
|
that the above copyright notice appears in all copies and that both the
|
||||||
|
copyright notice and this permission notice appear in supporting
|
||||||
|
documentation. In addition, Intel grants this permission provided that
|
||||||
|
you prominently mark as "not part of the original" any modifications
|
||||||
|
made to this software or documentation, and that the name of Intel
|
||||||
|
Corporation not be used in advertising or publicity pertaining to
|
||||||
|
distribution of the software or the documentation without specific,
|
||||||
|
written prior permission.
|
||||||
|
|
||||||
|
Intel Corporation provides this AS IS, WITHOUT ANY WARRANTY, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY
|
||||||
|
OR FITNESS FOR A PARTICULAR PURPOSE. Intel makes no guarantee or
|
||||||
|
representations regarding the use of, or the results of the use of,
|
||||||
|
the software and documentation in terms of correctness, accuracy,
|
||||||
|
reliability, currentness, or otherwise; and you rely on the software,
|
||||||
|
documentation and results solely at your own risk.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL INTEL BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
|
||||||
|
LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
|
||||||
|
OF ANY KIND. IN NO EVENT SHALL INTEL'S TOTAL LIABILITY EXCEED THE SUM
|
||||||
|
PAID TO INTEL FOR THE PRODUCT LICENSED HEREUNDER.
|
22
options/license/HPND-export-US-acknowledgement
Normal file
22
options/license/HPND-export-US-acknowledgement
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Copyright (C) 1994 by the University of Southern California
|
||||||
|
|
||||||
|
EXPORT OF THIS SOFTWARE from the United States of America may
|
||||||
|
require a specific license from the United States Government. It
|
||||||
|
is the responsibility of any person or organization
|
||||||
|
contemplating export to obtain such a license before exporting.
|
||||||
|
|
||||||
|
WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
|
||||||
|
this software and its documentation in source and binary forms is
|
||||||
|
hereby granted, provided that any documentation or other materials
|
||||||
|
related to such distribution or use acknowledge that the software
|
||||||
|
was developed by the University of Southern California.
|
||||||
|
|
||||||
|
DISCLAIMER OF WARRANTY. THIS SOFTWARE IS PROVIDED "AS IS". The
|
||||||
|
University of Southern California MAKES NO REPRESENTATIONS OR
|
||||||
|
WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not
|
||||||
|
limitation, the University of Southern California MAKES NO
|
||||||
|
REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
|
||||||
|
PARTICULAR PURPOSE. The University of Southern California shall not
|
||||||
|
be held liable for any liability nor for any direct, indirect, or
|
||||||
|
consequential damages with respect to any claim by the user or
|
||||||
|
distributor of the ksu software.
|
19
options/license/NCBI-PD
Normal file
19
options/license/NCBI-PD
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
PUBLIC DOMAIN NOTICE
|
||||||
|
National Center for Biotechnology Information
|
||||||
|
|
||||||
|
This software is a "United States Government Work" under the terms of the
|
||||||
|
United States Copyright Act. It was written as part of the authors'
|
||||||
|
official duties as United States Government employees and thus cannot
|
||||||
|
be copyrighted. This software is freely available to the public for
|
||||||
|
use. The National Library of Medicine and the U.S. Government have not
|
||||||
|
placed any restriction on its use or reproduction.
|
||||||
|
|
||||||
|
Although all reasonable efforts have been taken to ensure the accuracy
|
||||||
|
and reliability of the software and data, the NLM and the U.S.
|
||||||
|
Government do not and cannot warrant the performance or results that
|
||||||
|
may be obtained by using this software or data. The NLM and the U.S.
|
||||||
|
Government disclaim all warranties, express or implied, including
|
||||||
|
warranties of performance, merchantability or fitness for any
|
||||||
|
particular purpose.
|
||||||
|
|
||||||
|
Please cite the author in any work or product based on this material.
|
@ -3320,7 +3320,6 @@ mirror_sync_create=synchronizoval/a novou referenci <a href="%[2]s">%[3]s</a> do
|
|||||||
mirror_sync_delete=synchronizoval/a a smazal/a referenci <code>%[2]s</code> v <a href="%[1]s">%[3]s</a> ze zrcadla
|
mirror_sync_delete=synchronizoval/a a smazal/a referenci <code>%[2]s</code> v <a href="%[1]s">%[3]s</a> ze zrcadla
|
||||||
approve_pull_request=`schválil/a <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`schválil/a <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`navrhl/a změny pro <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`navrhl/a změny pro <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`vydal/a <a href="%[2]s"> "%[4]s" </a> v <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`zamítl/a posouzení z <b>%[4]s</b> pro <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`zamítl/a posouzení z <b>%[4]s</b> pro <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Důvod:
|
review_dismissed_reason=Důvod:
|
||||||
create_branch=vytvořil/a větev <a href="%[2]s">%[3]s</a> v <a href="%[1]s">%[4]s</a>
|
create_branch=vytvořil/a větev <a href="%[2]s">%[3]s</a> v <a href="%[1]s">%[4]s</a>
|
||||||
|
@ -3329,7 +3329,6 @@ mirror_sync_create=neue Referenz <a href="%[2]s">%[3]s</a> bei <a href="%[1]s">%
|
|||||||
mirror_sync_delete=hat die Referenz des Mirrors <code>%[2]s</code> in <a href="%[1]s">%[3]s</a> synchronisiert und gelöscht
|
mirror_sync_delete=hat die Referenz des Mirrors <code>%[2]s</code> in <a href="%[1]s">%[3]s</a> synchronisiert und gelöscht
|
||||||
approve_pull_request=`hat <a href="%[1]s">%[3]s#%[2]s</a> approved`
|
approve_pull_request=`hat <a href="%[1]s">%[3]s#%[2]s</a> approved`
|
||||||
reject_pull_request=`schlug Änderungen für <a href="%[1]s">%[3]s#%[2]s</a> vor`
|
reject_pull_request=`schlug Änderungen für <a href="%[1]s">%[3]s#%[2]s</a> vor`
|
||||||
publish_release=`veröffentlichte Release <a href="%[2]s"> "%[4]s" </a> in <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`verwarf das Review von <b>%[4]s</b> in <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`verwarf das Review von <b>%[4]s</b> in <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Grund:
|
review_dismissed_reason=Grund:
|
||||||
create_branch=legte den Branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> an
|
create_branch=legte den Branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> an
|
||||||
|
@ -3210,7 +3210,6 @@ mirror_sync_create=συγχρονίστηκε η νέα αναφορά <a href="
|
|||||||
mirror_sync_delete=συγχρόνισε και διάγραψε την αναφορά <code>%[2]s</code> σε <a href="%[1]s">%[3]s</a> από το είδωλο
|
mirror_sync_delete=συγχρόνισε και διάγραψε την αναφορά <code>%[2]s</code> σε <a href="%[1]s">%[3]s</a> από το είδωλο
|
||||||
approve_pull_request=`ενέκρινε το <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`ενέκρινε το <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`πρότεινε αλλαγές για το <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`πρότεινε αλλαγές για το <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`έκδωσε τη <a href="%[2]s"> "%[4]s" </a> στο <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`ακύρωσε την εξέταση από <b>%[4]s</b> for <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`ακύρωσε την εξέταση από <b>%[4]s</b> for <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Αιτία:
|
review_dismissed_reason=Αιτία:
|
||||||
create_branch=δημιούργησε το κλαδο <a href="%[2]s">%[3]s</a> στο <a href="%[1]s">%[4]s</a>
|
create_branch=δημιούργησε το κλαδο <a href="%[2]s">%[3]s</a> στο <a href="%[1]s">%[4]s</a>
|
||||||
|
@ -3348,7 +3348,7 @@ mirror_sync_create = synced new reference <a href="%[2]s">%[3]s</a> to <a href="
|
|||||||
mirror_sync_delete = synced and deleted reference <code>%[2]s</code> at <a href="%[1]s">%[3]s</a> from mirror
|
mirror_sync_delete = synced and deleted reference <code>%[2]s</code> at <a href="%[1]s">%[3]s</a> from mirror
|
||||||
approve_pull_request = `approved <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request = `approved <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request = `suggested changes for <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request = `suggested changes for <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release = `released <a href="%[2]s"> "%[4]s" </a> at <a href="%[1]s">%[3]s</a>`
|
publish_release = `released <a href="%[2]s">%[4]s</a> at <a href="%[1]s">%[3]s</a>`
|
||||||
review_dismissed = `dismissed review from <b>%[4]s</b> for <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed = `dismissed review from <b>%[4]s</b> for <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason = Reason:
|
review_dismissed_reason = Reason:
|
||||||
create_branch = created branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a>
|
create_branch = created branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a>
|
||||||
@ -3415,6 +3415,7 @@ error.unit_not_allowed = You are not allowed to access this repository section.
|
|||||||
title = Packages
|
title = Packages
|
||||||
desc = Manage repository packages.
|
desc = Manage repository packages.
|
||||||
empty = There are no packages yet.
|
empty = There are no packages yet.
|
||||||
|
no_metadata = No metadata.
|
||||||
empty.documentation = For more information on the package registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
|
empty.documentation = For more information on the package registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
|
||||||
empty.repo = Did you upload a package, but it's not shown here? Go to <a href="%[1]s">package settings</a> and link it to this repo.
|
empty.repo = Did you upload a package, but it's not shown here? Go to <a href="%[1]s">package settings</a> and link it to this repo.
|
||||||
registry.documentation = For more information on the %s registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
|
registry.documentation = For more information on the %s registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
|
||||||
|
@ -3193,7 +3193,6 @@ mirror_sync_create=sincronizó la nueva referencia <a href="%[2]s">%[3]s</a> a <
|
|||||||
mirror_sync_delete=sincronizada y eliminada referencia <code>%[2]s</code> en <a href="%[1]s">%[3]s</a> desde réplica
|
mirror_sync_delete=sincronizada y eliminada referencia <code>%[2]s</code> en <a href="%[1]s">%[3]s</a> desde réplica
|
||||||
approve_pull_request=`aprobó <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`aprobó <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`sugirió cambios para <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`sugirió cambios para <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`se lanzó <a href="%[2]s"> "%[4]s" </a> en <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`descartó la revisión de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`descartó la revisión de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Motivo:
|
review_dismissed_reason=Motivo:
|
||||||
create_branch=creó rama <a href="%[2]s">%[3]s</a> en <a href="%[1]s">%[4]s</a>
|
create_branch=creó rama <a href="%[2]s">%[3]s</a> en <a href="%[1]s">%[4]s</a>
|
||||||
|
@ -2508,7 +2508,6 @@ mirror_sync_create=مرجع جدید <a href="%[2]s">%[3]s</a> با <a href="%[1
|
|||||||
mirror_sync_delete=از مرجع <code>%[2]s</code> در<a href="%[1]s">%[3]s</a> حذف شده و از قرینه همگام شده
|
mirror_sync_delete=از مرجع <code>%[2]s</code> در<a href="%[1]s">%[3]s</a> حذف شده و از قرینه همگام شده
|
||||||
approve_pull_request=`تأیید <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`تأیید <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`تغییرات پیشنهادی برای <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`تغییرات پیشنهادی برای <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`<a href="%[2]s"> "%[4]s" </a> در <a href="%[1]s">%[3]s</a> منتشر شد`
|
|
||||||
review_dismissed=`بازبینی از <b>%[4]s</b> برای <a href="%[1]s">%[3]s#%[2]s</a> رد شد`
|
review_dismissed=`بازبینی از <b>%[4]s</b> برای <a href="%[1]s">%[3]s#%[2]s</a> رد شد`
|
||||||
review_dismissed_reason=دلیل:
|
review_dismissed_reason=دلیل:
|
||||||
create_branch=شاخه <a href="%[2]s">%[3]s</a> در <a href="%[1]s">%[4]s</a> ایجاد کرد
|
create_branch=شاخه <a href="%[2]s">%[3]s</a> در <a href="%[1]s">%[4]s</a> ایجاد کرد
|
||||||
|
@ -3249,7 +3249,6 @@ mirror_sync_create=a synchronisé la nouvelle référence <a href="%[2]s">%[3]s<
|
|||||||
mirror_sync_delete=a synchronisé puis supprimé la nouvelle référence <code>%[2]s</code> vers <a href="%[1]s">%[3]s</a> depuis le miroir
|
mirror_sync_delete=a synchronisé puis supprimé la nouvelle référence <code>%[2]s</code> vers <a href="%[1]s">%[3]s</a> depuis le miroir
|
||||||
approve_pull_request=`a approuvé <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`a approuvé <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`a suggérés des changements pour <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`a suggérés des changements pour <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`a publié <a href="%[2]s"> "%[4]s" </a> dans <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`a révoqué l’évaluation de <b>%[4]s</b> dans <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`a révoqué l’évaluation de <b>%[4]s</b> dans <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Raison :
|
review_dismissed_reason=Raison :
|
||||||
create_branch=a créé la branche <a href="%[2]s">%[3]s</a> dans <a href="%[1]s">%[4]s</a>
|
create_branch=a créé la branche <a href="%[2]s">%[3]s</a> dans <a href="%[1]s">%[4]s</a>
|
||||||
|
@ -2707,7 +2707,6 @@ mirror_sync_create=ha sincronizzato un nuovo riferimento <a href="%[2]s">%[3]s</
|
|||||||
mirror_sync_delete=riferimento sincronizzato ed eliminato <code>%[2]s</code> a <a href="%[1]s">%[3]s</a> dal mirror
|
mirror_sync_delete=riferimento sincronizzato ed eliminato <code>%[2]s</code> a <a href="%[1]s">%[3]s</a> dal mirror
|
||||||
approve_pull_request=`ha approvato <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`ha approvato <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`ha suggerito modifiche per <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`ha suggerito modifiche per <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`ha rilasciato <a href="%[2]s"> "%[4]s" </a> su <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`respinta la recensione da <b>%[4]s</b> per <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`respinta la recensione da <b>%[4]s</b> per <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Motivo:
|
review_dismissed_reason=Motivo:
|
||||||
create_branch=ha creato il ramo <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a>
|
create_branch=ha creato il ramo <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a>
|
||||||
|
@ -164,6 +164,8 @@ search=検索…
|
|||||||
type_tooltip=検索タイプ
|
type_tooltip=検索タイプ
|
||||||
fuzzy=あいまい
|
fuzzy=あいまい
|
||||||
fuzzy_tooltip=検索語におおよそ一致する結果も含めます
|
fuzzy_tooltip=検索語におおよそ一致する結果も含めます
|
||||||
|
exact=完全一致
|
||||||
|
exact_tooltip=検索語と完全に一致する結果だけを含めます
|
||||||
repo_kind=リポジトリを検索...
|
repo_kind=リポジトリを検索...
|
||||||
user_kind=ユーザーを検索...
|
user_kind=ユーザーを検索...
|
||||||
org_kind=組織を検索...
|
org_kind=組織を検索...
|
||||||
@ -177,6 +179,8 @@ branch_kind=ブランチを検索...
|
|||||||
commit_kind=コミットを検索...
|
commit_kind=コミットを検索...
|
||||||
runner_kind=ランナーを検索...
|
runner_kind=ランナーを検索...
|
||||||
no_results=一致する結果が見つかりませんでした
|
no_results=一致する結果が見つかりませんでした
|
||||||
|
issue_kind=イシューを検索...
|
||||||
|
pull_kind=プルリクエストを検索...
|
||||||
keyword_search_unavailable=キーワード検索は現在利用できません。 サイト管理者にお問い合わせください。
|
keyword_search_unavailable=キーワード検索は現在利用できません。 サイト管理者にお問い合わせください。
|
||||||
|
|
||||||
[aria]
|
[aria]
|
||||||
@ -432,6 +436,7 @@ oauth_signin_submit=アカウントにリンク
|
|||||||
oauth.signin.error=認可リクエストの処理中にエラーが発生しました。このエラーが解決しない場合は、サイト管理者に問い合わせてください。
|
oauth.signin.error=認可リクエストの処理中にエラーが発生しました。このエラーが解決しない場合は、サイト管理者に問い合わせてください。
|
||||||
oauth.signin.error.access_denied=認可リクエストが拒否されました。
|
oauth.signin.error.access_denied=認可リクエストが拒否されました。
|
||||||
oauth.signin.error.temporarily_unavailable=認証サーバーが一時的に利用できないため、認可に失敗しました。後でもう一度やり直してください。
|
oauth.signin.error.temporarily_unavailable=認証サーバーが一時的に利用できないため、認可に失敗しました。後でもう一度やり直してください。
|
||||||
|
oauth_callback_unable_auto_reg=自動登録が有効になっていますが、OAuth2プロバイダー %[1]s の応答はフィールド %[2]s が不足しており、自動でアカウントを作成することができません。 アカウントを作成またはリンクするか、サイト管理者に問い合わせてください。
|
||||||
openid_connect_submit=接続
|
openid_connect_submit=接続
|
||||||
openid_connect_title=既存のアカウントに接続
|
openid_connect_title=既存のアカウントに接続
|
||||||
openid_connect_desc=選択したOpenID URIは未登録です。 ここで新しいアカウントと関連付けます。
|
openid_connect_desc=選択したOpenID URIは未登録です。 ここで新しいアカウントと関連付けます。
|
||||||
@ -759,6 +764,8 @@ manage_themes=デフォルトのテーマを選択
|
|||||||
manage_openid=OpenIDアドレスの管理
|
manage_openid=OpenIDアドレスの管理
|
||||||
email_desc=プライマリメールアドレスは、通知、パスワードの回復、さらにメールアドレスを隠さない場合は、WebベースのGit操作にも使用されます。
|
email_desc=プライマリメールアドレスは、通知、パスワードの回復、さらにメールアドレスを隠さない場合は、WebベースのGit操作にも使用されます。
|
||||||
theme_desc=この設定がサイト全体のデフォルトのテーマとなります。
|
theme_desc=この設定がサイト全体のデフォルトのテーマとなります。
|
||||||
|
theme_colorblindness_help=色覚障害テーマのサポート
|
||||||
|
theme_colorblindness_prompt=Giteaには基本的な色覚障害サポートを含むテーマがいくつか入っていますが、それらは色定義が少ししかありません。 作業はまだ進行中です。 テーマCSSファイルにもっと多くの色を定義していくことで、さらに改善できる余地があります。
|
||||||
primary=プライマリー
|
primary=プライマリー
|
||||||
activated=アクティベート済み
|
activated=アクティベート済み
|
||||||
requires_activation=アクティベーションが必要
|
requires_activation=アクティベーションが必要
|
||||||
@ -883,6 +890,7 @@ repo_and_org_access=リポジトリと組織へのアクセス
|
|||||||
permissions_public_only=公開のみ
|
permissions_public_only=公開のみ
|
||||||
permissions_access_all=すべて (公開、プライベート、限定)
|
permissions_access_all=すべて (公開、プライベート、限定)
|
||||||
select_permissions=許可の選択
|
select_permissions=許可の選択
|
||||||
|
permission_not_set=設定なし
|
||||||
permission_no_access=アクセス不可
|
permission_no_access=アクセス不可
|
||||||
permission_read=読み取り
|
permission_read=読み取り
|
||||||
permission_write=読み取りと書き込み
|
permission_write=読み取りと書き込み
|
||||||
@ -2093,6 +2101,7 @@ settings.advanced_settings=拡張設定
|
|||||||
settings.wiki_desc=Wikiを有効にする
|
settings.wiki_desc=Wikiを有効にする
|
||||||
settings.use_internal_wiki=ビルトインのWikiを使用する
|
settings.use_internal_wiki=ビルトインのWikiを使用する
|
||||||
settings.default_wiki_branch_name=デフォルトのWikiブランチ名
|
settings.default_wiki_branch_name=デフォルトのWikiブランチ名
|
||||||
|
settings.default_wiki_everyone_access=サインインユーザーのデフォルトのアクセス権限:
|
||||||
settings.failed_to_change_default_wiki_branch=デフォルトのWikiブランチを変更できませんでした。
|
settings.failed_to_change_default_wiki_branch=デフォルトのWikiブランチを変更できませんでした。
|
||||||
settings.use_external_wiki=外部のWikiを使用する
|
settings.use_external_wiki=外部のWikiを使用する
|
||||||
settings.external_wiki_url=外部WikiのURL
|
settings.external_wiki_url=外部WikiのURL
|
||||||
@ -3311,6 +3320,7 @@ self_check.database_collation_case_insensitive=データベースは照合順序
|
|||||||
self_check.database_inconsistent_collation_columns=データベースは照合順序 %s を使用していますが、以下のカラムはそれと一致しない照合順序を使用しており、予期せぬ問題を引き起こす可能性があります。
|
self_check.database_inconsistent_collation_columns=データベースは照合順序 %s を使用していますが、以下のカラムはそれと一致しない照合順序を使用しており、予期せぬ問題を引き起こす可能性があります。
|
||||||
self_check.database_fix_mysql=MySQL/MariaDBユーザーの方は、"gitea doctor convert" コマンドを使用することで、照合順序の問題を修正できます。 また、"ALTER ... COLLATE ..." のSQLを手で実行しても修正することができます。
|
self_check.database_fix_mysql=MySQL/MariaDBユーザーの方は、"gitea doctor convert" コマンドを使用することで、照合順序の問題を修正できます。 また、"ALTER ... COLLATE ..." のSQLを手で実行しても修正することができます。
|
||||||
self_check.database_fix_mssql=MSSQLユーザーの方は、問題を修正するには今のところ "ALTER ... COLLATE ..." のSQLを手で実行するしかありません。
|
self_check.database_fix_mssql=MSSQLユーザーの方は、問題を修正するには今のところ "ALTER ... COLLATE ..." のSQLを手で実行するしかありません。
|
||||||
|
self_check.location_origin_mismatch=現在のURL (%[1]s) は、Giteaが見ているURL (%[2]s) に一致していません。 リバースプロキシを使用している場合は、"Host" ヘッダーと "X-Forwarded-Proto" ヘッダーが正しく設定されていることを確認してください。
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
create_repo=がリポジトリ <a href="%s">%s</a> を作成しました
|
create_repo=がリポジトリ <a href="%s">%s</a> を作成しました
|
||||||
@ -3338,7 +3348,7 @@ mirror_sync_create=が <a href="%[1]s">%[4]s</a> の新しい参照 <a href="%[2
|
|||||||
mirror_sync_delete=が <a href="%[1]s">%[3]s</a> の参照 <code>%[2]s</code> をミラーから反映し、削除しました
|
mirror_sync_delete=が <a href="%[1]s">%[3]s</a> の参照 <code>%[2]s</code> をミラーから反映し、削除しました
|
||||||
approve_pull_request=`が <a href="%[1]s">%[3]s#%[2]s</a> を承認しました`
|
approve_pull_request=`が <a href="%[1]s">%[3]s#%[2]s</a> を承認しました`
|
||||||
reject_pull_request=`が <a href="%[1]s">%[3]s#%[2]s</a>について変更を提案しました`
|
reject_pull_request=`が <a href="%[1]s">%[3]s#%[2]s</a>について変更を提案しました`
|
||||||
publish_release=`が <a href="%[1]s">%[3]s</a> の <a href="%[2]s"> "%[4]s" </a> をリリースしました`
|
publish_release=`が <a href="%[1]s">%[3]s</a> の <a href="%[2]s">%[4]s</a> をリリースしました`
|
||||||
review_dismissed=`が <b>%[4]s</b> の <a href="%[1]s">%[3]s#%[2]s</a> へのレビューを棄却しました`
|
review_dismissed=`が <b>%[4]s</b> の <a href="%[1]s">%[3]s#%[2]s</a> へのレビューを棄却しました`
|
||||||
review_dismissed_reason=理由:
|
review_dismissed_reason=理由:
|
||||||
create_branch=がブランチ <a href="%[2]s">%[3]s</a> を <a href="%[1]s">%[4]s</a> に作成しました
|
create_branch=がブランチ <a href="%[2]s">%[3]s</a> を <a href="%[1]s">%[4]s</a> に作成しました
|
||||||
@ -3486,6 +3496,7 @@ npm.install=npm を使用してパッケージをインストールするには
|
|||||||
npm.install2=または package.json ファイルに追加します:
|
npm.install2=または package.json ファイルに追加します:
|
||||||
npm.dependencies=依存関係
|
npm.dependencies=依存関係
|
||||||
npm.dependencies.development=開発用依存関係
|
npm.dependencies.development=開発用依存関係
|
||||||
|
npm.dependencies.bundle=バンドルされた依存関係
|
||||||
npm.dependencies.peer=Peer依存関係
|
npm.dependencies.peer=Peer依存関係
|
||||||
npm.dependencies.optional=オプションの依存関係
|
npm.dependencies.optional=オプションの依存関係
|
||||||
npm.details.tag=タグ
|
npm.details.tag=タグ
|
||||||
|
@ -111,7 +111,7 @@ preview=Priekšskatītījums
|
|||||||
loading=Notiek ielāde…
|
loading=Notiek ielāde…
|
||||||
|
|
||||||
error=Kļūda
|
error=Kļūda
|
||||||
error404=Lapa, ko vēlaties atvērt, <strong>neeksistē</strong> vai arī <strong>Jums nav tiesības</strong> to aplūkot.
|
error404=Lapa, ko tiek mēģināts atvērt, vai nu <strong>nepastāv</strong> vai arī <strong>nav tiesību</strong> to aplūkot.
|
||||||
go_back=Atgriezties
|
go_back=Atgriezties
|
||||||
|
|
||||||
never=Nekad
|
never=Nekad
|
||||||
@ -133,10 +133,10 @@ concept_user_organization=Organizācija
|
|||||||
|
|
||||||
show_timestamps=Rādīt laika zīmogus
|
show_timestamps=Rādīt laika zīmogus
|
||||||
show_log_seconds=Rādīt sekundes
|
show_log_seconds=Rādīt sekundes
|
||||||
show_full_screen=Atvērt pilnā logā
|
show_full_screen=Rādīt pilnekrānā
|
||||||
download_logs=Lejupielādēt žurnālus
|
download_logs=Lejupielādēt žurnālus
|
||||||
|
|
||||||
confirm_delete_selected=Apstiprināt, lai izdzēstu visus atlasītos vienumus?
|
confirm_delete_selected=Apstiprināt visu atlasīto vienumus dzēšanu?
|
||||||
|
|
||||||
name=Nosaukums
|
name=Nosaukums
|
||||||
value=Vērtība
|
value=Vērtība
|
||||||
@ -651,10 +651,11 @@ cancel=Atcelt
|
|||||||
language=Valoda
|
language=Valoda
|
||||||
ui=Motīvs
|
ui=Motīvs
|
||||||
hidden_comment_types=Attēlojot paslēpt šauds komentārus:
|
hidden_comment_types=Attēlojot paslēpt šauds komentārus:
|
||||||
|
hidden_comment_types_description=Komentāru veidi, kas atzīmēti, netiks rādīti problēmu lapā. Piemēram, atzīmējot "Iezīmes" netiks rādīti komentāri "{lietotājs} pievienoja/noņēma {iezīme} iezīmi".
|
||||||
hidden_comment_types.ref_tooltip=Komentāri, kad problēmai tiek pievienota atsauce uz citu probēmu, komentāru, …
|
hidden_comment_types.ref_tooltip=Komentāri, kad problēmai tiek pievienota atsauce uz citu probēmu, komentāru, …
|
||||||
hidden_comment_types.issue_ref_tooltip=Komentāri par lietotāja izmaiņām ar problēmas saistīto atzaru/tagu
|
hidden_comment_types.issue_ref_tooltip=Komentāri par lietotāja izmaiņām ar problēmas saistīto atzaru/tagu
|
||||||
comment_type_group_reference=Atsauces
|
comment_type_group_reference=Atsauces
|
||||||
comment_type_group_label=Etiķetes
|
comment_type_group_label=Iezīmes
|
||||||
comment_type_group_milestone=Atskaites punktus
|
comment_type_group_milestone=Atskaites punktus
|
||||||
comment_type_group_assignee=Atbildīgos
|
comment_type_group_assignee=Atbildīgos
|
||||||
comment_type_group_title=Nosaukuma izmaiņas
|
comment_type_group_title=Nosaukuma izmaiņas
|
||||||
@ -956,8 +957,8 @@ repo_desc_helper=Ievadiet īsu aprakstu (neobligāts)
|
|||||||
repo_lang=Valoda
|
repo_lang=Valoda
|
||||||
repo_gitignore_helper=Izvēlieties .gitignore sagatavi.
|
repo_gitignore_helper=Izvēlieties .gitignore sagatavi.
|
||||||
repo_gitignore_helper_desc=Izvēlieties kādi faili netiks glabāti repozitorijā no sagatavēm biežāk lietotājām valodām. Pēc noklusējuma .gitignore iekļauj valodu kompilācijas rīku artifaktus.
|
repo_gitignore_helper_desc=Izvēlieties kādi faili netiks glabāti repozitorijā no sagatavēm biežāk lietotājām valodām. Pēc noklusējuma .gitignore iekļauj valodu kompilācijas rīku artifaktus.
|
||||||
issue_labels=Problēmu etiķetes
|
issue_labels=Problēmu iezīmes
|
||||||
issue_labels_helper=Izvēlieties problēmu etiķešu kopu.
|
issue_labels_helper=Izvēlieties problēmu iezīmju kopu.
|
||||||
license=Licence
|
license=Licence
|
||||||
license_helper=Izvēlieties licences failu.
|
license_helper=Izvēlieties licences failu.
|
||||||
license_helper_desc=Licence nosaka, ko citi var un ko nevar darīt ar šo kodu. Neesat pārliecintāts, kādu izvēlēties šim projektam? Aplūkojiet <a target="_blank" rel="noopener noreferrer" href="%s">licences izvēle</a>.
|
license_helper_desc=Licence nosaka, ko citi var un ko nevar darīt ar šo kodu. Neesat pārliecintāts, kādu izvēlēties šim projektam? Aplūkojiet <a target="_blank" rel="noopener noreferrer" href="%s">licences izvēle</a>.
|
||||||
@ -1030,15 +1031,15 @@ desc.internal=Iekšējs
|
|||||||
desc.archived=Arhivēts
|
desc.archived=Arhivēts
|
||||||
desc.sha256=SHA256
|
desc.sha256=SHA256
|
||||||
|
|
||||||
template.items=Sagataves ieraksti
|
template.items=Sagataves vienumi
|
||||||
template.git_content=Git saturs (noklusētais atzars)
|
template.git_content=Git saturs (noklusētais atzars)
|
||||||
template.git_hooks=Git āķi
|
template.git_hooks=Git āķi
|
||||||
template.git_hooks_tooltip=Pēc repozitorija izveidošanas, Jums nav tiesību mainīt Git āķus. Atzīmējiet šo tikai, ja uzticaties sagataves repozitorija saturam.
|
template.git_hooks_tooltip=Pēc repozitorija izveidošanas, Jums nav tiesību mainīt Git āķus. Atzīmējiet šo tikai, ja uzticaties sagataves repozitorija saturam.
|
||||||
template.webhooks=Tīmekļa āķi
|
template.webhooks=Tīmekļa āķi
|
||||||
template.topics=Tēmas
|
template.topics=Tēmas
|
||||||
template.avatar=Profila attēls
|
template.avatar=Profila attēls
|
||||||
template.issue_labels=Problēmu etiķetes
|
template.issue_labels=Problēmu iezīmes
|
||||||
template.one_item=Norādiet vismaz vienu sagataves vienību
|
template.one_item=Norādiet vismaz vienu sagataves vienumu
|
||||||
template.invalid=Norādiet sagataves repozitoriju
|
template.invalid=Norādiet sagataves repozitoriju
|
||||||
|
|
||||||
archive.title=Šis repozitorijs ir arhivēts. Ir iespējams aplūkot tā failus un to konēt, bet nav iespējams iesūtīt izmaiņas, kā arī izveidot jaunas problēmas vai izmaiņu pieprasījumus.
|
archive.title=Šis repozitorijs ir arhivēts. Ir iespējams aplūkot tā failus un to konēt, bet nav iespējams iesūtīt izmaiņas, kā arī izveidot jaunas problēmas vai izmaiņu pieprasījumus.
|
||||||
@ -1060,10 +1061,10 @@ migrate_options_lfs_endpoint.label=LFS galapunkts
|
|||||||
migrate_options_lfs_endpoint.description=Migrācija mēģinās izmantot attālināto URL, lai <a target="_blank" rel="noopener noreferrer" href="%s">noteiktu LFS serveri</a>. Var norādīt arī citu galapunktu, ja repozitorija LFS dati ir izvietoti citā vietā.
|
migrate_options_lfs_endpoint.description=Migrācija mēģinās izmantot attālināto URL, lai <a target="_blank" rel="noopener noreferrer" href="%s">noteiktu LFS serveri</a>. Var norādīt arī citu galapunktu, ja repozitorija LFS dati ir izvietoti citā vietā.
|
||||||
migrate_options_lfs_endpoint.description.local=Iespējams norādīt arī servera ceļu.
|
migrate_options_lfs_endpoint.description.local=Iespējams norādīt arī servera ceļu.
|
||||||
migrate_options_lfs_endpoint.placeholder=Ja nav norādīts, galamērķis tiks atvasināts no klonēšanas URL
|
migrate_options_lfs_endpoint.placeholder=Ja nav norādīts, galamērķis tiks atvasināts no klonēšanas URL
|
||||||
migrate_items=Vienības, ko pārņemt
|
migrate_items=Vienumi, ko pārņemt
|
||||||
migrate_items_wiki=Vikivietni
|
migrate_items_wiki=Vikivietni
|
||||||
migrate_items_milestones=Atskaites punktus
|
migrate_items_milestones=Atskaites punktus
|
||||||
migrate_items_labels=Etiķetes
|
migrate_items_labels=Iezīmes
|
||||||
migrate_items_issues=Problēmas
|
migrate_items_issues=Problēmas
|
||||||
migrate_items_pullrequests=Izmaiņu pieprasījumus
|
migrate_items_pullrequests=Izmaiņu pieprasījumus
|
||||||
migrate_items_merge_requests=Sapludināšanas pieprasījumi
|
migrate_items_merge_requests=Sapludināšanas pieprasījumi
|
||||||
@ -1078,7 +1079,7 @@ migrate.permission_denied_blocked=Nav iespējams importēt no neatļautām adres
|
|||||||
migrate.invalid_local_path=Nederīgs lokālais ceļš. Tas neeksistē vai nav direktorija.
|
migrate.invalid_local_path=Nederīgs lokālais ceļš. Tas neeksistē vai nav direktorija.
|
||||||
migrate.invalid_lfs_endpoint=LFS galapunkts nav korekts.
|
migrate.invalid_lfs_endpoint=LFS galapunkts nav korekts.
|
||||||
migrate.failed=Migrācija neizdevās: %v
|
migrate.failed=Migrācija neizdevās: %v
|
||||||
migrate.migrate_items_options=Piekļuves pilnvara ir nepieciešams, lai migrētu papildus datus
|
migrate.migrate_items_options=Piekļuves pilnvara ir nepieciešama, lai pārņemtu papildus datus
|
||||||
migrated_from=Migrēts no <a href="%[1]s">%[2]s</a>
|
migrated_from=Migrēts no <a href="%[1]s">%[2]s</a>
|
||||||
migrated_from_fake=Migrēts no %[1]s
|
migrated_from_fake=Migrēts no %[1]s
|
||||||
migrate.migrate=Migrēt no %s
|
migrate.migrate=Migrēt no %s
|
||||||
@ -1097,7 +1098,7 @@ migrate.gitbucket.description=Migrēt datus no GitBucket instancēm.
|
|||||||
migrate.migrating_git=Migrē git datus
|
migrate.migrating_git=Migrē git datus
|
||||||
migrate.migrating_topics=Migrē tēmas
|
migrate.migrating_topics=Migrē tēmas
|
||||||
migrate.migrating_milestones=Migrē atskaites punktus
|
migrate.migrating_milestones=Migrē atskaites punktus
|
||||||
migrate.migrating_labels=Migrē etiķetes
|
migrate.migrating_labels=Migrē iezīmes
|
||||||
migrate.migrating_releases=Migrē laidienus
|
migrate.migrating_releases=Migrē laidienus
|
||||||
migrate.migrating_issues=Migrācijas problēmas
|
migrate.migrating_issues=Migrācijas problēmas
|
||||||
migrate.migrating_pulls=Migrē izmaiņu pieprasījumus
|
migrate.migrating_pulls=Migrē izmaiņu pieprasījumus
|
||||||
@ -1141,8 +1142,8 @@ pulls=Izmaiņu pieprasījumi
|
|||||||
project_board=Projekti
|
project_board=Projekti
|
||||||
packages=Pakotnes
|
packages=Pakotnes
|
||||||
actions=Darbības
|
actions=Darbības
|
||||||
labels=Etiķetes
|
labels=Iezīmes
|
||||||
org_labels_desc=Organizācijas līmeņa etiķetes var tikt izmantotas <strong>visiem repozitorijiem</strong> šajā organizācijā
|
org_labels_desc=Organizācijas līmeņa iezīmes var tikt izmantotas <strong>visiem repozitorijiem</strong> šajā organizācijā
|
||||||
org_labels_desc_manage=pārvaldīt
|
org_labels_desc_manage=pārvaldīt
|
||||||
|
|
||||||
milestones=Atskaites punkti
|
milestones=Atskaites punkti
|
||||||
@ -1334,19 +1335,19 @@ issues.desc=Organizēt kļūdu ziņojumus, uzdevumus un atskaites punktus.
|
|||||||
issues.filter_assignees=Filtrēt pēc atbildīgajiem
|
issues.filter_assignees=Filtrēt pēc atbildīgajiem
|
||||||
issues.filter_milestones=Filtrēt pēc atskaites punkta
|
issues.filter_milestones=Filtrēt pēc atskaites punkta
|
||||||
issues.filter_projects=Filtrēt pēc projekta
|
issues.filter_projects=Filtrēt pēc projekta
|
||||||
issues.filter_labels=Filtrēt pēc etiķetēm
|
issues.filter_labels=Filtrēt pēc iezīmēm
|
||||||
issues.filter_reviewers=Filtrēt pēc recenzentiem
|
issues.filter_reviewers=Filtrēt pēc recenzentiem
|
||||||
issues.new=Jauna problēma
|
issues.new=Jauna problēma
|
||||||
issues.new.title_empty=Nosaukums nevar būt tukšs
|
issues.new.title_empty=Nosaukums nevar būt tukšs
|
||||||
issues.new.labels=Etiķetes
|
issues.new.labels=Iezīmes
|
||||||
issues.new.no_label=Nav etiķešu
|
issues.new.no_label=Nav iezīmju
|
||||||
issues.new.clear_labels=Noņemt etiķetes
|
issues.new.clear_labels=Noņemt iezīmes
|
||||||
issues.new.projects=Projekti
|
issues.new.projects=Projekti
|
||||||
issues.new.clear_projects=Notīrīt projektus
|
issues.new.clear_projects=Notīrīt projektus
|
||||||
issues.new.no_projects=Nav projektu
|
issues.new.no_projects=Nav projektu
|
||||||
issues.new.open_projects=Aktīvie projekti
|
issues.new.open_projects=Aktīvie projekti
|
||||||
issues.new.closed_projects=Pabeigtie projekti
|
issues.new.closed_projects=Pabeigtie projekti
|
||||||
issues.new.no_items=Nav neviena ieraksta
|
issues.new.no_items=Nav vienumu
|
||||||
issues.new.milestone=Atskaites punkts
|
issues.new.milestone=Atskaites punkts
|
||||||
issues.new.no_milestone=Nav atskaites punktu
|
issues.new.no_milestone=Nav atskaites punktu
|
||||||
issues.new.clear_milestone=Notīrīt atskaites punktus
|
issues.new.clear_milestone=Notīrīt atskaites punktus
|
||||||
@ -1365,20 +1366,20 @@ issues.choose.invalid_templates=%v ķļūdaina sagatave(s) atrastas
|
|||||||
issues.choose.invalid_config=Problēmu konfigurācija satur kļūdas:
|
issues.choose.invalid_config=Problēmu konfigurācija satur kļūdas:
|
||||||
issues.no_ref=Nav norādīts atzars/tags
|
issues.no_ref=Nav norādīts atzars/tags
|
||||||
issues.create=Pieteikt problēmu
|
issues.create=Pieteikt problēmu
|
||||||
issues.new_label=Jauna etiķete
|
issues.new_label=Jauna iezīme
|
||||||
issues.new_label_placeholder=Etiķetes nosaukums
|
issues.new_label_placeholder=Iezīmes nosaukums
|
||||||
issues.new_label_desc_placeholder=Apraksts
|
issues.new_label_desc_placeholder=Apraksts
|
||||||
issues.create_label=Izveidot etiķeti
|
issues.create_label=Izveidot iezīmi
|
||||||
issues.label_templates.title=Ielādēt sākotnēji noteiktu etiķešu kopu
|
issues.label_templates.title=Ielādēt sākotnēji noteiktu iezīmju kopu
|
||||||
issues.label_templates.info=Nav izveidota neviena etiķete. Jūs varat noklikšķināt uz "Jauna etiķete" augstāk, lai to izveidotu vai izmantot zemāk piedāvātās etiķetes:
|
issues.label_templates.info=Nav izveidota neviena iezīme. Nospiediet uz pogas "Jauna iezīme", lai to izveidotu vai izmantojiet zemāk piedāvātās iezīmju kopas:
|
||||||
issues.label_templates.helper=Izvēlieties etiķešu kopu
|
issues.label_templates.helper=Izvēlieties iezīmju kopu
|
||||||
issues.label_templates.use=Izmantot etiķešu kopu
|
issues.label_templates.use=Izmantot iezīmju kopu
|
||||||
issues.label_templates.fail_to_load_file=Neizdevās ielādēt etiķetes sagataves failu "%s": %v
|
issues.label_templates.fail_to_load_file=Neizdevās ielādēt iezīmju sagataves failu "%s": %v
|
||||||
issues.add_label=pievienoja %s etiķeti %s
|
issues.add_label=pievienoja %s iezīmi %s
|
||||||
issues.add_labels=pievienoja %s etiķetes %s
|
issues.add_labels=pievienoja %s iezīmes %s
|
||||||
issues.remove_label=noņēma %s etiķeti %s
|
issues.remove_label=noņēma %s iezīmi %s
|
||||||
issues.remove_labels=noņēma %s etiķetes %s
|
issues.remove_labels=noņēma %s iezīmes %s
|
||||||
issues.add_remove_labels=pievienoja %s un noņēma %s etiķetes %s
|
issues.add_remove_labels=pievienoja %s un noņēma %s iezīmes %s
|
||||||
issues.add_milestone_at=`pievienoja atskaites punktu <b>%s</b> %s`
|
issues.add_milestone_at=`pievienoja atskaites punktu <b>%s</b> %s`
|
||||||
issues.add_project_at=`pievienoja šo problēmu <b>%s</b> projektam %s`
|
issues.add_project_at=`pievienoja šo problēmu <b>%s</b> projektam %s`
|
||||||
issues.change_milestone_at=`nomainīja atskaites punktu no <b>%s</b> uz <b>%s</b> %s`
|
issues.change_milestone_at=`nomainīja atskaites punktu no <b>%s</b> uz <b>%s</b> %s`
|
||||||
@ -1396,9 +1397,9 @@ issues.change_ref_at=`nomainīta atsauce no <b><strike>%s</strike></b> uz <b>%s<
|
|||||||
issues.remove_ref_at=`noņēma atsauci no <b>%s</b> %s`
|
issues.remove_ref_at=`noņēma atsauci no <b>%s</b> %s`
|
||||||
issues.add_ref_at=`pievienoja atsauci uz <b>%s</b> %s`
|
issues.add_ref_at=`pievienoja atsauci uz <b>%s</b> %s`
|
||||||
issues.delete_branch_at=`izdzēsa atzaru <b>%s</b> %s`
|
issues.delete_branch_at=`izdzēsa atzaru <b>%s</b> %s`
|
||||||
issues.filter_label=Etiķete
|
issues.filter_label=Iezīme
|
||||||
issues.filter_label_exclude=`Izmantojiet <code>alt</code> + <code>peles klikšķis vai enter</code>, lai neiekļautu etiķeti`
|
issues.filter_label_exclude=`Izmantojiet <code>alt</code> + <code>peles klikšķis vai enter</code>, lai neiekļautu iezīmes`
|
||||||
issues.filter_label_no_select=Visas etiķetes
|
issues.filter_label_no_select=Visas iezīmes
|
||||||
issues.filter_label_select_no_label=Nav etiķetes
|
issues.filter_label_select_no_label=Nav etiķetes
|
||||||
issues.filter_milestone=Atskaites punkts
|
issues.filter_milestone=Atskaites punkts
|
||||||
issues.filter_milestone_all=Visi atskaites punkti
|
issues.filter_milestone_all=Visi atskaites punkti
|
||||||
@ -1435,13 +1436,13 @@ issues.filter_sort.mostforks=Visvairāk atdalītie
|
|||||||
issues.filter_sort.fewestforks=Vismazāk atdalītie
|
issues.filter_sort.fewestforks=Vismazāk atdalītie
|
||||||
issues.action_open=Atvērt
|
issues.action_open=Atvērt
|
||||||
issues.action_close=Aizvērt
|
issues.action_close=Aizvērt
|
||||||
issues.action_label=Etiķete
|
issues.action_label=Iezīme
|
||||||
issues.action_milestone=Atskaites punkts
|
issues.action_milestone=Atskaites punkts
|
||||||
issues.action_milestone_no_select=Nav atskaites punkta
|
issues.action_milestone_no_select=Nav atskaites punkta
|
||||||
issues.action_assignee=Atbildīgais
|
issues.action_assignee=Atbildīgais
|
||||||
issues.action_assignee_no_select=Nav atbildīgā
|
issues.action_assignee_no_select=Nav atbildīgā
|
||||||
issues.action_check=Atzīmēt/Notīrīt
|
issues.action_check=Atzīmēt/Notīrīt
|
||||||
issues.action_check_all=Atzīmēt/Notīrīt visus ierakstus
|
issues.action_check_all=Atzīmēt/notīrīt visus vienumus
|
||||||
issues.opened_by=<a href="%[2]s">%[3]s</a> atvēra %[1]s
|
issues.opened_by=<a href="%[2]s">%[3]s</a> atvēra %[1]s
|
||||||
pulls.merged_by=<a href="%[2]s">%[3]s</a> sapludināja %[1]s
|
pulls.merged_by=<a href="%[2]s">%[3]s</a> sapludināja %[1]s
|
||||||
pulls.merged_by_fake=%[2]s sapludināja %[1]s
|
pulls.merged_by_fake=%[2]s sapludināja %[1]s
|
||||||
@ -1502,23 +1503,23 @@ issues.sign_in_require_desc=Nepieciešams <a href="%s">pieteikties</a>, lai piev
|
|||||||
issues.edit=Labot
|
issues.edit=Labot
|
||||||
issues.cancel=Atcelt
|
issues.cancel=Atcelt
|
||||||
issues.save=Saglabāt
|
issues.save=Saglabāt
|
||||||
issues.label_title=Etiķetes nosaukums
|
issues.label_title=Nosaukums
|
||||||
issues.label_description=Etiķetes apraksts
|
issues.label_description=Apraksts
|
||||||
issues.label_color=Etiķetes krāsa
|
issues.label_color=Krāsa
|
||||||
issues.label_exclusive=Ekskluzīvs
|
issues.label_exclusive=Sevišķa
|
||||||
issues.label_archive=Arhīvēt etiķeti
|
issues.label_archive=Arhīvēt etiķeti
|
||||||
issues.label_archived_filter=Rādīt arhivētās etiķetes
|
issues.label_archived_filter=Rādīt arhivētās etiķetes
|
||||||
issues.label_archive_tooltip=Arhivētās etiķetes pēc noklusējuma netiek iekļautas ieteikumos, kad meklē pēc nosaukuma.
|
issues.label_archive_tooltip=Arhivētās etiķetes pēc noklusējuma netiek iekļautas ieteikumos, kad meklē pēc nosaukuma.
|
||||||
issues.label_exclusive_desc=Nosauciet etiķeti <code>grupa/nosaukums</code>, lai grupētu etiķētes un varētu norādīt tās kā ekskluzīvas ar citām <code>grupa/</code> etiķetēm.
|
issues.label_exclusive_desc=Nosauciet iezīmi <code>grupa/nosaukums</code>, lai tās grupētu un varētu padarīt kā savstarpēji sevišķas ar citām <code>grupa/</code> iezīmēm.
|
||||||
issues.label_exclusive_warning=Jebkura konfliktējoša ekskluzīvas grupas etiķete tiks noņemta, labojot pieteikumu vai izmaiņu pietikumu etiķetes.
|
issues.label_exclusive_warning=Jebkura konfliktējoša savstarpēji sevišķas grupas iezīme tiks noņemta, labojot problēmas vai izmaiņu pietikuma iezīmes.
|
||||||
issues.label_count=%d etiķetes
|
issues.label_count=%d iezīmes
|
||||||
issues.label_open_issues=%d atvērtas problēmas
|
issues.label_open_issues=%d atvērtas problēmas
|
||||||
issues.label_edit=Labot
|
issues.label_edit=Labot
|
||||||
issues.label_delete=Dzēst
|
issues.label_delete=Dzēst
|
||||||
issues.label_modify=Labot etiķeti
|
issues.label_modify=Labot iezīmi
|
||||||
issues.label_deletion=Dzēst etiķeti
|
issues.label_deletion=Dzēst etiķeti
|
||||||
issues.label_deletion_desc=Dzēšot etiķeti, tā tiks noņemta no visām problēmām un izmaiņu pieprasījumiem. Vai turpināt?
|
issues.label_deletion_desc=Dzēšot iezīmi, tā tiks noņemta no visām problēmām un izmaiņu pieprasījumiem. Vai turpināt?
|
||||||
issues.label_deletion_success=Etiķete tika izdzēsta.
|
issues.label_deletion_success=Iezīme tika izdzēsta.
|
||||||
issues.label.filter_sort.alphabetically=Alfabētiski
|
issues.label.filter_sort.alphabetically=Alfabētiski
|
||||||
issues.label.filter_sort.reverse_alphabetically=Pretēji alfabētiski
|
issues.label.filter_sort.reverse_alphabetically=Pretēji alfabētiski
|
||||||
issues.label.filter_sort.by_size=Mazākais izmērs
|
issues.label.filter_sort.by_size=Mazākais izmērs
|
||||||
@ -1676,7 +1677,7 @@ pulls.allow_edits_from_maintainers_err=Atjaunošana neizdevās
|
|||||||
pulls.compare_changes_desc=Izvēlieties atzaru, kurā sapludināt izmaiņas un atzaru, no kura tās saņemt.
|
pulls.compare_changes_desc=Izvēlieties atzaru, kurā sapludināt izmaiņas un atzaru, no kura tās saņemt.
|
||||||
pulls.has_viewed_file=Skatīts
|
pulls.has_viewed_file=Skatīts
|
||||||
pulls.has_changed_since_last_review=Mainīts kopš pēdējās recenzijas
|
pulls.has_changed_since_last_review=Mainīts kopš pēdējās recenzijas
|
||||||
pulls.viewed_files_label=%[1]d no %[2]d failiem apskatīts
|
pulls.viewed_files_label=apskatīts %[1]d no %[2]d failiem
|
||||||
pulls.expand_files=Izvērst visus failus
|
pulls.expand_files=Izvērst visus failus
|
||||||
pulls.collapse_files=Savērst visus failus
|
pulls.collapse_files=Savērst visus failus
|
||||||
pulls.compare_base=pamata
|
pulls.compare_base=pamata
|
||||||
@ -1886,7 +1887,7 @@ wiki.page_name_desc=Ievadiet vikivietnes lapas nosaukumu. Speciālie nosaukumi i
|
|||||||
wiki.original_git_entry_tooltip=Attēlot oriģinālo Git faila nosaukumu.
|
wiki.original_git_entry_tooltip=Attēlot oriģinālo Git faila nosaukumu.
|
||||||
|
|
||||||
activity=Aktivitāte
|
activity=Aktivitāte
|
||||||
activity.period.filter_label=Laika periods:
|
activity.period.filter_label=Laika posms:
|
||||||
activity.period.daily=1 diena
|
activity.period.daily=1 diena
|
||||||
activity.period.halfweekly=3 dienas
|
activity.period.halfweekly=3 dienas
|
||||||
activity.period.weekly=1 nedēļa
|
activity.period.weekly=1 nedēļa
|
||||||
@ -2171,8 +2172,8 @@ settings.event_issues=Problēmas
|
|||||||
settings.event_issues_desc=Problēma atvērta, aizvērta, atkārtoti atvērta vai mainīta.
|
settings.event_issues_desc=Problēma atvērta, aizvērta, atkārtoti atvērta vai mainīta.
|
||||||
settings.event_issue_assign=Problēmas atbildīgie
|
settings.event_issue_assign=Problēmas atbildīgie
|
||||||
settings.event_issue_assign_desc=Problēmai piešķirti vai noņemti atbildīgie.
|
settings.event_issue_assign_desc=Problēmai piešķirti vai noņemti atbildīgie.
|
||||||
settings.event_issue_label=Problēmu etiķetes
|
settings.event_issue_label=Problēmu iezīmes
|
||||||
settings.event_issue_label_desc=Problēmai pievienotas vai noņemtas etiķetes.
|
settings.event_issue_label_desc=Problēmai pievienotas vai noņemtas iezīmes.
|
||||||
settings.event_issue_milestone=Problēmas atskaites punkts
|
settings.event_issue_milestone=Problēmas atskaites punkts
|
||||||
settings.event_issue_milestone_desc=Problēmai pievienots vai noņemts atskaites punkts.
|
settings.event_issue_milestone_desc=Problēmai pievienots vai noņemts atskaites punkts.
|
||||||
settings.event_issue_comment=Problēmas komentārs
|
settings.event_issue_comment=Problēmas komentārs
|
||||||
@ -2182,8 +2183,8 @@ settings.event_pull_request=Izmaiņu pieprasījums
|
|||||||
settings.event_pull_request_desc=Izmaiņu pieprasījums atvērts, aizvērts, atkārtoti atvērts vai mainīts.
|
settings.event_pull_request_desc=Izmaiņu pieprasījums atvērts, aizvērts, atkārtoti atvērts vai mainīts.
|
||||||
settings.event_pull_request_assign=Izmaiņu pieprasījuma atbildīgie
|
settings.event_pull_request_assign=Izmaiņu pieprasījuma atbildīgie
|
||||||
settings.event_pull_request_assign_desc=Izmaiņu pieprasījumam piešķirti vai noņemti atbildīgie.
|
settings.event_pull_request_assign_desc=Izmaiņu pieprasījumam piešķirti vai noņemti atbildīgie.
|
||||||
settings.event_pull_request_label=Izmaiņu pieprasījuma etiķetes
|
settings.event_pull_request_label=Izmaiņu pieprasījuma iezīmes
|
||||||
settings.event_pull_request_label_desc=Izmaiņu pieprasījumam pievienotas vai noņemtas etiķetes.
|
settings.event_pull_request_label_desc=Izmaiņu pieprasījumam tika pievienotas vai noņemtas iezīmes.
|
||||||
settings.event_pull_request_milestone=Izmaiņu pieprasījuma atskaites punkts
|
settings.event_pull_request_milestone=Izmaiņu pieprasījuma atskaites punkts
|
||||||
settings.event_pull_request_milestone_desc=Izmaiņu pieprasījumam pievienots vai noņemts atskaites punkts.
|
settings.event_pull_request_milestone_desc=Izmaiņu pieprasījumam pievienots vai noņemts atskaites punkts.
|
||||||
settings.event_pull_request_comment=Izmaiņu pieprasījuma komentārs
|
settings.event_pull_request_comment=Izmaiņu pieprasījuma komentārs
|
||||||
@ -2598,7 +2599,7 @@ settings.delete_org_title=Dzēst organizāciju
|
|||||||
settings.delete_org_desc=Organizācija tiks dzēsta neatgriezeniski. Vai turpināt?
|
settings.delete_org_desc=Organizācija tiks dzēsta neatgriezeniski. Vai turpināt?
|
||||||
settings.hooks_desc=Pievienot tīmekļa āķus, kas nostrādās <strong>visiem repozitorijiem</strong> šajā organizācijā.
|
settings.hooks_desc=Pievienot tīmekļa āķus, kas nostrādās <strong>visiem repozitorijiem</strong> šajā organizācijā.
|
||||||
|
|
||||||
settings.labels_desc=Pievienojiet etiķetes, kas var tikt izmantotas <strong>visos</strong> šīs organizācijas repozitorijos.
|
settings.labels_desc=Pievienojiet iezīmes, kas var tikt izmantotas <strong>visos</strong> šīs organizācijas repozitorijos.
|
||||||
|
|
||||||
members.membership_visibility=Dalībnieka redzamība:
|
members.membership_visibility=Dalībnieka redzamība:
|
||||||
members.public=Redzams
|
members.public=Redzams
|
||||||
@ -3217,7 +3218,6 @@ mirror_sync_create=ar spoguli sinhronizēta jauna atsauce <a href="%[2]s">%[3]s<
|
|||||||
mirror_sync_delete=ar spoguli sinhronizēta un izdzēsta atsauce <code>%[2]s</code> repozitorijam <a href="%[1]s">%[3]s</a>
|
mirror_sync_delete=ar spoguli sinhronizēta un izdzēsta atsauce <code>%[2]s</code> repozitorijam <a href="%[1]s">%[3]s</a>
|
||||||
approve_pull_request=`apstiprināja izmaiņu pieprasījumu <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`apstiprināja izmaiņu pieprasījumu <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`ieteica izmaiņas izmaiņu pieprasījumam <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`ieteica izmaiņas izmaiņu pieprasījumam <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`izveidoja versiju <a href="%[2]s"> "%[4]s" </a> repozitorijā <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`noraidīja lietotāja <b>%[4]s</b> recenziju izmaiņu pieprasījumam <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`noraidīja lietotāja <b>%[4]s</b> recenziju izmaiņu pieprasījumam <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Iemesls:
|
review_dismissed_reason=Iemesls:
|
||||||
create_branch=izveidoja atzaru <a href="%[2]s">%[3]s</a> repozitorijā <a href="%[1]s">%[4]s</a>
|
create_branch=izveidoja atzaru <a href="%[2]s">%[3]s</a> repozitorijā <a href="%[1]s">%[4]s</a>
|
||||||
@ -3337,7 +3337,7 @@ container.pull=Atgādājiet šo attēlu no komandrindas:
|
|||||||
container.digest=Īssavilkums:
|
container.digest=Īssavilkums:
|
||||||
container.multi_arch=OS / arhitektūra
|
container.multi_arch=OS / arhitektūra
|
||||||
container.layers=Attēla slāņi
|
container.layers=Attēla slāņi
|
||||||
container.labels=Etiķetes
|
container.labels=Iezīmes
|
||||||
container.labels.key=Atslēga
|
container.labels.key=Atslēga
|
||||||
container.labels.value=Vērtība
|
container.labels.value=Vērtība
|
||||||
cran.registry=Iestaties šo reģistru savā <code>Rprofile.site</code> failā:
|
cran.registry=Iestaties šo reģistru savā <code>Rprofile.site</code> failā:
|
||||||
|
@ -3153,7 +3153,6 @@ mirror_sync_create=sincronizou a nova referência <a href="%[2]s">%[3]s</a> para
|
|||||||
mirror_sync_delete=referência excluída e sincronizada <code>%[2]s</code> em <a href="%[1]s">%[3]s</a> do espelhamento
|
mirror_sync_delete=referência excluída e sincronizada <code>%[2]s</code> em <a href="%[1]s">%[3]s</a> do espelhamento
|
||||||
approve_pull_request=`aprovou <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`aprovou <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`sugeriu modificações para <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`sugeriu modificações para <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`lançou a versão <a href="%[2]s"> "%[4]s" </a> em <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Motivo:
|
review_dismissed_reason=Motivo:
|
||||||
create_branch=criou o branch <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a>
|
create_branch=criou o branch <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a>
|
||||||
|
@ -3348,7 +3348,6 @@ mirror_sync_create=sincronizou a nova referência <a href="%[2]s">%[3]s</a> para
|
|||||||
mirror_sync_delete=sincronizou e eliminou a referência <code>%[2]s</code> em <a href="%[1]s">%[3]s</a> da réplica
|
mirror_sync_delete=sincronizou e eliminou a referência <code>%[2]s</code> em <a href="%[1]s">%[3]s</a> da réplica
|
||||||
approve_pull_request=`aprovou <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`aprovou <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`sugeriu modificações para <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`sugeriu modificações para <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`lançou <a href="%[2]s"> "%[4]s" </a> em <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Motivo:
|
review_dismissed_reason=Motivo:
|
||||||
create_branch=criou o ramo <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a>
|
create_branch=criou o ramo <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a>
|
||||||
|
@ -3147,7 +3147,6 @@ mirror_sync_create=синхронизировал(а) новую ссылку <a
|
|||||||
mirror_sync_delete=синхронизированные и удалённые ссылки <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> из зеркала
|
mirror_sync_delete=синхронизированные и удалённые ссылки <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> из зеркала
|
||||||
approve_pull_request=`утвердил(а) задачу <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`утвердил(а) задачу <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`предложил(а) изменения для <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`предложил(а) изменения для <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`выпустил(а) <a href="%[2]s"> "%[4]s" </a> в <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`отклонил(а) отзыв от <b>%[4]s</b> для <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`отклонил(а) отзыв от <b>%[4]s</b> для <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Причина:
|
review_dismissed_reason=Причина:
|
||||||
create_branch=создал(а) ветку <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
create_branch=создал(а) ветку <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
||||||
|
@ -2465,7 +2465,6 @@ mirror_sync_create=සමමුහුර්ත නව යොමු <a href="%[2]
|
|||||||
mirror_sync_delete=සමමුහුර්ත සහ මකාදැමූ යොමු <code>%[2]s</code> හි <a href="%[1]s">%[3]s</a> කැඩපතෙන්
|
mirror_sync_delete=සමමුහුර්ත සහ මකාදැමූ යොමු <code>%[2]s</code> හි <a href="%[1]s">%[3]s</a> කැඩපතෙන්
|
||||||
approve_pull_request=`අනුමත <a href="%[1]s">%[3]s #%[2]s ගේ</a>`
|
approve_pull_request=`අනුමත <a href="%[1]s">%[3]s #%[2]s ගේ</a>`
|
||||||
reject_pull_request=<a href="%[1]s">%[3]s #%[2]s</a>සඳහා යෝජිත වෙනස්කම්
|
reject_pull_request=<a href="%[1]s">%[3]s #%[2]s</a>සඳහා යෝජිත වෙනස්කම්
|
||||||
publish_release=`නිදහස් <a href="%[2]s"> "%[4]s" </a> හි <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed_reason=හේතුව:
|
review_dismissed_reason=හේතුව:
|
||||||
create_branch=නිර්මාණය කරන ලද ශාඛාව <a href="%[2]s">%[3]s</a> <a href="%[1]s">%[4]s</a>
|
create_branch=නිර්මාණය කරන ලද ශාඛාව <a href="%[2]s">%[3]s</a> <a href="%[1]s">%[4]s</a>
|
||||||
watched_repo=<a href="%[1]s">%[2]s</a>නැරඹීමට පටන් ගත්තා
|
watched_repo=<a href="%[1]s">%[2]s</a>නැරඹීමට පටන් ගත්තා
|
||||||
|
@ -3344,7 +3344,6 @@ mirror_sync_create=<a href="%[2]s">%[3]s</a> yeni referansını, <a href="%[1]s"
|
|||||||
mirror_sync_delete=<a href="%[1]s">%[3]s</a> adresindeki <code>%[2]s</code> referansını eşitledi ve sildi
|
mirror_sync_delete=<a href="%[1]s">%[3]s</a> adresindeki <code>%[2]s</code> referansını eşitledi ve sildi
|
||||||
approve_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> değişiklik isteğini onayladı`
|
approve_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> değişiklik isteğini onayladı`
|
||||||
reject_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> için değişiklikler önerdi`
|
reject_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> için değişiklikler önerdi`
|
||||||
publish_release=`<a href="%[1]s">%[3]s</a> deposu için <a href="%[2]s"> "%[4]s" </a> sürümü yayınlandı`
|
|
||||||
review_dismissed=`<a href="%[1]s">%[3]s#%[2]s</a> için <b>%[4]s</b> yorumunu reddetti`
|
review_dismissed=`<a href="%[1]s">%[3]s#%[2]s</a> için <b>%[4]s</b> yorumunu reddetti`
|
||||||
review_dismissed_reason=Sebep:
|
review_dismissed_reason=Sebep:
|
||||||
create_branch=<a href="%[1]s">%[4]s</a> deposunda <a href="%[2]s">%[3]s</a> dalını oluşturdu
|
create_branch=<a href="%[1]s">%[4]s</a> deposunda <a href="%[2]s">%[3]s</a> dalını oluşturdu
|
||||||
|
@ -2517,7 +2517,6 @@ mirror_sync_create=синхронізував нове посилання <a hre
|
|||||||
mirror_sync_delete=синхронізовано й видалено посилання <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> із дзеркала
|
mirror_sync_delete=синхронізовано й видалено посилання <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> із дзеркала
|
||||||
approve_pull_request=`схвалив <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`схвалив <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`запропонував зміни до <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`запропонував зміни до <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`опублікував випуск <a href="%[2]s"> "%[4]s" </a> з <a href="%[1]s">%[3]s</a>`
|
|
||||||
review_dismissed=`відхилив відгук від <b>%[4]s</b> для <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`відхилив відгук від <b>%[4]s</b> для <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Причина:
|
review_dismissed_reason=Причина:
|
||||||
create_branch=створив гілку <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
create_branch=створив гілку <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
||||||
|
@ -3320,6 +3320,7 @@ self_check.database_collation_case_insensitive=数据库正在使用一个校验
|
|||||||
self_check.database_inconsistent_collation_columns=数据库正在使用%s的排序规则,但是这些列使用了不匹配的排序规则。这可能会造成一些意外问题。
|
self_check.database_inconsistent_collation_columns=数据库正在使用%s的排序规则,但是这些列使用了不匹配的排序规则。这可能会造成一些意外问题。
|
||||||
self_check.database_fix_mysql=对于MySQL/MariaDB用户,您可以使用“gitea doctor convert”命令来解决校验问题。 或者您也可以通过 "ALTER ... COLLATE ..." 这样的SQL 来手动解决这个问题。
|
self_check.database_fix_mysql=对于MySQL/MariaDB用户,您可以使用“gitea doctor convert”命令来解决校验问题。 或者您也可以通过 "ALTER ... COLLATE ..." 这样的SQL 来手动解决这个问题。
|
||||||
self_check.database_fix_mssql=对于MSSQL用户,您现在只能通过"ALTER ... COLLATE ..."SQLs手动解决这个问题。
|
self_check.database_fix_mssql=对于MSSQL用户,您现在只能通过"ALTER ... COLLATE ..."SQLs手动解决这个问题。
|
||||||
|
self_check.location_origin_mismatch=当前 URL (%[1]s) 与 Gitea 的 URL (%[2]s) 不匹配 。 如果您正在使用反向代理,请确保设置正确的“主机”和“X-转发-原始”标题。
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
create_repo=创建了仓库 <a href="%s">%s</a>
|
create_repo=创建了仓库 <a href="%s">%s</a>
|
||||||
@ -3347,7 +3348,7 @@ mirror_sync_create=从镜像同步了引用 <a href="%[2]s">%[3]s</a> 至仓库
|
|||||||
mirror_sync_delete=从镜像同步并从 <a href="%[1]s">%[3]s</a> 删除了引用 <code>%[2]s</code>
|
mirror_sync_delete=从镜像同步并从 <a href="%[1]s">%[3]s</a> 删除了引用 <code>%[2]s</code>
|
||||||
approve_pull_request=`批准了 <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`批准了 <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`建议变更 <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`建议变更 <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`在 <a href="%[1]s">%[3]s</a> 发布了 <a href="%[2]s"> "%[4]s" </a>`
|
publish_release=`在 <a href="%[1]s">%[3]s</a> 发布了 <a href="%[2]s"> %[4]s </a>`
|
||||||
review_dismissed=`取消了 <b>%[4]s</b> 对 <a href="%[1]s">%[3]s#%[2]s</a> 的变更请求`
|
review_dismissed=`取消了 <b>%[4]s</b> 对 <a href="%[1]s">%[3]s#%[2]s</a> 的变更请求`
|
||||||
review_dismissed_reason=原因:
|
review_dismissed_reason=原因:
|
||||||
create_branch=于 <a href="%[1]s">%[4]s</a> 创建了分支 <a href="%[2]s">%[3]s</a>
|
create_branch=于 <a href="%[1]s">%[4]s</a> 创建了分支 <a href="%[2]s">%[3]s</a>
|
||||||
|
@ -2932,7 +2932,6 @@ mirror_sync_create=從鏡像同步了新參考 <a href="%[2]s">%[3]s</a> 到 <a
|
|||||||
mirror_sync_delete=從鏡像同步並從 <a href="%[1]s">%[3]s</a> 刪除了參考 <code>%[2]s</code>
|
mirror_sync_delete=從鏡像同步並從 <a href="%[1]s">%[3]s</a> 刪除了參考 <code>%[2]s</code>
|
||||||
approve_pull_request=`核可了 <a href="%[1]s">%[3]s#%[2]s</a>`
|
approve_pull_request=`核可了 <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`提出了修改建議 <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`提出了修改建議 <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`發布了 <a href="%[1]s">%[3]s</a> 的 <a href="%[2]s"> "%[4]s" </a>`
|
|
||||||
review_dismissed=`取消了 <b>%[4]s</b> 對 <a href="%[1]s">%[3]s#%[2]s</a> 的審核`
|
review_dismissed=`取消了 <b>%[4]s</b> 對 <a href="%[1]s">%[3]s#%[2]s</a> 的審核`
|
||||||
review_dismissed_reason=原因:
|
review_dismissed_reason=原因:
|
||||||
create_branch=在 <a href="%[1]s">%[4]s</a> 中建立了分支 <a href="%[2]s">%[3]s</a>
|
create_branch=在 <a href="%[1]s">%[4]s</a> 中建立了分支 <a href="%[2]s">%[3]s</a>
|
||||||
|
8
poetry.lock
generated
8
poetry.lock
generated
@ -1,4 +1,4 @@
|
|||||||
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
@ -318,13 +318,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tqdm"
|
name = "tqdm"
|
||||||
version = "4.66.2"
|
version = "4.66.4"
|
||||||
description = "Fast, Extensible Progress Meter"
|
description = "Fast, Extensible Progress Meter"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"},
|
{file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"},
|
||||||
{file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"},
|
{file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
@ -116,6 +116,8 @@ func apiErrorDefined(ctx *context.Context, err *namedError) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func apiUnauthorizedError(ctx *context.Context) {
|
func apiUnauthorizedError(ctx *context.Context) {
|
||||||
|
// TODO: it doesn't seem quite right but it doesn't really cause problem at the moment.
|
||||||
|
// container registry requires that the "/v2" must be in the root, so the sub-path in AppURL should be removed, ideally.
|
||||||
ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+httplib.GuessCurrentAppURL(ctx)+`v2/token",service="container_registry",scope="*"`)
|
ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+httplib.GuessCurrentAppURL(ctx)+`v2/token",service="container_registry",scope="*"`)
|
||||||
apiErrorDefined(ctx, errUnauthorized)
|
apiErrorDefined(ctx, errUnauthorized)
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ func UpdateAvatar(ctx *context.APIContext) {
|
|||||||
err = user_service.UploadAvatar(ctx, ctx.Org.Organization.AsUser(), content)
|
err = user_service.UploadAvatar(ctx, ctx.Org.Organization.AsUser(), content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "UploadAvatar", err)
|
ctx.Error(http.StatusInternalServerError, "UploadAvatar", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
@ -72,6 +73,7 @@ func DeleteAvatar(ctx *context.APIContext) {
|
|||||||
err := user_service.DeleteAvatar(ctx, ctx.Org.Organization.AsUser())
|
err := user_service.DeleteAvatar(ctx, ctx.Org.Organization.AsUser())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "DeleteAvatar", err)
|
ctx.Error(http.StatusInternalServerError, "DeleteAvatar", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
|
@ -175,7 +175,7 @@ func Migrate(ctx *context.APIContext) {
|
|||||||
Description: opts.Description,
|
Description: opts.Description,
|
||||||
OriginalURL: form.CloneAddr,
|
OriginalURL: form.CloneAddr,
|
||||||
GitServiceType: gitServiceType,
|
GitServiceType: gitServiceType,
|
||||||
IsPrivate: opts.Private,
|
IsPrivate: opts.Private || setting.Repository.ForcePrivate,
|
||||||
IsMirror: opts.Mirror,
|
IsMirror: opts.Mirror,
|
||||||
Status: repo_model.RepositoryBeingMigrated,
|
Status: repo_model.RepositoryBeingMigrated,
|
||||||
})
|
})
|
||||||
|
@ -215,6 +215,9 @@ func CreateRelease(ctx *context.APIContext) {
|
|||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
// "409":
|
// "409":
|
||||||
// "$ref": "#/responses/error"
|
// "$ref": "#/responses/error"
|
||||||
|
// "422":
|
||||||
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.CreateReleaseOption)
|
form := web.GetForm(ctx).(*api.CreateReleaseOption)
|
||||||
if ctx.Repo.Repository.IsEmpty {
|
if ctx.Repo.Repository.IsEmpty {
|
||||||
ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty"))
|
ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty"))
|
||||||
@ -246,6 +249,8 @@ func CreateRelease(ctx *context.APIContext) {
|
|||||||
if err := release_service.CreateRelease(ctx.Repo.GitRepo, rel, nil, ""); err != nil {
|
if err := release_service.CreateRelease(ctx.Repo.GitRepo, rel, nil, ""); err != nil {
|
||||||
if repo_model.IsErrReleaseAlreadyExist(err) {
|
if repo_model.IsErrReleaseAlreadyExist(err) {
|
||||||
ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err)
|
ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err)
|
||||||
|
} else if models.IsErrProtectedTagName(err) {
|
||||||
|
ctx.Error(http.StatusUnprocessableEntity, "ProtectedTagName", err)
|
||||||
} else {
|
} else {
|
||||||
ctx.Error(http.StatusInternalServerError, "CreateRelease", err)
|
ctx.Error(http.StatusInternalServerError, "CreateRelease", err)
|
||||||
}
|
}
|
||||||
@ -386,8 +391,8 @@ func DeleteRelease(ctx *context.APIContext) {
|
|||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
// "405":
|
// "422":
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
id := ctx.ParamsInt64(":id")
|
id := ctx.ParamsInt64(":id")
|
||||||
rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id)
|
rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id)
|
||||||
@ -401,7 +406,7 @@ func DeleteRelease(ctx *context.APIContext) {
|
|||||||
}
|
}
|
||||||
if err := release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, false); err != nil {
|
if err := release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, false); err != nil {
|
||||||
if models.IsErrProtectedTagName(err) {
|
if models.IsErrProtectedTagName(err) {
|
||||||
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
|
ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
|
ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
|
||||||
|
@ -92,8 +92,8 @@ func DeleteReleaseByTag(ctx *context.APIContext) {
|
|||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
// "405":
|
// "422":
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
tag := ctx.Params(":tag")
|
tag := ctx.Params(":tag")
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ func DeleteReleaseByTag(ctx *context.APIContext) {
|
|||||||
|
|
||||||
if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, release, ctx.Doer, false); err != nil {
|
if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, release, ctx.Doer, false); err != nil {
|
||||||
if models.IsErrProtectedTagName(err) {
|
if models.IsErrProtectedTagName(err) {
|
||||||
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
|
ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
|
ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
|
||||||
|
@ -252,7 +252,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
|
|||||||
Gitignores: opt.Gitignores,
|
Gitignores: opt.Gitignores,
|
||||||
License: opt.License,
|
License: opt.License,
|
||||||
Readme: opt.Readme,
|
Readme: opt.Readme,
|
||||||
IsPrivate: opt.Private,
|
IsPrivate: opt.Private || setting.Repository.ForcePrivate,
|
||||||
AutoInit: opt.AutoInit,
|
AutoInit: opt.AutoInit,
|
||||||
DefaultBranch: opt.DefaultBranch,
|
DefaultBranch: opt.DefaultBranch,
|
||||||
TrustModel: repo_model.ToTrustModel(opt.TrustModel),
|
TrustModel: repo_model.ToTrustModel(opt.TrustModel),
|
||||||
@ -364,7 +364,7 @@ func Generate(ctx *context.APIContext) {
|
|||||||
Name: form.Name,
|
Name: form.Name,
|
||||||
DefaultBranch: form.DefaultBranch,
|
DefaultBranch: form.DefaultBranch,
|
||||||
Description: form.Description,
|
Description: form.Description,
|
||||||
Private: form.Private,
|
Private: form.Private || setting.Repository.ForcePrivate,
|
||||||
GitContent: form.GitContent,
|
GitContent: form.GitContent,
|
||||||
Topics: form.Topics,
|
Topics: form.Topics,
|
||||||
GitHooks: form.GitHooks,
|
GitHooks: form.GitHooks,
|
||||||
@ -1062,16 +1062,10 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e
|
|||||||
func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error {
|
func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||||
repo := ctx.Repo.Repository
|
repo := ctx.Repo.Repository
|
||||||
|
|
||||||
// only update mirror if interval or enable prune are provided
|
// Skip this update if the repo is not a mirror, do not return error.
|
||||||
if opts.MirrorInterval == nil && opts.EnablePrune == nil {
|
// Because reporting errors only makes the logic more complex&fragile, it doesn't really help end users.
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// these values only make sense if the repo is a mirror
|
|
||||||
if !repo.IsMirror {
|
if !repo.IsMirror {
|
||||||
err := fmt.Errorf("repo is not a mirror, can not change mirror interval")
|
return nil
|
||||||
ctx.Error(http.StatusUnprocessableEntity, err.Error(), err)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the mirror from the repo
|
// get the mirror from the repo
|
||||||
|
@ -184,6 +184,8 @@ func CreateTag(ctx *context.APIContext) {
|
|||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
// "409":
|
// "409":
|
||||||
// "$ref": "#/responses/conflict"
|
// "$ref": "#/responses/conflict"
|
||||||
|
// "422":
|
||||||
|
// "$ref": "#/responses/validationError"
|
||||||
// "423":
|
// "423":
|
||||||
// "$ref": "#/responses/repoArchivedError"
|
// "$ref": "#/responses/repoArchivedError"
|
||||||
form := web.GetForm(ctx).(*api.CreateTagOption)
|
form := web.GetForm(ctx).(*api.CreateTagOption)
|
||||||
@ -205,7 +207,7 @@ func CreateTag(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if models.IsErrProtectedTagName(err) {
|
if models.IsErrProtectedTagName(err) {
|
||||||
ctx.Error(http.StatusMethodNotAllowed, "CreateNewTag", "user not allowed to create protected tag")
|
ctx.Error(http.StatusUnprocessableEntity, "CreateNewTag", "user not allowed to create protected tag")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,6 +255,8 @@ func DeleteTag(ctx *context.APIContext) {
|
|||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
// "409":
|
// "409":
|
||||||
// "$ref": "#/responses/conflict"
|
// "$ref": "#/responses/conflict"
|
||||||
|
// "422":
|
||||||
|
// "$ref": "#/responses/validationError"
|
||||||
// "423":
|
// "423":
|
||||||
// "$ref": "#/responses/repoArchivedError"
|
// "$ref": "#/responses/repoArchivedError"
|
||||||
tagName := ctx.Params("*")
|
tagName := ctx.Params("*")
|
||||||
@ -274,7 +278,7 @@ func DeleteTag(ctx *context.APIContext) {
|
|||||||
|
|
||||||
if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil {
|
if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil {
|
||||||
if models.IsErrProtectedTagName(err) {
|
if models.IsErrProtectedTagName(err) {
|
||||||
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
|
ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
|
ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
|
||||||
|
@ -39,6 +39,7 @@ func UpdateAvatar(ctx *context.APIContext) {
|
|||||||
err = user_service.UploadAvatar(ctx, ctx.Doer, content)
|
err = user_service.UploadAvatar(ctx, ctx.Doer, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "UploadAvatar", err)
|
ctx.Error(http.StatusInternalServerError, "UploadAvatar", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
@ -57,6 +58,7 @@ func DeleteAvatar(ctx *context.APIContext) {
|
|||||||
err := user_service.DeleteAvatar(ctx, ctx.Doer)
|
err := user_service.DeleteAvatar(ctx, ctx.Doer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "DeleteAvatar", err)
|
ctx.Error(http.StatusInternalServerError, "DeleteAvatar", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
|
@ -481,6 +481,17 @@ func SubmitInstall(ctx *context.Context) {
|
|||||||
cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(internalToken)
|
cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(internalToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: at the moment, no matter oauth2 is enabled or not, it must generate a "oauth2 JWT_SECRET"
|
||||||
|
// see the "loadOAuth2From" in "setting/oauth2.go"
|
||||||
|
if !cfg.Section("oauth2").HasKey("JWT_SECRET") && !cfg.Section("oauth2").HasKey("JWT_SECRET_URI") {
|
||||||
|
_, jwtSecretBase64, err := generate.NewJwtSecretWithBase64()
|
||||||
|
if err != nil {
|
||||||
|
ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), tplInstall, &form)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfg.Section("oauth2").Key("JWT_SECRET").SetValue(jwtSecretBase64)
|
||||||
|
}
|
||||||
|
|
||||||
// if there is already a SECRET_KEY, we should not overwrite it, otherwise the encrypted data will not be able to be decrypted
|
// if there is already a SECRET_KEY, we should not overwrite it, otherwise the encrypted data will not be able to be decrypted
|
||||||
if setting.SecretKey == "" {
|
if setting.SecretKey == "" {
|
||||||
var secretKey string
|
var secretKey string
|
||||||
|
@ -87,6 +87,6 @@ func TestSelfCheckPost(t *testing.T) {
|
|||||||
err := json.Unmarshal(resp.Body.Bytes(), &data)
|
err := json.Unmarshal(resp.Body.Bytes(), &data)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []string{
|
assert.Equal(t, []string{
|
||||||
ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://host/sub/"),
|
ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://config/sub/"),
|
||||||
}, data.Problems)
|
}, data.Problems)
|
||||||
}
|
}
|
||||||
|
@ -541,6 +541,16 @@ func GrantApplicationOAuth(ctx *context.Context) {
|
|||||||
ctx.Error(http.StatusBadRequest)
|
ctx.Error(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !form.Granted {
|
||||||
|
handleAuthorizeError(ctx, AuthorizeError{
|
||||||
|
State: form.State,
|
||||||
|
ErrorDescription: "the request is denied",
|
||||||
|
ErrorCode: ErrorCodeAccessDenied,
|
||||||
|
}, form.RedirectURI)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
|
app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetOAuth2ApplicationByClientID", err)
|
ctx.ServerError("GetOAuth2ApplicationByClientID", err)
|
||||||
|
@ -931,7 +931,7 @@ func ExcerptBlob(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.Data["section"] = section
|
ctx.Data["section"] = section
|
||||||
ctx.Data["FileNameHash"] = base.EncodeSha1(filePath)
|
ctx.Data["FileNameHash"] = git.HashFilePathForWebUI(filePath)
|
||||||
ctx.Data["AfterCommitID"] = commitID
|
ctx.Data["AfterCommitID"] = commitID
|
||||||
ctx.Data["Anchor"] = anchor
|
ctx.Data["Anchor"] = anchor
|
||||||
ctx.HTML(http.StatusOK, tplBlobExcerpt)
|
ctx.HTML(http.StatusOK, tplBlobExcerpt)
|
||||||
|
@ -248,7 +248,7 @@ func CreatePost(ctx *context.Context) {
|
|||||||
opts := repo_service.GenerateRepoOptions{
|
opts := repo_service.GenerateRepoOptions{
|
||||||
Name: form.RepoName,
|
Name: form.RepoName,
|
||||||
Description: form.Description,
|
Description: form.Description,
|
||||||
Private: form.Private,
|
Private: form.Private || setting.Repository.ForcePrivate,
|
||||||
GitContent: form.GitContent,
|
GitContent: form.GitContent,
|
||||||
Topics: form.Topics,
|
Topics: form.Topics,
|
||||||
GitHooks: form.GitHooks,
|
GitHooks: form.GitHooks,
|
||||||
|
@ -161,6 +161,7 @@ func (f *AuthorizationForm) Validate(req *http.Request, errs binding.Errors) bin
|
|||||||
// GrantApplicationForm form for authorizing oauth2 clients
|
// GrantApplicationForm form for authorizing oauth2 clients
|
||||||
type GrantApplicationForm struct {
|
type GrantApplicationForm struct {
|
||||||
ClientID string `binding:"Required"`
|
ClientID string `binding:"Required"`
|
||||||
|
Granted bool
|
||||||
RedirectURI string
|
RedirectURI string
|
||||||
State string
|
State string
|
||||||
Scope string
|
Scope string
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
pull_model "code.gitea.io/gitea/models/pull"
|
pull_model "code.gitea.io/gitea/models/pull"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/analyze"
|
"code.gitea.io/gitea/modules/analyze"
|
||||||
"code.gitea.io/gitea/modules/base"
|
|
||||||
"code.gitea.io/gitea/modules/charset"
|
"code.gitea.io/gitea/modules/charset"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/highlight"
|
"code.gitea.io/gitea/modules/highlight"
|
||||||
@ -746,7 +745,7 @@ parsingLoop:
|
|||||||
diffLineTypeBuffers[DiffLineAdd] = new(bytes.Buffer)
|
diffLineTypeBuffers[DiffLineAdd] = new(bytes.Buffer)
|
||||||
diffLineTypeBuffers[DiffLineDel] = new(bytes.Buffer)
|
diffLineTypeBuffers[DiffLineDel] = new(bytes.Buffer)
|
||||||
for _, f := range diff.Files {
|
for _, f := range diff.Files {
|
||||||
f.NameHash = base.EncodeSha1(f.Name)
|
f.NameHash = git.HashFilePathForWebUI(f.Name)
|
||||||
|
|
||||||
for _, buffer := range diffLineTypeBuffers {
|
for _, buffer := range diffLineTypeBuffers {
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
@ -107,7 +107,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate
|
|||||||
Description: repo.Description,
|
Description: repo.Description,
|
||||||
OriginalURL: repo.OriginalURL,
|
OriginalURL: repo.OriginalURL,
|
||||||
GitServiceType: opts.GitServiceType,
|
GitServiceType: opts.GitServiceType,
|
||||||
IsPrivate: opts.Private,
|
IsPrivate: opts.Private || setting.Repository.ForcePrivate,
|
||||||
IsMirror: opts.Mirror,
|
IsMirror: opts.Mirror,
|
||||||
Status: repo_model.RepositoryBeingMigrated,
|
Status: repo_model.RepositoryBeingMigrated,
|
||||||
})
|
})
|
||||||
|
@ -204,7 +204,7 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo
|
|||||||
if rel.ID == 0 {
|
if rel.ID == 0 {
|
||||||
return errors.New("UpdateRelease only accepts an exist release")
|
return errors.New("UpdateRelease only accepts an exist release")
|
||||||
}
|
}
|
||||||
isCreated, err := createTag(gitRepo.Ctx, gitRepo, rel, "")
|
isTagCreated, err := createTag(gitRepo.Ctx, gitRepo, rel, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -216,6 +216,12 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo
|
|||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
|
oldRelease, err := repo_model.GetReleaseByID(ctx, rel.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
isConvertedFromTag := oldRelease.IsTag && !rel.IsTag
|
||||||
|
|
||||||
if err = repo_model.UpdateRelease(ctx, rel); err != nil {
|
if err = repo_model.UpdateRelease(ctx, rel); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -292,7 +298,7 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !rel.IsDraft {
|
if !rel.IsDraft {
|
||||||
if !isCreated {
|
if !isTagCreated && !isConvertedFromTag {
|
||||||
notify_service.UpdateRelease(gitRepo.Ctx, doer, rel)
|
notify_service.UpdateRelease(gitRepo.Ctx, doer, rel)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ func PushCreateRepo(ctx context.Context, authUser, owner *user_model.User, repoN
|
|||||||
|
|
||||||
repo, err := CreateRepository(ctx, authUser, owner, CreateRepoOptions{
|
repo, err := CreateRepository(ctx, authUser, owner, CreateRepoOptions{
|
||||||
Name: repoName,
|
Name: repoName,
|
||||||
IsPrivate: setting.Repository.DefaultPushCreatePrivate,
|
IsPrivate: setting.Repository.DefaultPushCreatePrivate || setting.Repository.ForcePrivate,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -107,7 +107,7 @@ func CreateMigrateTask(ctx context.Context, doer, u *user_model.User, opts base.
|
|||||||
Description: opts.Description,
|
Description: opts.Description,
|
||||||
OriginalURL: opts.OriginalURL,
|
OriginalURL: opts.OriginalURL,
|
||||||
GitServiceType: opts.GitServiceType,
|
GitServiceType: opts.GitServiceType,
|
||||||
IsPrivate: opts.Private,
|
IsPrivate: opts.Private || setting.Repository.ForcePrivate,
|
||||||
IsMirror: opts.Mirror,
|
IsMirror: opts.Mirror,
|
||||||
Status: repo_model.RepositoryBeingMigrated,
|
Status: repo_model.RepositoryBeingMigrated,
|
||||||
})
|
})
|
||||||
|
@ -5,8 +5,10 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
@ -48,16 +50,24 @@ func UploadAvatar(ctx context.Context, u *user_model.User, data []byte) error {
|
|||||||
func DeleteAvatar(ctx context.Context, u *user_model.User) error {
|
func DeleteAvatar(ctx context.Context, u *user_model.User) error {
|
||||||
aPath := u.CustomAvatarRelativePath()
|
aPath := u.CustomAvatarRelativePath()
|
||||||
log.Trace("DeleteAvatar[%d]: %s", u.ID, aPath)
|
log.Trace("DeleteAvatar[%d]: %s", u.ID, aPath)
|
||||||
if len(u.Avatar) > 0 {
|
|
||||||
if err := storage.Avatars.Delete(aPath); err != nil {
|
|
||||||
return fmt.Errorf("Failed to remove %s: %w", aPath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
|
hasAvatar := len(u.Avatar) > 0
|
||||||
u.UseCustomAvatar = false
|
u.UseCustomAvatar = false
|
||||||
u.Avatar = ""
|
u.Avatar = ""
|
||||||
if _, err := db.GetEngine(ctx).ID(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil {
|
if _, err := db.GetEngine(ctx).ID(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil {
|
||||||
return fmt.Errorf("DeleteAvatar: %w", err)
|
return fmt.Errorf("DeleteAvatar: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hasAvatar {
|
||||||
|
if err := storage.Avatars.Delete(aPath); err != nil {
|
||||||
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
|
return fmt.Errorf("failed to remove %s: %w", aPath, err)
|
||||||
|
}
|
||||||
|
log.Warn("Deleting avatar %s but it doesn't exist", aPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
{{if eq .PackageDescriptor.Package.Type "maven"}}
|
{{if and (eq .PackageDescriptor.Package.Type "maven") (not .PackageDescriptor.Metadata)}}
|
||||||
|
<h4 class="ui top attached header">{{ctx.Locale.Tr "packages.installation"}}</h4>
|
||||||
|
<div class="ui attached segment">{{ctx.Locale.Tr "packages.no_metadata"}}</div>
|
||||||
|
{{end}}
|
||||||
|
{{if and (eq .PackageDescriptor.Package.Type "maven") .PackageDescriptor.Metadata}}
|
||||||
<h4 class="ui top attached header">{{ctx.Locale.Tr "packages.installation"}}</h4>
|
<h4 class="ui top attached header">{{ctx.Locale.Tr "packages.installation"}}</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<div class="ui form">
|
<div class="ui form">
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
{{if eq .PackageDescriptor.Package.Type "maven"}}
|
{{if and (eq .PackageDescriptor.Package.Type "maven") (not .PackageDescriptor.Metadata)}}
|
||||||
|
<div class="item">{{svg "octicon-note" 16 "tw-mr-2"}} {{ctx.Locale.Tr "packages.no_metadata"}}</div>
|
||||||
|
{{end}}
|
||||||
|
{{if and (eq .PackageDescriptor.Package.Type "maven") .PackageDescriptor.Metadata}}
|
||||||
{{if .PackageDescriptor.Metadata.Name}}<div class="item">{{svg "octicon-note" 16 "tw-mr-2"}} {{.PackageDescriptor.Metadata.Name}}</div>{{end}}
|
{{if .PackageDescriptor.Metadata.Name}}<div class="item">{{svg "octicon-note" 16 "tw-mr-2"}} {{.PackageDescriptor.Metadata.Name}}</div>{{end}}
|
||||||
{{if .PackageDescriptor.Metadata.ProjectURL}}<div class="item">{{svg "octicon-link-external" 16 "tw-mr-2"}} <a href="{{.PackageDescriptor.Metadata.ProjectURL}}" target="_blank" rel="noopener noreferrer me">{{ctx.Locale.Tr "packages.details.project_site"}}</a></div>{{end}}
|
{{if .PackageDescriptor.Metadata.ProjectURL}}<div class="item">{{svg "octicon-link-external" 16 "tw-mr-2"}} <a href="{{.PackageDescriptor.Metadata.ProjectURL}}" target="_blank" rel="noopener noreferrer me">{{ctx.Locale.Tr "packages.details.project_site"}}</a></div>{{end}}
|
||||||
{{range .PackageDescriptor.Metadata.Licenses}}<div class="item" title="{{ctx.Locale.Tr "packages.details.license"}}">{{svg "octicon-law" 16 "tw-mr-2"}} {{.}}</div>{{end}}
|
{{range .PackageDescriptor.Metadata.Licenses}}<div class="item" title="{{ctx.Locale.Tr "packages.details.license"}}">{{svg "octicon-law" 16 "tw-mr-2"}} {{.}}</div>{{end}}
|
||||||
|
@ -68,18 +68,14 @@
|
|||||||
{{range .Columns}}
|
{{range .Columns}}
|
||||||
<div class="ui segment project-column"{{if .Color}} style="background: {{.Color}} !important; color: {{ContrastColor .Color}} !important"{{end}} data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.Link}}/{{.ID}}">
|
<div class="ui segment project-column"{{if .Color}} style="background: {{.Color}} !important; color: {{ContrastColor .Color}} !important"{{end}} data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.Link}}/{{.ID}}">
|
||||||
<div class="project-column-header{{if $canWriteProject}} tw-cursor-grab{{end}}">
|
<div class="project-column-header{{if $canWriteProject}} tw-cursor-grab{{end}}">
|
||||||
<div class="ui large label project-column-title tw-py-1">
|
<div class="ui circular label project-column-issue-count">
|
||||||
<div class="ui small circular grey label project-column-issue-count">
|
|
||||||
{{.NumIssues ctx}}
|
{{.NumIssues ctx}}
|
||||||
</div>
|
</div>
|
||||||
<span class="project-column-title-label">{{.Title}}</span>
|
<div class="project-column-title-label gt-ellipsis">{{.Title}}</div>
|
||||||
</div>
|
|
||||||
{{if $canWriteProject}}
|
{{if $canWriteProject}}
|
||||||
<div class="ui dropdown jump item">
|
<div class="ui dropdown tw-p-1">
|
||||||
<div class="tw-px-2">
|
|
||||||
{{svg "octicon-kebab-horizontal"}}
|
{{svg "octicon-kebab-horizontal"}}
|
||||||
</div>
|
<div class="menu">
|
||||||
<div class="menu user-menu">
|
|
||||||
<a class="item show-modal button" data-modal="#edit-project-column-modal-{{.ID}}">
|
<a class="item show-modal button" data-modal="#edit-project-column-modal-{{.ID}}">
|
||||||
{{svg "octicon-pencil"}}
|
{{svg "octicon-pencil"}}
|
||||||
{{ctx.Locale.Tr "repo.projects.column.edit"}}
|
{{ctx.Locale.Tr "repo.projects.column.edit"}}
|
||||||
|
@ -87,7 +87,7 @@
|
|||||||
<td class="eight wide">
|
<td class="eight wide">
|
||||||
{{if .DBBranch.IsDeleted}}
|
{{if .DBBranch.IsDeleted}}
|
||||||
<div class="flex-text-block">
|
<div class="flex-text-block">
|
||||||
<a class="gt-ellipsis" href="{{$.RepoLink}}/src/branch/{{PathEscapeSegments .DBBranch.Name}}">{{.DBBranch.Name}}</a>
|
<span class="gt-ellipsis">{{.DBBranch.Name}}</span>
|
||||||
<button class="btn interact-fg tw-px-1" data-clipboard-text="{{.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button>
|
<button class="btn interact-fg tw-px-1" data-clipboard-text="{{.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="info">{{ctx.Locale.Tr "repo.branch.deleted_by" .DBBranch.DeletedBy.Name}} {{TimeSinceUnix .DBBranch.DeletedUnix ctx.Locale}}</p>
|
<p class="info">{{ctx.Locale.Tr "repo.branch.deleted_by" .DBBranch.DeletedBy.Name}} {{TimeSinceUnix .DBBranch.DeletedUnix ctx.Locale}}</p>
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked readonly>
|
<input name="private" type="checkbox" checked disabled>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{{$file := .file}}
|
{{$file := .file}}
|
||||||
|
{{$blobExcerptRepoLink := or ctx.RootData.CommitRepoLink ctx.RootData.RepoLink}}
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col width="50">
|
<col width="50">
|
||||||
<col width="10">
|
<col width="10">
|
||||||
@ -18,17 +19,17 @@
|
|||||||
<td class="lines-num lines-num-old">
|
<td class="lines-num lines-num-old">
|
||||||
<div class="tw-flex">
|
<div class="tw-flex">
|
||||||
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
|
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
|
||||||
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
||||||
{{svg "octicon-fold-down"}}
|
{{svg "octicon-fold-down"}}
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}}
|
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}}
|
||||||
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
||||||
{{svg "octicon-fold-up"}}
|
{{svg "octicon-fold-up"}}
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if eq $line.GetExpandDirection 2}}
|
{{if eq $line.GetExpandDirection 2}}
|
||||||
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
||||||
{{svg "octicon-fold"}}
|
{{svg "octicon-fold"}}
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{{$file := .file}}
|
{{$file := .file}}
|
||||||
|
{{$blobExcerptRepoLink := or ctx.RootData.CommitRepoLink ctx.RootData.RepoLink}}
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col width="50">
|
<col width="50">
|
||||||
<col width="50">
|
<col width="50">
|
||||||
@ -14,17 +15,17 @@
|
|||||||
<td colspan="2" class="lines-num">
|
<td colspan="2" class="lines-num">
|
||||||
<div class="tw-flex">
|
<div class="tw-flex">
|
||||||
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
|
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
|
||||||
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
||||||
{{svg "octicon-fold-down"}}
|
{{svg "octicon-fold-down"}}
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}}
|
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}}
|
||||||
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
||||||
{{svg "octicon-fold-up"}}
|
{{svg "octicon-fold-up"}}
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if eq $line.GetExpandDirection 2}}
|
{{if eq $line.GetExpandDirection 2}}
|
||||||
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
|
||||||
{{svg "octicon-fold"}}
|
{{svg "octicon-fold"}}
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
<div class="ui top attached header">
|
||||||
<div class="ui compact small menu small-menu-items repo-editor-menu">
|
<div class="ui compact small menu small-menu-items repo-editor-menu">
|
||||||
<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a>
|
<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a>
|
||||||
<a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markup" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-markup-mode="file">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a>
|
<a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markup" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-markup-mode="file">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a>
|
||||||
@ -33,7 +34,9 @@
|
|||||||
<a class="item" data-tab="diff" hx-params="context,content" hx-vals='{"context":"{{.BranchLink}}"}' hx-include="#edit_area" hx-swap="innerHTML" hx-target=".tab[data-tab='diff']" hx-indicator=".tab[data-tab='diff']" hx-post="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a>
|
<a class="item" data-tab="diff" hx-params="context,content" hx-vals='{"context":"{{.BranchLink}}"}' hx-include="#edit_area" hx-swap="innerHTML" hx-target=".tab[data-tab='diff']" hx-indicator=".tab[data-tab='diff']" hx-post="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui active tab segment tw-rounded" data-tab="write">
|
</div>
|
||||||
|
<div class="ui bottom attached segment tw-p-0">
|
||||||
|
<div class="ui active tab tw-rounded" data-tab="write">
|
||||||
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
|
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
|
||||||
data-url="{{.Repository.Link}}/markup"
|
data-url="{{.Repository.Link}}/markup"
|
||||||
data-context="{{.RepoLink}}"
|
data-context="{{.RepoLink}}"
|
||||||
@ -41,13 +44,14 @@
|
|||||||
data-line-wrap-extensions="{{.LineWrapExtensions}}">{{.FileContent}}</textarea>
|
data-line-wrap-extensions="{{.LineWrapExtensions}}">{{.FileContent}}</textarea>
|
||||||
<div class="editor-loading is-loading"></div>
|
<div class="editor-loading is-loading"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui tab segment markup tw-rounded" data-tab="preview">
|
<div class="ui tab markup tw-px-4 tw-py-3" data-tab="preview">
|
||||||
{{ctx.Locale.Tr "loading"}}
|
{{ctx.Locale.Tr "loading"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui tab segment diff edit-diff" data-tab="diff">
|
<div class="ui tab diff edit-diff" data-tab="diff">
|
||||||
<div class="tw-p-16"></div>
|
<div class="tw-p-16"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{{template "repo/editor/commit_form" .}}
|
{{template "repo/editor/commit_form" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,9 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="issue-title-buttons">
|
<div class="issue-title-buttons">
|
||||||
<button class="ui small basic cancel button">{{ctx.Locale.Tr "repo.issues.cancel"}}</button>
|
<button class="ui small basic cancel button">{{ctx.Locale.Tr "repo.issues.cancel"}}</button>
|
||||||
<button class="ui small primary button"
|
<button class="ui small primary button" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title">
|
||||||
data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title"
|
|
||||||
{{if .Issue.IsPull}}data-target-update-url="{{$.RepoLink}}/pull/{{.Issue.Index}}/target_branch"{{end}}>
|
|
||||||
{{ctx.Locale.Tr "repo.issues.save"}}
|
{{ctx.Locale.Tr "repo.issues.save"}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -77,7 +75,7 @@
|
|||||||
{{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}}
|
{{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}}
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
<span id="pull-desc-editor" class="tw-hidden flex-text-block">
|
<span id="pull-desc-editor" class="tw-hidden flex-text-block" data-target-update-url="{{$.RepoLink}}/pull/{{.Issue.Index}}/target_branch">
|
||||||
<div class="ui floating filter dropdown">
|
<div class="ui floating filter dropdown">
|
||||||
<div class="ui basic small button tw-mr-0">
|
<div class="ui basic small button tw-mr-0">
|
||||||
<span class="text">{{ctx.Locale.Tr "repo.pulls.compare_compare"}}: {{$.HeadTarget}}</span>
|
<span class="text">{{ctx.Locale.Tr "repo.pulls.compare_compare"}}: {{$.HeadTarget}}</span>
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked readonly>
|
<input name="private" type="checkbox" checked disabled>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked readonly>
|
<input name="private" type="checkbox" checked disabled>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked readonly>
|
<input name="private" type="checkbox" checked disabled>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -101,7 +101,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked readonly>
|
<input name="private" type="checkbox" checked disabled>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}} checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}} checked{{end}}>
|
||||||
|
@ -103,7 +103,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked readonly>
|
<input name="private" type="checkbox" checked disabled>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -100,7 +100,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked readonly>
|
<input name="private" type="checkbox" checked disabled>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -103,7 +103,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked readonly>
|
<input name="private" type="checkbox" checked disabled>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}} checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}} checked{{end}}>
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked readonly>
|
<input name="private" type="checkbox" checked disabled>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -7,18 +7,18 @@
|
|||||||
<ul id="release-list">
|
<ul id="release-list">
|
||||||
{{range $idx, $info := .Releases}}
|
{{range $idx, $info := .Releases}}
|
||||||
{{$release := $info.Release}}
|
{{$release := $info.Release}}
|
||||||
<li class="ui grid">
|
<li class="release-entry">
|
||||||
<div class="ui four wide column meta">
|
<div class="meta">
|
||||||
<a class="muted" href="{{if not (and $release.Sha1 ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode))}}#{{else}}{{$.RepoLink}}/src/tag/{{$release.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "tw-mr-1"}}{{$release.TagName}}</a>
|
<a class="muted" href="{{if not (and $release.Sha1 ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode))}}#{{else}}{{$.RepoLink}}/src/tag/{{$release.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "tw-mr-1"}}{{$release.TagName}}</a>
|
||||||
{{if and $release.Sha1 ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}}
|
{{if and $release.Sha1 ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}}
|
||||||
<a class="muted tw-font-mono" href="{{$.RepoLink}}/src/commit/{{$release.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha $release.Sha1}}</a>
|
<a class="muted tw-font-mono" href="{{$.RepoLink}}/src/commit/{{$release.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha $release.Sha1}}</a>
|
||||||
{{template "repo/branch_dropdown" dict "root" $ "release" $release}}
|
{{template "repo/branch_dropdown" dict "root" $ "release" $release}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui twelve wide column detail">
|
<div class="ui segment detail">
|
||||||
<div class="tw-flex tw-items-center tw-justify-between tw-flex-wrap tw-mb-2">
|
<div class="tw-flex tw-items-center tw-justify-between tw-flex-wrap tw-mb-2">
|
||||||
<h4 class="release-list-title gt-word-break">
|
<h4 class="release-list-title gt-word-break">
|
||||||
{{if $.PageIsSingleTag}}{{$release.Title}}{{else}}<a href="{{$.RepoLink}}/releases/tag/{{$release.TagName | PathEscapeSegments}}">{{$release.Title}}</a>{{end}}
|
{{if $.PageIsSingleTag}}{{$release.Title}}{{else}}<a class="muted" href="{{$.RepoLink}}/releases/tag/{{$release.TagName | PathEscapeSegments}}">{{$release.Title}}</a>{{end}}
|
||||||
{{template "repo/commit_statuses" dict "Status" $info.CommitStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "tw-flex"}}
|
{{template "repo/commit_statuses" dict "Status" $info.CommitStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "tw-flex"}}
|
||||||
{{if $release.IsDraft}}
|
{{if $release.IsDraft}}
|
||||||
<span class="ui yellow label">{{ctx.Locale.Tr "repo.release.draft"}}</span>
|
<span class="ui yellow label">{{ctx.Locale.Tr "repo.release.draft"}}</span>
|
||||||
@ -62,22 +62,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<details class="download" {{if eq $idx 0}}open{{end}}>
|
<details class="download" {{if eq $idx 0}}open{{end}}>
|
||||||
<summary class="tw-my-4">
|
<summary>
|
||||||
{{ctx.Locale.Tr "repo.release.downloads"}}
|
{{ctx.Locale.Tr "repo.release.downloads"}}
|
||||||
</summary>
|
</summary>
|
||||||
<ul class="list">
|
<ul class="list">
|
||||||
{{if and (not $.DisableDownloadSourceArchives) (not $release.IsDraft) ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}}
|
{{if and (not $.DisableDownloadSourceArchives) (not $release.IsDraft) ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}}
|
||||||
<li>
|
<li>
|
||||||
<a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.zip" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.source_code"}} (ZIP)</strong></a>
|
<a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.zip" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "download-icon"}}{{ctx.Locale.Tr "repo.release.source_code"}} (ZIP)</strong></a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.source_code"}} (TAR.GZ)</strong></a>
|
<a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "download-icon"}}{{ctx.Locale.Tr "repo.release.source_code"}} (TAR.GZ)</strong></a>
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{range $release.Attachments}}
|
{{range $release.Attachments}}
|
||||||
<li>
|
<li>
|
||||||
<a target="_blank" rel="nofollow" href="{{.DownloadURL}}" download>
|
<a target="_blank" rel="nofollow" href="{{.DownloadURL}}" download>
|
||||||
<strong>{{svg "octicon-package" 16 "tw-mr-1"}}{{.Name}}</strong>
|
<strong>{{svg "octicon-package" 16 "download-icon"}}{{.Name}}</strong>
|
||||||
</a>
|
</a>
|
||||||
<div>
|
<div>
|
||||||
<span class="text grey">{{.Size | FileSize}}</span>
|
<span class="text grey">{{.Size | FileSize}}</span>
|
||||||
@ -89,7 +89,6 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<div class="dot"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui checkbox {{if .Err_IsWritable}}error{{end}}">
|
<div class="ui checkbox {{if .Err_IsWritable}}error{{end}}">
|
||||||
<input id="ssh-key-is-writable" name="is_writable" type="checkbox" value="1">
|
<input id="ssh-key-is-writable" name="is_writable" type="checkbox" value="1">
|
||||||
<label for="is_writable">
|
<label for="ssh-key-is-writable">
|
||||||
{{ctx.Locale.Tr "repo.settings.is_writable"}}
|
{{ctx.Locale.Tr "repo.settings.is_writable"}}
|
||||||
</label>
|
</label>
|
||||||
<small class="tw-pl-[26px]">{{ctx.Locale.Tr "repo.settings.is_writable_info"}}</small>
|
<small class="tw-pl-[26px]">{{ctx.Locale.Tr "repo.settings.is_writable_info"}}</small>
|
||||||
|
@ -30,7 +30,8 @@
|
|||||||
{{if .IsAdmin}}
|
{{if .IsAdmin}}
|
||||||
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}{{if and $.ForcePrivate .Repository.IsPrivate}} readonly{{end}}>
|
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}{{if and $.ForcePrivate .Repository.IsPrivate}} disabled{{end}}>
|
||||||
|
{{if and .Repository.IsPrivate $.ForcePrivate}}<input type="hidden" name="private" value="{{.Repository.IsPrivate}}">{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper"}} {{if .Repository.NumForks}}<span class="text red">{{ctx.Locale.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper"}} {{if .Repository.NumForks}}<span class="text red">{{ctx.Locale.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,12 +16,12 @@
|
|||||||
<tbody class="tag-list">
|
<tbody class="tag-list">
|
||||||
{{range $idx, $release := .Releases}}
|
{{range $idx, $release := .Releases}}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tag">
|
<td class="tag-list-row">
|
||||||
<h3 class="release-tag-name tw-mb-2">
|
<h3 class="tag-list-row-title tw-mb-2">
|
||||||
{{if $canReadReleases}}
|
{{if $canReadReleases}}
|
||||||
<a class="tw-flex tw-items-center" href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
|
<a class="tag-list-row-link tw-flex tw-items-center" href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="tw-flex tw-items-center" href="{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
|
<a class="tag-list-row-link tw-flex tw-items-center" href="{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="download tw-flex tw-items-center">
|
<div class="download tw-flex tw-items-center">
|
||||||
|
19
templates/swagger/v1_json.tmpl
generated
19
templates/swagger/v1_json.tmpl
generated
@ -12831,6 +12831,9 @@
|
|||||||
},
|
},
|
||||||
"409": {
|
"409": {
|
||||||
"$ref": "#/responses/error"
|
"$ref": "#/responses/error"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"$ref": "#/responses/validationError"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12949,8 +12952,8 @@
|
|||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
},
|
},
|
||||||
"405": {
|
"422": {
|
||||||
"$ref": "#/responses/empty"
|
"$ref": "#/responses/validationError"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13035,8 +13038,8 @@
|
|||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
},
|
},
|
||||||
"405": {
|
"422": {
|
||||||
"$ref": "#/responses/empty"
|
"$ref": "#/responses/validationError"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -13886,6 +13889,9 @@
|
|||||||
"409": {
|
"409": {
|
||||||
"$ref": "#/responses/conflict"
|
"$ref": "#/responses/conflict"
|
||||||
},
|
},
|
||||||
|
"422": {
|
||||||
|
"$ref": "#/responses/validationError"
|
||||||
|
},
|
||||||
"423": {
|
"423": {
|
||||||
"$ref": "#/responses/repoArchivedError"
|
"$ref": "#/responses/repoArchivedError"
|
||||||
}
|
}
|
||||||
@ -13979,6 +13985,9 @@
|
|||||||
"409": {
|
"409": {
|
||||||
"$ref": "#/responses/conflict"
|
"$ref": "#/responses/conflict"
|
||||||
},
|
},
|
||||||
|
"422": {
|
||||||
|
"$ref": "#/responses/validationError"
|
||||||
|
},
|
||||||
"423": {
|
"423": {
|
||||||
"$ref": "#/responses/repoArchivedError"
|
"$ref": "#/responses/repoArchivedError"
|
||||||
}
|
}
|
||||||
@ -20744,7 +20753,7 @@
|
|||||||
"x-go-name": "Description"
|
"x-go-name": "Description"
|
||||||
},
|
},
|
||||||
"enable_prune": {
|
"enable_prune": {
|
||||||
"description": "enable prune - remove obsolete remote-tracking references",
|
"description": "enable prune - remove obsolete remote-tracking references when mirroring",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "EnablePrune"
|
"x-go-name": "EnablePrune"
|
||||||
},
|
},
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
<input type="hidden" name="scope" value="{{.Scope}}">
|
<input type="hidden" name="scope" value="{{.Scope}}">
|
||||||
<input type="hidden" name="nonce" value="{{.Nonce}}">
|
<input type="hidden" name="nonce" value="{{.Nonce}}">
|
||||||
<input type="hidden" name="redirect_uri" value="{{.RedirectURI}}">
|
<input type="hidden" name="redirect_uri" value="{{.RedirectURI}}">
|
||||||
<button type="submit" id="authorize-app" value="{{ctx.Locale.Tr "auth.authorize_application"}}" class="ui red inline button">{{ctx.Locale.Tr "auth.authorize_application"}}</button>
|
<button type="submit" id="authorize-app" name="granted" value="true" class="ui red inline button">{{ctx.Locale.Tr "auth.authorize_application"}}</button>
|
||||||
<a href="{{.RedirectURI}}" class="ui basic primary inline button">Cancel</a>
|
<button type="submit" name="granted" value="false" class="ui basic primary inline button">{{ctx.Locale.Tr "cancel"}}</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/packages/maven"
|
"code.gitea.io/gitea/modules/packages/maven"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -241,4 +242,13 @@ func TestPackageMaven(t *testing.T) {
|
|||||||
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test", http.StatusCreated)
|
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test", http.StatusCreated)
|
||||||
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test-overwrite", http.StatusCreated)
|
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test-overwrite", http.StatusCreated)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("InvalidFile", func(t *testing.T) {
|
||||||
|
ver := packageVersion + "-invalid"
|
||||||
|
putFile(t, fmt.Sprintf("/%s/%s", ver, filename), "any invalid content", http.StatusCreated)
|
||||||
|
req := NewRequestf(t, "GET", "/%s/-/packages/maven/%s-%s/%s", user.Name, groupID, artifactID, ver)
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
assert.Contains(t, resp.Body.String(), "No metadata.")
|
||||||
|
assert.True(t, test.IsNormalPageCompleted(resp.Body.String()))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -154,6 +154,31 @@ func TestAPICreateAndUpdateRelease(t *testing.T) {
|
|||||||
assert.EqualValues(t, rel.Note, newRelease.Note)
|
assert.EqualValues(t, rel.Note, newRelease.Note)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPICreateProtectedTagRelease(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
|
writer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
||||||
|
session := loginUser(t, writer.LowerName)
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
|
||||||
|
gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer gitRepo.Close()
|
||||||
|
|
||||||
|
commit, err := gitRepo.GetBranchCommit("master")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/releases", repo.OwnerName, repo.Name), &api.CreateReleaseOption{
|
||||||
|
TagName: "v0.0.1",
|
||||||
|
Title: "v0.0.1",
|
||||||
|
IsDraft: false,
|
||||||
|
IsPrerelease: false,
|
||||||
|
Target: commit.ID.String(),
|
||||||
|
}).AddTokenAuth(token)
|
||||||
|
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAPICreateReleaseToDefaultBranch(t *testing.T) {
|
func TestAPICreateReleaseToDefaultBranch(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
@ -6,9 +6,14 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -118,3 +123,37 @@ func TestCompareBranches(t *testing.T) {
|
|||||||
|
|
||||||
inspectCompare(t, htmlDoc, diffCount, diffChanges)
|
inspectCompare(t, htmlDoc, diffCount, diffChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompareCodeExpand(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
|
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
|
repo, err := repo_service.CreateRepositoryDirectly(db.DefaultContext, user1, user1, repo_service.CreateRepoOptions{
|
||||||
|
Name: "test_blob_excerpt",
|
||||||
|
Readme: "Default",
|
||||||
|
AutoInit: true,
|
||||||
|
DefaultBranch: "main",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
session := loginUser(t, user1.Name)
|
||||||
|
testEditFile(t, session, user1.Name, repo.Name, "main", "README.md", strings.Repeat("a\n", 30))
|
||||||
|
|
||||||
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
session = loginUser(t, user2.Name)
|
||||||
|
testRepoFork(t, session, user1.Name, repo.Name, user2.Name, "test_blob_excerpt-fork")
|
||||||
|
testCreateBranch(t, session, user2.Name, "test_blob_excerpt-fork", "branch/main", "forked-branch", http.StatusSeeOther)
|
||||||
|
testEditFile(t, session, user2.Name, "test_blob_excerpt-fork", "forked-branch", "README.md", strings.Repeat("a\n", 15)+"CHANGED\n"+strings.Repeat("a\n", 15))
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", "/user1/test_blob_excerpt/compare/main...user2/test_blob_excerpt-fork:forked-branch")
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
els := htmlDoc.Find(`button.code-expander-button[hx-get]`)
|
||||||
|
|
||||||
|
// all the links in the comparison should be to the forked repo&branch
|
||||||
|
assert.NotZero(t, els.Length())
|
||||||
|
for i := 0; i < els.Length(); i++ {
|
||||||
|
link := els.Eq(i).AttrOr("hx-get", "")
|
||||||
|
assert.True(t, strings.HasPrefix(link, "/user2/test_blob_excerpt-fork/blob_excerpt/"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -9,13 +9,15 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
unit_model "code.gitea.io/gitea/models/unit"
|
unit_model "code.gitea.io/gitea/models/unit"
|
||||||
"code.gitea.io/gitea/modules/test"
|
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOrgProjectAccess(t *testing.T) {
|
func TestOrgProjectAccess(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
defer test.MockVariableValue(&unit_model.DisabledRepoUnits, append(slices.Clone(unit_model.DisabledRepoUnits), unit_model.TypeProjects))()
|
|
||||||
|
disabledRepoUnits := unit_model.DisabledRepoUnitsGet()
|
||||||
|
unit_model.DisabledRepoUnitsSet(append(slices.Clone(disabledRepoUnits), unit_model.TypeProjects))
|
||||||
|
defer unit_model.DisabledRepoUnitsSet(disabledRepoUnits)
|
||||||
|
|
||||||
// repo project, 404
|
// repo project, 404
|
||||||
req := NewRequest(t, "GET", "/user2/repo1/projects")
|
req := NewRequest(t, "GET", "/user2/repo1/projects")
|
||||||
|
@ -142,7 +142,7 @@ func TestViewReleaseListNoLogin(t *testing.T) {
|
|||||||
rsp := MakeRequest(t, req, http.StatusOK)
|
rsp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
htmlDoc := NewHTMLParser(t, rsp.Body)
|
htmlDoc := NewHTMLParser(t, rsp.Body)
|
||||||
releases := htmlDoc.Find("#release-list li.ui.grid")
|
releases := htmlDoc.Find("#release-list .release-entry")
|
||||||
assert.Equal(t, 5, releases.Length())
|
assert.Equal(t, 5, releases.Length())
|
||||||
|
|
||||||
links := make([]string, 0, 5)
|
links := make([]string, 0, 5)
|
||||||
@ -198,7 +198,7 @@ func TestViewReleaseListLogin(t *testing.T) {
|
|||||||
rsp := session.MakeRequest(t, req, http.StatusOK)
|
rsp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
htmlDoc := NewHTMLParser(t, rsp.Body)
|
htmlDoc := NewHTMLParser(t, rsp.Body)
|
||||||
releases := htmlDoc.Find("#release-list li.ui.grid")
|
releases := htmlDoc.Find("#release-list .release-entry")
|
||||||
assert.Equal(t, 3, releases.Length())
|
assert.Equal(t, 3, releases.Length())
|
||||||
|
|
||||||
links := make([]string, 0, 5)
|
links := make([]string, 0, 5)
|
||||||
@ -229,12 +229,12 @@ func TestViewTagsList(t *testing.T) {
|
|||||||
rsp := session.MakeRequest(t, req, http.StatusOK)
|
rsp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
htmlDoc := NewHTMLParser(t, rsp.Body)
|
htmlDoc := NewHTMLParser(t, rsp.Body)
|
||||||
tags := htmlDoc.Find(".tag-list tr")
|
tags := htmlDoc.Find(".tag-list-row-link")
|
||||||
assert.Equal(t, 3, tags.Length())
|
assert.Equal(t, 3, tags.Length())
|
||||||
|
|
||||||
tagNames := make([]string, 0, 5)
|
tagNames := make([]string, 0, 5)
|
||||||
tags.Each(func(i int, s *goquery.Selection) {
|
tags.Each(func(i int, s *goquery.Selection) {
|
||||||
tagNames = append(tagNames, s.Find(".tag a.tw-flex.tw-items-center").Text())
|
tagNames = append(tagNames, s.Text())
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.EqualValues(t, []string{"v1.0", "delete-tag", "v1.1"}, tagNames)
|
assert.EqualValues(t, []string{"v1.0", "delete-tag", "v1.1"}, tagNames)
|
||||||
|
@ -26,22 +26,10 @@ func TestCreateNewTagProtected(t *testing.T) {
|
|||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
t.Run("API", func(t *testing.T) {
|
t.Run("Code", func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
err := release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-1", "first tag")
|
err := release.CreateNewTag(git.DefaultContext, owner, repo, "master", "t-first", "first tag")
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
err = git_model.InsertProtectedTag(db.DefaultContext, &git_model.ProtectedTag{
|
|
||||||
RepoID: repo.ID,
|
|
||||||
NamePattern: "v-*",
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
err = git_model.InsertProtectedTag(db.DefaultContext, &git_model.ProtectedTag{
|
|
||||||
RepoID: repo.ID,
|
|
||||||
NamePattern: "v-1.1",
|
|
||||||
AllowlistUserIDs: []int64{repo.OwnerID},
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-2", "second tag")
|
err = release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-2", "second tag")
|
||||||
@ -54,13 +42,12 @@ func TestCreateNewTagProtected(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Git", func(t *testing.T) {
|
t.Run("Git", func(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
username := "user2"
|
httpContext := NewAPITestContext(t, owner.Name, repo.Name)
|
||||||
httpContext := NewAPITestContext(t, username, "repo1")
|
|
||||||
|
|
||||||
dstPath := t.TempDir()
|
dstPath := t.TempDir()
|
||||||
|
|
||||||
u.Path = httpContext.GitPath()
|
u.Path = httpContext.GitPath()
|
||||||
u.User = url.UserPassword(username, userPassword)
|
u.User = url.UserPassword(owner.Name, userPassword)
|
||||||
|
|
||||||
doGitClone(dstPath, u)(t)
|
doGitClone(dstPath, u)(t)
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user