mirror of
https://github.com/go-gitea/gitea
synced 2024-11-05 09:44:26 +00:00
Merge remote-tracking branch 'origin/main' into api-repo-actions
This commit is contained in:
commit
80a2c8ee38
@ -5,7 +5,7 @@
|
||||
2. Please ask questions or configuration/deploy problems on our Discord
|
||||
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
|
||||
3. Please take a moment to check that your issue doesn't already exist.
|
||||
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.io/en-us/faq)
|
||||
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
|
||||
5. Please give all relevant information below for bug reports, because
|
||||
incomplete details will be handled as an invalid report.
|
||||
-->
|
||||
@ -26,7 +26,7 @@
|
||||
- [ ] No
|
||||
- Log gist:
|
||||
<!-- It really is important to provide pertinent logs -->
|
||||
<!-- Please read https://docs.gitea.io/en-us/logging-configuration/#debugging-problems -->
|
||||
<!-- Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help -->
|
||||
<!-- In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini -->
|
||||
|
||||
## Description
|
||||
|
13
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
13
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
@ -1,6 +1,6 @@
|
||||
name: Bug Report
|
||||
description: Found something you weren't expecting? Report it here!
|
||||
labels: kind/bug
|
||||
labels: ["kind/bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
@ -14,12 +14,9 @@ body:
|
||||
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
|
||||
3. Make sure you are using the latest release and
|
||||
take a moment to check that your issue hasn't been reported before.
|
||||
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.io/en-us/faq)
|
||||
5. Please give all relevant information below for bug reports, because
|
||||
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
|
||||
5. It's really important to provide pertinent details and logs (https://docs.gitea.com/help/support),
|
||||
incomplete details will be handled as an invalid report.
|
||||
6. In particular it's really important to provide pertinent logs. You must give us DEBUG level logs.
|
||||
Please read https://docs.gitea.io/en-us/logging-configuration/#debugging-problems
|
||||
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
@ -50,7 +47,7 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
It's really important to provide pertinent logs
|
||||
Please read https://docs.gitea.io/en-us/logging-configuration/#debugging-problems
|
||||
Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help
|
||||
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
|
||||
- type: input
|
||||
id: logs
|
||||
@ -89,6 +86,6 @@ body:
|
||||
description: What database system are you running?
|
||||
options:
|
||||
- PostgreSQL
|
||||
- MySQL
|
||||
- MySQL/MariaDB
|
||||
- MSSQL
|
||||
- SQLite
|
||||
|
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -8,9 +8,9 @@ contact_links:
|
||||
about: Please ask questions and discuss configuration or deployment problems here.
|
||||
- name: Discourse Forum
|
||||
url: https://discourse.gitea.io
|
||||
about: Questions and configuration or deployment problems can also be discussed on our forum.
|
||||
about: Questions and configuration or deployment problems can also be discussed on our forum.
|
||||
- name: Frequently Asked Questions
|
||||
url: https://docs.gitea.io/en-us/faq
|
||||
url: https://docs.gitea.com/help/faq
|
||||
about: Please check if your question isn't mentioned here.
|
||||
- name: Crowdin Translations
|
||||
url: https://crowdin.com/project/gitea
|
||||
|
4
.github/ISSUE_TEMPLATE/ui.bug-report.yaml
vendored
4
.github/ISSUE_TEMPLATE/ui.bug-report.yaml
vendored
@ -13,12 +13,12 @@ body:
|
||||
2. Please ask questions or configuration/deploy problems on our Discord
|
||||
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
|
||||
3. Please take a moment to check that your issue doesn't already exist.
|
||||
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.io/en-us/faq)
|
||||
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
|
||||
5. Please give all relevant information below for bug reports, because
|
||||
incomplete details will be handled as an invalid report.
|
||||
6. In particular it's really important to provide pertinent logs. If you are certain that this is a javascript
|
||||
error, show us the javascript console. If the error appears to relate to Gitea the server you must also give us
|
||||
DEBUG level logs. (See https://docs.gitea.io/en-us/logging-configuration/#debugging-problems)
|
||||
DEBUG level logs. (See https://docs.gitea.com/administration/logging-config#collecting-logs-for-help)
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
10
.github/workflows/files-changed.yml
vendored
10
.github/workflows/files-changed.yml
vendored
@ -43,6 +43,8 @@ jobs:
|
||||
- "go.mod"
|
||||
- "go.sum"
|
||||
- "Makefile"
|
||||
- ".golangci.yml"
|
||||
- ".editorconfig"
|
||||
|
||||
frontend:
|
||||
- "**/*.js"
|
||||
@ -51,16 +53,21 @@ jobs:
|
||||
- "package.json"
|
||||
- "package-lock.json"
|
||||
- "Makefile"
|
||||
- ".eslintrc.yaml"
|
||||
- ".stylelintrc.yaml"
|
||||
- ".npmrc"
|
||||
|
||||
docs:
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
- ".markdownlint.yaml"
|
||||
|
||||
actions:
|
||||
- ".github/workflows/*"
|
||||
|
||||
templates:
|
||||
- "templates/**/*.tmpl"
|
||||
- "pyproject.toml"
|
||||
- "poetry.lock"
|
||||
|
||||
docker:
|
||||
@ -72,3 +79,6 @@ jobs:
|
||||
swagger:
|
||||
- "templates/swagger/v1_json.tmpl"
|
||||
- "Makefile"
|
||||
- "package.json"
|
||||
- "package-lock.json"
|
||||
- ".spectral.yml"
|
||||
|
@ -29,7 +29,7 @@ linters:
|
||||
fast: false
|
||||
|
||||
run:
|
||||
go: "1.20"
|
||||
go: "1.21"
|
||||
timeout: 10m
|
||||
skip-dirs:
|
||||
- node_modules
|
||||
@ -75,7 +75,7 @@ linters-settings:
|
||||
- name: modifies-value-receiver
|
||||
gofumpt:
|
||||
extra-rules: true
|
||||
lang-version: "1.20"
|
||||
lang-version: "1.21"
|
||||
depguard:
|
||||
rules:
|
||||
main:
|
||||
|
@ -60,7 +60,7 @@
|
||||
## Introduction
|
||||
|
||||
This document explains how to contribute changes to the Gitea project. \
|
||||
It assumes you have followed the [installation instructions](https://docs.gitea.io/en-us/). \
|
||||
It assumes you have followed the [installation instructions](https://docs.gitea.com/category/installation). \
|
||||
Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io).
|
||||
|
||||
For configuring IDEs for Gitea development, see the [contributed IDE configurations](contrib/ide/).
|
||||
|
@ -79,14 +79,14 @@ or if SQLite support is required:
|
||||
|
||||
The `build` target is split into two sub-targets:
|
||||
|
||||
- `make backend` which requires [Go Stable](https://go.dev/dl/), required version is defined in [go.mod](/go.mod).
|
||||
- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and Internet connectivity to download npm dependencies.
|
||||
- `make backend` which requires [Go Stable](https://go.dev/dl/), the required version is defined in [go.mod](/go.mod).
|
||||
- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater.
|
||||
|
||||
When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js and Internet connectivity.
|
||||
Internet connectivity is required to download the go and npm modules. When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js.
|
||||
|
||||
Parallelism (`make -j <num>`) is not supported.
|
||||
|
||||
More info: https://docs.gitea.io/en-us/install-from-source/
|
||||
More info: https://docs.gitea.com/installation/install-from-source
|
||||
|
||||
## Using
|
||||
|
||||
|
@ -68,7 +68,7 @@ Gitea 的首要目标是创建一个极易安装,运行非常快速,安装
|
||||
|
||||
## 文档
|
||||
|
||||
关于如何安装请访问我们的 [文档站](https://docs.gitea.io/zh-cn/),如果没有找到对应的文档,你也可以通过 [Discord - 英文](https://discord.gg/gitea) 和 QQ群 328432459 来和我们交流。
|
||||
关于如何安装请访问我们的 [文档站](https://docs.gitea.com/zh-cn/category/installation),如果没有找到对应的文档,你也可以通过 [Discord - 英文](https://discord.gg/gitea) 和 QQ群 328432459 来和我们交流。
|
||||
|
||||
## 贡献流程
|
||||
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
@ -58,7 +59,7 @@ func main() {
|
||||
|
||||
// use old en-US as the base, and copy the new translations to the old locales
|
||||
enUsOld := inisOld["options/locale/locale_en-US.ini"]
|
||||
brokenWarned := map[string]bool{}
|
||||
brokenWarned := make(container.Set[string])
|
||||
for path, iniOld := range inisOld {
|
||||
if iniOld == enUsOld {
|
||||
continue
|
||||
@ -77,7 +78,7 @@ func main() {
|
||||
broken := oldStr != "" && strings.Count(oldStr, "%") != strings.Count(newStr, "%")
|
||||
broken = broken || strings.Contains(oldStr, "\n") || strings.Contains(oldStr, "\n")
|
||||
if broken {
|
||||
brokenWarned[secOld.Name()+"."+keyEnUs.Name()] = true
|
||||
brokenWarned.Add(secOld.Name() + "." + keyEnUs.Name())
|
||||
fmt.Println("----")
|
||||
fmt.Printf("WARNING: skip broken locale: %s , [%s] %s\n", path, secEnUS.Name(), keyEnUs.Name())
|
||||
fmt.Printf("\told: %s\n", strings.ReplaceAll(oldStr, "\n", "\\n"))
|
||||
@ -103,7 +104,7 @@ func main() {
|
||||
broken = broken || strings.HasPrefix(str, "`\"")
|
||||
broken = broken || strings.Count(str, `"`)%2 == 1
|
||||
broken = broken || strings.Count(str, "`")%2 == 1
|
||||
if broken && !brokenWarned[sec.Name()+"."+key.Name()] {
|
||||
if broken && !brokenWarned.Contains(sec.Name()+"."+key.Name()) {
|
||||
fmt.Printf("WARNING: found broken locale: %s , [%s] %s\n", path, sec.Name(), key.Name())
|
||||
fmt.Printf("\tstr: %s\n", strings.ReplaceAll(str, "\n", "\\n"))
|
||||
fmt.Println("----")
|
||||
|
@ -15,6 +15,8 @@ import (
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
)
|
||||
|
||||
// regexp is based on go-license, excluding README and NOTICE
|
||||
@ -55,20 +57,14 @@ func main() {
|
||||
// yml
|
||||
//
|
||||
// It could be removed once we have a better regex.
|
||||
excludedExt := map[string]bool{
|
||||
".gitignore": true,
|
||||
".go": true,
|
||||
".mod": true,
|
||||
".sum": true,
|
||||
".toml": true,
|
||||
".yml": true,
|
||||
}
|
||||
excludedExt := container.SetOf(".gitignore", ".go", ".mod", ".sum", ".toml", ".yml")
|
||||
|
||||
var paths []string
|
||||
err := filepath.WalkDir(base, func(path string, entry fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if entry.IsDir() || !licenseRe.MatchString(entry.Name()) || excludedExt[filepath.Ext(entry.Name())] {
|
||||
if entry.IsDir() || !licenseRe.MatchString(entry.Name()) || excludedExt.Contains(filepath.Ext(entry.Name())) {
|
||||
return nil
|
||||
}
|
||||
paths = append(paths, path)
|
||||
|
@ -43,7 +43,7 @@ Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "rsa-bits",
|
||||
Value: 2048,
|
||||
Value: 3072,
|
||||
Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
|
@ -7,7 +7,7 @@
|
||||
dashboardTimezone: 'default',
|
||||
dashboardRefresh: '1m',
|
||||
|
||||
// please see https://docs.gitea.io/en-us/config-cheat-sheet/#metrics-metrics
|
||||
// please see https://docs.gitea.com/administration/config-cheat-sheet#metrics-metrics
|
||||
// Show issue by repository metrics with format gitea_issues_by_repository{repository="org/repo"} 5.
|
||||
// Requires Gitea 1.16.0 with ENABLED_ISSUE_BY_REPOSITORY set to true.
|
||||
showIssuesByRepository: true,
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
<h3>With your Consent</h3>
|
||||
|
||||
<p>We share your User Personal Information, if you consent, after letting you know what information will be shared, with whom, and why. For example, if you allow third party applications to access your Account using <a href="https://docs.gitea.io/en-us/oauth2-provider/">OAuth2 providers</a>, we share all information associated with your Account, including private repos and organizations. You may also direct us through your action on Your Gitea Instance to share your User Personal Information, such as when joining an Organization.</p>
|
||||
<p>We share your User Personal Information, if you consent, after letting you know what information will be shared, with whom, and why. For example, if you allow third party applications to access your Account using <a href="https://docs.gitea.com/development/oauth2-provider">OAuth2 providers</a>, we share all information associated with your Account, including private repos and organizations. You may also direct us through your action on Your Gitea Instance to share your User Personal Information, such as when joining an Organization.</p>
|
||||
|
||||
<h3>With Service Providers</h3>
|
||||
|
||||
@ -144,7 +144,7 @@
|
||||
|
||||
<h3>Data Portability</h3>
|
||||
|
||||
<p>As a Your Gitea Instance User, you can always take your data with you. You can clone your repositories to your computer, or you can <a href="https://docs.gitea.io/en-us/migrations-interfaces/">perform migrations using the provided interfaces</a>, for example.</p>
|
||||
<p>As a Your Gitea Instance User, you can always take your data with you. You can clone your repositories to your computer, or you can <a href="https://docs.gitea.com/development/migrations-interfaces">perform migrations using the provided interfaces</a>, for example.</p>
|
||||
|
||||
<h3>Data Retention and Deletion of Data</h3>
|
||||
|
||||
@ -183,7 +183,7 @@
|
||||
|
||||
<h2>Changes to this Privacy Policy</h2>
|
||||
|
||||
<p>Although most changes are likely to be minor, Your Gitea Instance may change our Privacy Statement from time to time. We will provide notification to Users of material changes to this Privacy Statement through our Website at least 30 days prior to the change taking effect by posting a notice on our home page or sending email to the primary email address specified in your account.</p>
|
||||
<p>Although most changes are likely to be minor, Your Gitea Instance may change our Privacy Statement from time to time. We will provide notification to Users of material changes to this Privacy Statement through our Website at least 30 days prior to the change taking effect by posting a notice on our home page or sending email to the primary email address specified in your account.</p>
|
||||
|
||||
<h2>Contact</h2>
|
||||
|
||||
|
@ -1339,7 +1339,7 @@ LEVEL = Info
|
||||
;; Define allowed algorithms and their minimum key length (use -1 to disable a type)
|
||||
;ED25519 = 256
|
||||
;ECDSA = 256
|
||||
;RSA = 2047 ; we allow 2047 here because an otherwise valid 2048 bit RSA key can be reported as having 2047 bit length
|
||||
;RSA = 3071 ; we allow 3071 here because an otherwise valid 3072 bit RSA key can be reported as having 3071 bit length
|
||||
;DSA = -1 ; set to 1024 to switch on
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -4,4 +4,4 @@ Dockerfile is found in root of repository.
|
||||
|
||||
Docker image can be found on [docker hub](https://hub.docker.com/r/gitea/gitea)
|
||||
|
||||
Documentation on using docker image can be found on [Gitea Docs site](https://docs.gitea.io/en-us/install-with-docker/)
|
||||
Documentation on using docker image can be found on [Gitea Docs site](https://docs.gitea.com/installation/install-with-docker-rootless)
|
||||
|
@ -11,7 +11,7 @@ fi
|
||||
|
||||
if [ ! -f /data/ssh/ssh_host_rsa_key ]; then
|
||||
echo "Generating /data/ssh/ssh_host_rsa_key..."
|
||||
ssh-keygen -t rsa -b 2048 -f /data/ssh/ssh_host_rsa_key -N "" > /dev/null
|
||||
ssh-keygen -t rsa -b 3072 -f /data/ssh/ssh_host_rsa_key -N "" > /dev/null
|
||||
fi
|
||||
|
||||
if [ ! -f /data/ssh/ssh_host_ecdsa_key ]; then
|
||||
|
@ -313,7 +313,7 @@ directory and will overwrite any existing files.
|
||||
- `--ecdsa-curve value`: ECDSA curve to use to generate a key. Optional. Valid options
|
||||
are P224, P256, P384, P521.
|
||||
- `--rsa-bits value`: Size of RSA key to generate. Optional. Ignored if --ecdsa-curve is
|
||||
set. (default: 2048).
|
||||
set. (default: 3072).
|
||||
- `--start-date value`: Creation date. Optional. (format: `Jan 1 15:04:05 2011`).
|
||||
- `--duration value`: Duration which the certificate is valid for. Optional. (default: 8760h0m0s)
|
||||
- `--ca`: If provided, this cert generates it's own certificate authority. Optional.
|
||||
|
@ -295,7 +295,7 @@ menu:
|
||||
- 选项:
|
||||
- `--host value`:逗号分隔的主机名和IP地址列表,此证书适用于这些主机。支持使用通配符。必填。
|
||||
- `--ecdsa-curve value`:用于生成密钥的ECDSA曲线。可选。有效选项为P224、P256、P384、P521。
|
||||
- `--rsa-bits value`:要生成的RSA密钥的大小。可选。如果设置了--ecdsa-curve,则忽略此选项。(默认值:2048)。
|
||||
- `--rsa-bits value`:要生成的RSA密钥的大小。可选。如果设置了--ecdsa-curve,则忽略此选项。(默认值:3072)。
|
||||
- `--start-date value`:证书的创建日期。可选。(格式:`Jan 1 15:04:05 2011`)。
|
||||
- `--duration value`:证书有效期。可选。(默认值:8760h0m0s)
|
||||
- `--ca`:如果提供此选项,则证书将生成自己的证书颁发机构。可选。
|
||||
|
@ -681,7 +681,7 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
|
||||
|
||||
- `ED25519`: **256**
|
||||
- `ECDSA`: **256**
|
||||
- `RSA`: **2047**: We set 2047 here because an otherwise valid 2048 RSA key can be reported as 2047 length.
|
||||
- `RSA`: **3071**: We set 3071 here because an otherwise valid 3072 RSA key can be reported as 3071 length.
|
||||
- `DSA`: **-1**: DSA is now disabled by default. Set to **1024** to re-enable but ensure you may need to reconfigure your SSHD provider
|
||||
|
||||
## Webhook (`webhook`)
|
||||
|
@ -648,7 +648,7 @@ Gitea 创建以下非唯一队列:
|
||||
|
||||
- `ED25519`:**256**
|
||||
- `ECDSA`:**256**
|
||||
- `RSA`:**2047**:我们在这里设置为2047,因为一个其他方面有效的2048 RSA密钥可能被报告为2047长度。
|
||||
- `RSA`:**3071**:我们在这里设置为2047,因为一个其他方面有效的3072 RSA密钥可能被报告为3071长度。
|
||||
- `DSA`:**-1**:默认情况下禁用DSA。设置为**1024**以重新启用,但请注意可能需要重新配置您的SSHD提供者
|
||||
|
||||
## Webhook (`webhook`)
|
||||
|
@ -36,7 +36,7 @@ Application settings can be found in file `CustomConf` which is by default,
|
||||
Again `gitea help` will allow you review this variable and you can override it using the
|
||||
`--config` option on the `gitea` binary.
|
||||
|
||||
- [Quick Cheat Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/)
|
||||
- [Quick Cheat Sheet](administration/config-cheat-sheet.md)
|
||||
- [Complete List](https://github.com/go-gitea/gitea/blob/main/custom/conf/app.example.ini)
|
||||
|
||||
If the `CustomPath` folder can't be found despite checking `gitea help`, check the `GITEA_CUSTOM`
|
||||
@ -44,7 +44,7 @@ environment variable; this can be used to override the default path to something
|
||||
`GITEA_CUSTOM` might, for example, be set by an init script. You can check whether the value
|
||||
is set under the "Configuration" tab on the site administration page.
|
||||
|
||||
- [List of Environment Variables](https://docs.gitea.io/en-us/environment-variables/)
|
||||
- [List of Environment Variables](administration/environment-variables.md)
|
||||
|
||||
**Note:** Gitea must perform a full restart to see configuration changes.
|
||||
|
||||
@ -84,7 +84,7 @@ for C++ repositories, we want to replace `options/gitignore/C++`. To do this, a
|
||||
must be placed in `$GITEA_CUSTOM/options/gitignore/C++` (see about the location of the `CustomPath`
|
||||
directory at the top of this document).
|
||||
|
||||
Every single page of Gitea can be changed. Dynamic content is generated using [go templates](https://golang.org/pkg/html/template/),
|
||||
Every single page of Gitea can be changed. Dynamic content is generated using [go templates](https://pkg.go.dev/html/template),
|
||||
which can be modified by placing replacements below the `$GITEA_CUSTOM/templates` directory.
|
||||
|
||||
To obtain any embedded file (including templates), the [`gitea embedded` tool](administration/cmd-embedded.md) can be used. Alternatively, they can be found in the [`templates`](https://github.com/go-gitea/gitea/tree/main/templates) directory of Gitea source (Note: the example link is from the `main` branch. Make sure to use templates compatible with the release you are using).
|
||||
@ -108,7 +108,7 @@ just place it under your "$GITEA_CUSTOM/public/assets/" directory (for instance
|
||||
To match the current style, the link should have the class name "item", and you can use `{{AppSubUrl}}` to get the base URL:
|
||||
`<a class="item" href="{{AppSubUrl}}/assets/impressum.html">Impressum</a>`
|
||||
|
||||
For more information, see [Adding Legal Pages](https://docs.gitea.io/en-us/adding-legal-pages).
|
||||
For more information, see [Adding Legal Pages](administration/adding-legal-pages.md).
|
||||
|
||||
You can add new tabs in the same way, putting them in `extra_tabs.tmpl`.
|
||||
The exact HTML needed to match the style of other tabs is in the file
|
||||
@ -371,10 +371,10 @@ A full list of supported emoji's is at [emoji list](https://gitea.com/gitea/gite
|
||||
## Customizing the look of Gitea
|
||||
|
||||
The default built-in themes are `gitea` (light), `arc-green` (dark), and `auto` (chooses light or dark depending on operating system settings).
|
||||
The default theme can be changed via `DEFAULT_THEME` in the [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) section of `app.ini`.
|
||||
The default theme can be changed via `DEFAULT_THEME` in the [ui](administration/config-cheat-sheet.md#ui-ui) section of `app.ini`.
|
||||
|
||||
Gitea also has support for user themes, which means every user can select which theme should be used.
|
||||
The list of themes a user can choose from can be configured with the `THEMES` value in the [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) section of `app.ini`.
|
||||
The list of themes a user can choose from can be configured with the `THEMES` value in the [ui](administration/config-cheat-sheet.md#ui-ui) section of `app.ini`.
|
||||
|
||||
To make a custom theme available to all users:
|
||||
|
||||
|
@ -23,13 +23,13 @@ Gitea 引用 `custom` 目录中的自定义配置文件来覆盖配置、模板
|
||||
将会自动创建包括 `custom/` 在内的必要应用目录,应用本身的配置存放在
|
||||
`custom/conf/app.ini` 当中。在发行版中可能会以 `/etc/gitea/` 的形式为 `custom` 设置一个符号链接,查看配置详情请移步:
|
||||
|
||||
- [快速备忘单](https://docs.gitea.io/en-us/config-cheat-sheet/)
|
||||
- [快速备忘单](administration/config-cheat-sheet.md)
|
||||
- [完整配置清单](https://github.com/go-gitea/gitea/blob/main/custom/conf/app.example.ini)
|
||||
|
||||
如果您在 binary 同目录下无法找到 `custom` 文件夹,请检查您的 `GITEA_CUSTOM`
|
||||
环境变量配置, 因为它可能被配置到了其他地方(可能被一些启动脚本设置指定了目录)。
|
||||
|
||||
- [环境变量清单](https://docs.gitea.io/en-us/specific-variables/)
|
||||
- [环境变量清单](administration/environment-variables.md)
|
||||
|
||||
**注:** 必须完全重启 Gitea 以使配置生效。
|
||||
|
||||
@ -87,4 +87,4 @@ Gitea 引用 `custom` 目录中的自定义配置文件来覆盖配置、模板
|
||||
## 更改 Gitea 外观
|
||||
|
||||
Gitea 目前由两种内置主题,分别为默认 `gitea` 主题和深色主题 `arc-green`,您可以通过修改
|
||||
`app.ini` [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) 部分的 `DEFAULT_THEME` 的值来变更至一个可用的 Gitea 外观。
|
||||
`app.ini` [ui](administration/config-cheat-sheet.md#ui-ui) 部分的 `DEFAULT_THEME` 的值来变更至一个可用的 Gitea 外观。
|
||||
|
@ -119,7 +119,7 @@ proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
The security options in `app.ini` need to be adjusted to allow the interpretation of the headers
|
||||
as well as the list of IP addresses and networks that describe trusted proxy servers
|
||||
(See the [configuration cheat sheet](https://docs.gitea.io/en-us/config-cheat-sheet/#security-security) for more information).
|
||||
(See the [configuration cheat sheet](administration/config-cheat-sheet.md#security-security) for more information).
|
||||
|
||||
```
|
||||
REVERSE_PROXY_LIMIT = 1
|
||||
|
@ -91,4 +91,4 @@ REVERSE_PROXY_TRUSTED_PROXIES = 127.0.0.0/8,::1/128
|
||||
`REVERSE_PROXY_LIMIT` 限制反向代理服务器的层数,设置为 `0` 表示不使用这些标头。
|
||||
`REVERSE_PROXY_TRUSTED_PROXIES` 表示受信任的反向代理服务器网络地址,
|
||||
经过该网络地址转发来的流量会经过解析 `X-Real-IP` 头部得到真实客户端地址。
|
||||
(参考 [configuration cheat sheet](https://docs.gitea.io/en-us/config-cheat-sheet/#security-security))
|
||||
(参考 [configuration cheat sheet](administration/config-cheat-sheet.md#security-security))
|
||||
|
@ -18,7 +18,7 @@ menu:
|
||||
# Mail templates
|
||||
|
||||
To craft the e-mail subject and contents for certain operations, Gitea can be customized by using templates. The templates
|
||||
for these functions are located under the [`custom` directory](https://docs.gitea.io/en-us/customizing-gitea/).
|
||||
for these functions are located under the [`custom` directory](administration/customizing-gitea.md).
|
||||
Gitea has an internal template that serves as default in case there's no custom alternative.
|
||||
|
||||
Custom templates are loaded when Gitea starts. Changes made to them are not recognized until Gitea is restarted again.
|
||||
@ -165,7 +165,7 @@ If the template fails to render, it will be noticed only at the moment the mail
|
||||
A default subject is used if the subject template fails, and whatever was rendered successfully
|
||||
from the the _mail body_ is used, disregarding the rest.
|
||||
|
||||
Please check [Gitea's logs](https://docs.gitea.io/en-us/logging-configuration/) for error messages in case of trouble.
|
||||
Please check [Gitea's logs](administration/logging-config.md) for error messages in case of trouble.
|
||||
|
||||
## Example
|
||||
|
||||
|
@ -17,7 +17,7 @@ menu:
|
||||
|
||||
# 邮件模板
|
||||
|
||||
为了定制特定操作的电子邮件主题和内容,可以使用模板来自定义 Gitea。这些功能的模板位于 [`custom` 目录](https://docs.gitea.io/en-us/customizing-gitea/) 下。
|
||||
为了定制特定操作的电子邮件主题和内容,可以使用模板来自定义 Gitea。这些功能的模板位于 [`custom` 目录](administration/customizing-gitea.md) 下。
|
||||
如果没有自定义的替代方案,Gitea 将使用内部模板作为默认模板。
|
||||
|
||||
自定义模板在 Gitea 启动时加载。对它们的更改在 Gitea 重新启动之前不会被识别。
|
||||
@ -148,7 +148,7 @@ _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://golang.org/pkg/t
|
||||
如果模板无法呈现,则只有在发送邮件时才会注意到。
|
||||
如果主题模板失败,将使用默认主题,如果从 _邮件正文_ 中成功呈现了任何内容,则将使用该内容,忽略其他内容。
|
||||
|
||||
如果遇到问题,请检查 [Gitea的日志](https://docs.gitea.io/en-us/logging-configuration/) 以获取错误消息。
|
||||
如果遇到问题,请检查 [Gitea的日志](administration/logging-config.md) 以获取错误消息。
|
||||
|
||||
## 示例
|
||||
|
||||
|
@ -19,7 +19,7 @@ menu:
|
||||
|
||||
## Setting up the repository indexer
|
||||
|
||||
Gitea can search through the files of the repositories by enabling this function in your [`app.ini`](https://docs.gitea.io/en-us/config-cheat-sheet/):
|
||||
Gitea can search through the files of the repositories by enabling this function in your [`app.ini`](administration/config-cheat-sheet.md):
|
||||
|
||||
```ini
|
||||
[indexer]
|
||||
|
@ -19,7 +19,7 @@ menu:
|
||||
|
||||
## 设置仓库索引器
|
||||
|
||||
通过在您的 [`app.ini`](https://docs.gitea.io/en-us/config-cheat-sheet/) 中启用此功能,Gitea 可以通过仓库的文件进行搜索:
|
||||
通过在您的 [`app.ini`](administration/config-cheat-sheet.md) 中启用此功能,Gitea 可以通过仓库的文件进行搜索:
|
||||
|
||||
```ini
|
||||
[indexer]
|
||||
|
@ -21,7 +21,7 @@ menu:
|
||||
|
||||
By default, `ENABLE_SWAGGER` is true, and
|
||||
`MAX_RESPONSE_ITEMS` is set to 50. See [Config Cheat
|
||||
Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/) for more
|
||||
Sheet](administration/config-cheat-sheet.md) for more
|
||||
information.
|
||||
|
||||
## Authentication
|
||||
@ -76,7 +76,7 @@ interface: `Settings | Applications | Generate New Token`.
|
||||
|
||||
## OAuth2 Provider
|
||||
|
||||
Access tokens obtained from Gitea's [OAuth2 provider](https://docs.gitea.io/en-us/oauth2-provider) are accepted by these methods:
|
||||
Access tokens obtained from Gitea's [OAuth2 provider](development/oauth2-provider.md) are accepted by these methods:
|
||||
|
||||
- `Authorization bearer ...` header in HTTP headers
|
||||
- `token=...` parameter in URL query string
|
||||
|
@ -20,7 +20,7 @@ menu:
|
||||
## 开启/配置 API 访问
|
||||
|
||||
通常情况下, `ENABLE_SWAGGER` 默认开启并且参数 `MAX_RESPONSE_ITEMS` 默认为 50。您可以从 [Config Cheat
|
||||
Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/) 中获取更多配置相关信息。
|
||||
Sheet](administration/config-cheat-sheet.md) 中获取更多配置相关信息。
|
||||
|
||||
## 通过 API 认证
|
||||
|
||||
|
@ -148,7 +148,7 @@ For public clients, a redirect URI of a loopback IP address such as `http://127.
|
||||
|
||||
The `REDIRECT_URI` in the `access_token` request must match the `REDIRECT_URI` in the `authorize` request.
|
||||
|
||||
3. Use the `access_token` to make [API requests](https://docs.gitea.io/en-us/api-usage#oauth2) to access the user's resources.
|
||||
3. Use the `access_token` to make [API requests](development/api-usage.md#oauth2-provider) to access the user's resources.
|
||||
|
||||
### Public client (PKCE)
|
||||
|
||||
@ -210,4 +210,4 @@ After you have generated this values, you can continue with your request.
|
||||
|
||||
The `REDIRECT_URI` in the `access_token` request must match the `REDIRECT_URI` in the `authorize` request.
|
||||
|
||||
3. Use the `access_token` to make [API requests](https://docs.gitea.io/en-us/api-usage#oauth2) to access the user's resources.
|
||||
3. Use the `access_token` to make [API requests](development/api-usage.md#oauth2-provider) to access the user's resources.
|
||||
|
@ -134,4 +134,4 @@ Gitea 支持私密和公共客户端类型,[参见 RFC 6749](https://datatrack
|
||||
|
||||
`access_token` 请求中的 `REDIRECT_URI` 必须与 `authorize` 请求中的 `REDIRECT_URI` 相符。
|
||||
|
||||
3. 使用 `access_token` 来构造 [API 请求](https://docs.gitea.io/en-us/api-usage#oauth2) 以读写用户的资源。
|
||||
3. 使用 `access_token` 来构造 [API 请求](development/api-usage.md#oauth2-provider) 以读写用户的资源。
|
||||
|
@ -93,4 +93,4 @@ Gitea 支援作為 OAuth2 提供者,能讓第三方程式能在使用者同意
|
||||
|
||||
`access_token` 請求中的 `REDIRECT_URI` 必須符合 `authorize` 請求中的 `REDIRECT_URI`。
|
||||
|
||||
1. 發送 [API requests](https://docs.gitea.io/en-us/api-usage#oauth2) 時使用 `access_token` 以存取使用者的資源。
|
||||
1. 發送 [API requests](development/api-usage.md#oauth2-provider) 時使用 `access_token` 以存取使用者的資源。
|
||||
|
@ -22,34 +22,57 @@ menu:
|
||||
- [Discourse Forum](https://discourse.gitea.io/)
|
||||
- [Matrix](https://matrix.to/#/#gitea-space:matrix.org)
|
||||
- NOTE: Most of the Matrix channels are bridged with their counterpart in Discord and may experience some degree of flakiness with the bridge process.
|
||||
- Chinese Support
|
||||
- [Discourse Chinese Category](https://discourse.gitea.io/c/5-category/5)
|
||||
- QQ Group 328432459
|
||||
|
||||
# Bug Report
|
||||
|
||||
If you found a bug, please [create an issue on GitHub](https://github.com/go-gitea/gitea/issues).
|
||||
|
||||
**NOTE:** When asking for support, it may be a good idea to have the following available so that the person helping has all the info they need:
|
||||
|
||||
1. Your `app.ini` (with any sensitive data scrubbed as necessary).
|
||||
2. The Gitea logs, and any other appropriate log files for the situation.
|
||||
- When using systemd, use `journalctl --lines 1000 --unit gitea` to collect logs.
|
||||
- When using docker, use `docker logs --tail 1000 <gitea-container>` to collect logs.
|
||||
- By default, the logs are outputted to console. If you need to collect logs from files,
|
||||
you could copy the following config into your `app.ini` (remove all other `[log]` sections),
|
||||
then you can find the `*.log` files in Gitea's log directory (default: `%(GITEA_WORK_DIR)/log`).
|
||||
|
||||
```ini
|
||||
; To show all SQL logs, you can also set LOG_SQL=true in the [database] section
|
||||
[log]
|
||||
LEVEL=debug
|
||||
MODE=console,file
|
||||
```
|
||||
|
||||
3. Any error messages you are seeing.
|
||||
4. When possible, try to replicate the issue on [try.gitea.io](https://try.gitea.io) and include steps so that others can reproduce the issue.
|
||||
- This will greatly improve the chance that the root of the issue can be quickly discovered and resolved.
|
||||
5. If you encounter slow/hanging/deadlock problems, please report the stack trace when the problem occurs.
|
||||
2. Any error messages you are seeing.
|
||||
3. The Gitea logs, and all other related logs for the situation.
|
||||
- It's more useful to collect `trace` / `debug` level logs (see the next section).
|
||||
- When using systemd, use `journalctl --lines 1000 --unit gitea` to collect logs.
|
||||
- When using docker, use `docker logs --tail 1000 <gitea-container>` to collect logs.
|
||||
4. Reproducible steps so that others could reproduce and understand the problem more quickly and easily.
|
||||
- [try.gitea.io](https://try.gitea.io) could be used to reproduce the problem.
|
||||
5. If you encounter slow/hanging/deadlock problems, please report the stacktrace when the problem occurs.
|
||||
Go to the "Site Admin" -> "Monitoring" -> "Stacktrace" -> "Download diagnosis report".
|
||||
|
||||
## Bugs
|
||||
# Advanced Bug Report Tips
|
||||
|
||||
If you found a bug, please create an [issue on GitHub](https://github.com/go-gitea/gitea/issues).
|
||||
## More Config Options for Logs
|
||||
|
||||
## Chinese Support
|
||||
By default, the logs are outputted to console with `info` level.
|
||||
If you need to set log level and/or collect logs from files,
|
||||
you could just copy the following config into your `app.ini` (remove all other `[log]` sections),
|
||||
then you will find the `*.log` files in Gitea's log directory (default: `%(GITEA_WORK_DIR)/log`).
|
||||
|
||||
Support for the Chinese language is provided at [Our discourse](https://discourse.gitea.io/c/5-category/5) or QQ Group 328432459.
|
||||
```ini
|
||||
; To show all SQL logs, you can also set LOG_SQL=true in the [database] section
|
||||
[log]
|
||||
LEVEL=debug
|
||||
MODE=console,file
|
||||
```
|
||||
|
||||
## Collecting Stacktrace by Command Line
|
||||
|
||||
Gitea could use Golang's pprof handler and toolchain to collect stacktrace and other runtime information.
|
||||
|
||||
If the web UI stops working, you could try to collect the stacktrace by command line:
|
||||
|
||||
1. Set `app.ini`:
|
||||
|
||||
```
|
||||
[server]
|
||||
ENABLE_PPROF = true
|
||||
```
|
||||
|
||||
2. Restart Gitea
|
||||
|
||||
3. Try to trigger the bug, when the requests get stuck for a while,
|
||||
use `curl` or browser to visit: `http://127.0.0.1:6060/debug/pprof/goroutine?debug=1` to get the stacktrace.
|
||||
|
@ -28,7 +28,7 @@ menu:
|
||||
3. 您看到的任何錯誤訊息
|
||||
4. 儘可能地在 [try.gitea.io](https://try.gitea.io) 觸發您的問題並記下步驟,以便其他人能重現那個問題。
|
||||
- 這將讓我們更有機會快速地找出問題的根源並解決它。
|
||||
5. 堆棧跟踪,[請參考英文文檔](https://docs.gitea.io/en-us/seek-help/)
|
||||
5. 堆棧跟踪,[請參考英文文檔](https://docs.gitea.com/help/support)
|
||||
|
||||
## 錯誤回報
|
||||
|
||||
|
@ -254,7 +254,7 @@ documented above, please note that `db` must be used as the database hostname.
|
||||
|
||||
# Customization
|
||||
|
||||
Customization files described [here](https://docs.gitea.io/en-us/customizing-gitea/) should
|
||||
Customization files described [here](administration/customizing-gitea.md) should
|
||||
be placed in `/var/lib/gitea/custom` directory. If using host volumes, it's quite easy to access these
|
||||
files; for named volumes, this is done through another container or by direct access at
|
||||
`/var/lib/docker/volumes/gitea_gitea/_/var_lib_gitea`. The configuration file will be saved at
|
||||
@ -313,7 +313,7 @@ services:
|
||||
- GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}"""
|
||||
```
|
||||
|
||||
To set required TOKEN and SECRET values, consider using Gitea's built-in [generate utility functions](https://docs.gitea.io/en-us/command-line/#generate).
|
||||
To set required TOKEN and SECRET values, consider using Gitea's built-in [generate utility functions](administration/command-line.md#generate).
|
||||
|
||||
# SSH Container Passthrough
|
||||
|
||||
@ -342,7 +342,7 @@ Once the wrapper is in place, you can make it the shell for the `git` user:
|
||||
sudo usermod -s /usr/local/bin/gitea-shell git
|
||||
```
|
||||
|
||||
Now that all the SSH commands are forwarded to the container, you need to set up the SSH authentication on the host. This is done by leveraging the [SSH AuthorizedKeysCommand](https://docs.gitea.io/en-us/command-line/#keys) to match the keys against those accepted by Gitea. Add the following block to `/etc/ssh/sshd_config`, on the host:
|
||||
Now that all the SSH commands are forwarded to the container, you need to set up the SSH authentication on the host. This is done by leveraging the [SSH AuthorizedKeysCommand](administration/command-line.md#keys) to match the keys against those accepted by Gitea. Add the following block to `/etc/ssh/sshd_config`, on the host:
|
||||
|
||||
```bash
|
||||
Match User git
|
||||
|
@ -281,7 +281,7 @@ services:
|
||||
- GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}"""
|
||||
```
|
||||
|
||||
要设置所需的 TOKEN 和 SECRET 值,可以使用 Gitea 的内置[生成使用函数](https://docs.gitea.io/en-us/command-line/#generate).
|
||||
要设置所需的 TOKEN 和 SECRET 值,可以使用 Gitea 的内置[生成使用函数](administration/command-line.md#generate).
|
||||
|
||||
# SSH 容器透传
|
||||
|
||||
@ -310,7 +310,7 @@ sudo chmod +x /usr/local/bin/gitea-shell
|
||||
sudo usermod -s /usr/local/bin/gitea-shell git
|
||||
```
|
||||
|
||||
现在,所有的 SSH 命令都会被转发到容器,您需要在主机上设置 SSH 认证。这可以通过利用 [SSH AuthorizedKeysCommand](https://docs.gitea.io/en-us/command-line/#keys) 来匹配 Gitea 接受的密钥。在主机的 `/etc/ssh/sshd_config` 文件中添加以下代码块:
|
||||
现在,所有的 SSH 命令都会被转发到容器,您需要在主机上设置 SSH 认证。这可以通过利用 [SSH AuthorizedKeysCommand](administration/command-line.md#keys) 来匹配 Gitea 接受的密钥。在主机的 `/etc/ssh/sshd_config` 文件中添加以下代码块:
|
||||
|
||||
```bash
|
||||
Match User git
|
||||
|
@ -261,7 +261,7 @@ documented above, please note that `db` must be used as the database hostname.
|
||||
|
||||
## Customization
|
||||
|
||||
Customization files described [here](https://docs.gitea.io/en-us/customizing-gitea/) should
|
||||
Customization files described [here](administration/customizing-gitea.md) should
|
||||
be placed in `/data/gitea` directory. If using host volumes, it's quite easy to access these
|
||||
files; for named volumes, this is done through another container or by direct access at
|
||||
`/var/lib/docker/volumes/gitea_gitea/_data`. The configuration file will be saved at
|
||||
@ -309,7 +309,7 @@ services:
|
||||
- GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}"""
|
||||
```
|
||||
|
||||
Gitea will generate new secrets/tokens for every new installation automatically and write them into the app.ini. If you want to set the secrets/tokens manually, you can use the following docker commands to use of Gitea's built-in [generate utility functions](https://docs.gitea.io/en-us/command-line/#generate). Do not lose/change your SECRET_KEY after the installation, otherwise the encrypted data can not be decrypted anymore.
|
||||
Gitea will generate new secrets/tokens for every new installation automatically and write them into the app.ini. If you want to set the secrets/tokens manually, you can use the following docker commands to use of Gitea's built-in [generate utility functions](administration/command-line.md#generate). Do not lose/change your SECRET_KEY after the installation, otherwise the encrypted data can not be decrypted anymore.
|
||||
|
||||
The following commands will output a new `SECRET_KEY` and `INTERNAL_TOKEN` to `stdout`, which you can then place in your environment variables.
|
||||
|
||||
@ -553,7 +553,7 @@ In this option, the idea is that the host SSH uses an `AuthorizedKeysCommand` in
|
||||
|
||||
Now all attempts to login as the `git` user on the host will be forwarded to the docker - including the `SSH_ORIGINAL_COMMAND`. We now need to set-up SSH authentication on the host.
|
||||
|
||||
We will do this by leveraging the [SSH AuthorizedKeysCommand](https://docs.gitea.io/en-us/command-line/#keys) to match the keys against those accepted by Gitea.
|
||||
We will do this by leveraging the [SSH AuthorizedKeysCommand](administration/command-line.md#keys) to match the keys against those accepted by Gitea.
|
||||
|
||||
Add the following block to `/etc/ssh/sshd_config`, on the host:
|
||||
|
||||
|
@ -103,7 +103,7 @@ Vous devriez maintenant avoir deux conteneurs Docker pour Gitea et PostgreSQL pl
|
||||
|
||||
# Personnalisation
|
||||
|
||||
Les fichier personnalisés ([voir les instructions](https://docs.gitea.io/en-us/customizing-gitea/)) peuvent être placés dans le répertoire `/data/gitea`.
|
||||
Les fichier personnalisés ([voir les instructions](administration/customizing-gitea.md)) peuvent être placés dans le répertoire `/data/gitea`.
|
||||
|
||||
Le fichier de configuration sera sauvegardé à l'emplacement suivant : `/data/gitea/conf/app.ini`
|
||||
|
||||
|
@ -260,7 +260,7 @@ MySQL 或 PostgreSQL 容器将需要分别创建。
|
||||
|
||||
## 自定义
|
||||
|
||||
[此处](https://docs.gitea.io/zh-cn/customizing-gitea/)描述的定制文件应放在 `/data/gitea` 目录中。如果使用主机卷,则访问这些文件非常容易;对于命名卷,可以通过另一个容器或通过直接访问 `/var/lib/docker/volumes/gitea_gitea/_data` 来完成。安装后,配置文件将保存在 `/data/gitea/conf/app.ini` 中。
|
||||
[此处](administration/customizing-gitea.md)描述的定制文件应放在 `/data/gitea` 目录中。如果使用主机卷,则访问这些文件非常容易;对于命名卷,可以通过另一个容器或通过直接访问 `/var/lib/docker/volumes/gitea_gitea/_data` 来完成。安装后,配置文件将保存在 `/data/gitea/conf/app.ini` 中。
|
||||
|
||||
## 升级
|
||||
|
||||
@ -293,7 +293,7 @@ services:
|
||||
- GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}"""
|
||||
```
|
||||
|
||||
Gitea 将为每次新安装自动生成新的 `SECRET_KEY` 并将它们写入 `app.ini`。 如果您想手动设置 `SECRET_KEY`,您可以使用以下 docker 命令来使用 Gitea 内置的[方法](https://docs.gitea.io/en-us/command-line/#generate)生成 `SECRET_KEY`。 安装后请妥善保管您的 `SECRET_KEY`,如若丢失则无法解密已加密的数据。
|
||||
Gitea 将为每次新安装自动生成新的 `SECRET_KEY` 并将它们写入 `app.ini`。 如果您想手动设置 `SECRET_KEY`,您可以使用以下 docker 命令来使用 Gitea 内置的[方法](administration/command-line.md#generate)生成 `SECRET_KEY`。 安装后请妥善保管您的 `SECRET_KEY`,如若丢失则无法解密已加密的数据。
|
||||
|
||||
以下命令将向 `stdout` 输出一个新的 `SECRET_KEY` 和 `INTERNAL_TOKEN`,然后您可以将其放入环境变量中。
|
||||
|
||||
|
@ -112,7 +112,7 @@ You can configure your Gitea instance to fetch actions or images from your intra
|
||||
|
||||
In fact, your Gitea instance can serve as both the actions marketplace and the image registry.
|
||||
You can mirror actions repositories from GitHub to your Gitea instance, and use them as normal.
|
||||
And [Gitea Container Registry](https://docs.gitea.io/en-us/usage/packages/container/) can be used as a Docker image registry.
|
||||
And [Gitea Container Registry](usage/packages/container.md) can be used as a Docker image registry.
|
||||
|
||||
### Connection 4, job containers to internet
|
||||
|
||||
|
@ -113,7 +113,7 @@ act runner 必须能够连接到Gitea以接收任务并发送执行结果回来
|
||||
|
||||
实际上,您的Gitea实例可以同时充当 Actions 市场和镜像注册表。
|
||||
您可以将GitHub上的Actions仓库镜像到您的Gitea实例,并将其用作普通Actions。
|
||||
而 [Gitea 容器注册表](https://docs.gitea.io/en-us/usage/packages/container/) 可用作Docker镜像注册表。
|
||||
而 [Gitea 容器注册表](usage/packages/container.md) 可用作Docker镜像注册表。
|
||||
|
||||
### 连接 4,Job容器到互联网
|
||||
|
||||
|
@ -61,7 +61,7 @@ For example:
|
||||
Be careful, the `https://` or `http://` prefix is necessary!
|
||||
|
||||
Alternatively, if you want your runners to download actions from GitHub or your own Gitea instance by default, you can configure it by setting `[actions].DEFAULT_ACTIONS_URL`.
|
||||
See [Configuration Cheat Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/#actions-actions).
|
||||
See [Configuration Cheat Sheet](administration/config-cheat-sheet.md#actions-actions).
|
||||
|
||||
This is one of the differences from GitHub Actions, but it should allow users much more flexibility in how they run Actions.
|
||||
|
||||
@ -69,7 +69,7 @@ This is one of the differences from GitHub Actions, but it should allow users mu
|
||||
|
||||
Runners have no more permissions than simply connecting to your Gitea instance.
|
||||
When any runner receives a job to run, it will temporarily gain limited permission to the repository associated with the job.
|
||||
If you want to give more permissions to the runner, allowing it to access more private repositories or external systems, you can pass [secrets](https://docs.gitea.io/en-us/usage/secrets/) to it.
|
||||
If you want to give more permissions to the runner, allowing it to access more private repositories or external systems, you can pass [secrets](usage/secrets.md) to it.
|
||||
|
||||
Refined permission control to Actions is a complicated job.
|
||||
In the future, we will add more options to Gitea to make it more configurable, such as allowing more write access to repositories or read access to all repositories in the same organization.
|
||||
|
@ -61,7 +61,7 @@ DEFAULT_REPO_UNITS = ...,repo.actions
|
||||
注意,`https://`或`http://`前缀是必需的!
|
||||
|
||||
另外,如果您希望您的Runner默认从GitHub或您自己的Gitea实例下载Actions,可以通过设置 `[actions].DEFAULT_ACTIONS_URL`进行配置。
|
||||
参见[配置速查表](https://docs.gitea.io/en-us/config-cheat-sheet/#actions-actions)。
|
||||
参见[配置速查表](administration/config-cheat-sheet.md#actions-actions)。
|
||||
|
||||
这是与GitHub Actions的一个区别,但它应该允许用户以更灵活的方式运行Actions。
|
||||
|
||||
@ -69,7 +69,7 @@ DEFAULT_REPO_UNITS = ...,repo.actions
|
||||
|
||||
Runner仅具有连接到您的Gitea实例的权限。
|
||||
当任何Runner接收到要运行的Job时,它将临时获得与Job关联的仓库的有限权限。
|
||||
如果您想为Runner提供更多权限,允许它访问更多私有仓库或外部系统,您可以向其传递[密钥](https://docs.gitea.io/en-us/usage/secrets/)。
|
||||
如果您想为Runner提供更多权限,允许它访问更多私有仓库或外部系统,您可以向其传递[密钥](usage/secrets.md)。
|
||||
|
||||
对于 Actions 的细粒度权限控制是一项复杂的工作。
|
||||
在未来,我们将添加更多选项以使Gitea更可配置,例如允许对仓库进行更多写访问或对同一组织中的所有仓库进行读访问。
|
||||
|
@ -197,7 +197,7 @@ administrative user.
|
||||
field is set to `mail.com`, then Gitea will expect the `user email` field
|
||||
for an authenticated GIT instance to be `gituser@mail.com`.[^2]
|
||||
|
||||
**Note**: PAM support is added via [build-time flags](https://docs.gitea.io/en-us/install-from-source/#build),
|
||||
**Note**: PAM support is added via [build-time flags](installation/install-from-source.md#build),
|
||||
and the official binaries provided do not have this enabled. PAM requires that
|
||||
the necessary libpam dynamic library be available and the necessary PAM
|
||||
development headers be accessible to the compiler.
|
||||
|
@ -162,7 +162,7 @@ PAM提供了一种机制,通过对用户进行PAM认证来自动将其添加
|
||||
- PAM电子邮件域:用户认证时要附加的电子邮件后缀。例如,如果登录系统期望一个名为gituse的用户,
|
||||
并且将此字段设置为mail.com,那么Gitea在验证一个GIT实例的用户时将期望user emai字段为gituser@mail.com[^2]。
|
||||
|
||||
**Note**: PAM 支持通过[build-time flags](https://docs.gitea.io/en-us/install-from-source/#build)添加,
|
||||
**Note**: PAM 支持通过[build-time flags](installation/install-from-source.md#build)添加,
|
||||
而官方提供的二进制文件通常不会默认启用此功能。PAM需要确保系统上有必要的libpam动态库,并且编译器可以访问必要的PAM开发头文件。
|
||||
|
||||
[^1]: 例如,在Debian "Bullseye"上使用标准Linux登录,可以使用`common-session-noninteractive`。这个值对于其他版本的Debian,
|
||||
|
2
go.mod
2
go.mod
@ -90,6 +90,7 @@ require (
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/quasoft/websspi v1.1.2
|
||||
github.com/redis/go-redis/v9 v9.0.5
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
|
||||
github.com/sassoftware/go-rpmutils v0.2.0
|
||||
github.com/sergi/go-diff v1.3.1
|
||||
@ -254,7 +255,6 @@ require (
|
||||
github.com/rhysd/actionlint v1.6.25 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/robfig/cron v1.2.0 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/rs/xid v1.5.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
|
120
models/actions/schedule.go
Normal file
120
models/actions/schedule.go
Normal file
@ -0,0 +1,120 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
// ActionSchedule represents a schedule of a workflow file
|
||||
type ActionSchedule struct {
|
||||
ID int64
|
||||
Title string
|
||||
Specs []string
|
||||
RepoID int64 `xorm:"index"`
|
||||
Repo *repo_model.Repository `xorm:"-"`
|
||||
OwnerID int64 `xorm:"index"`
|
||||
WorkflowID string
|
||||
TriggerUserID int64
|
||||
TriggerUser *user_model.User `xorm:"-"`
|
||||
Ref string
|
||||
CommitSHA string
|
||||
Event webhook_module.HookEventType
|
||||
EventPayload string `xorm:"LONGTEXT"`
|
||||
Content []byte
|
||||
Created timeutil.TimeStamp `xorm:"created"`
|
||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
db.RegisterModel(new(ActionSchedule))
|
||||
}
|
||||
|
||||
// GetSchedulesMapByIDs returns the schedules by given id slice.
|
||||
func GetSchedulesMapByIDs(ids []int64) (map[int64]*ActionSchedule, error) {
|
||||
schedules := make(map[int64]*ActionSchedule, len(ids))
|
||||
return schedules, db.GetEngine(db.DefaultContext).In("id", ids).Find(&schedules)
|
||||
}
|
||||
|
||||
// GetReposMapByIDs returns the repos by given id slice.
|
||||
func GetReposMapByIDs(ids []int64) (map[int64]*repo_model.Repository, error) {
|
||||
repos := make(map[int64]*repo_model.Repository, len(ids))
|
||||
return repos, db.GetEngine(db.DefaultContext).In("id", ids).Find(&repos)
|
||||
}
|
||||
|
||||
var cronParser = cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
|
||||
|
||||
// CreateScheduleTask creates new schedule task.
|
||||
func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error {
|
||||
// Return early if there are no rows to insert
|
||||
if len(rows) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Begin transaction
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
|
||||
// Loop through each schedule row
|
||||
for _, row := range rows {
|
||||
// Create new schedule row
|
||||
if err = db.Insert(ctx, row); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Loop through each schedule spec and create a new spec row
|
||||
now := time.Now()
|
||||
|
||||
for _, spec := range row.Specs {
|
||||
// Parse the spec and check for errors
|
||||
schedule, err := cronParser.Parse(spec)
|
||||
if err != nil {
|
||||
continue // skip to the next spec if there's an error
|
||||
}
|
||||
|
||||
// Insert the new schedule spec row
|
||||
if err = db.Insert(ctx, &ActionScheduleSpec{
|
||||
RepoID: row.RepoID,
|
||||
ScheduleID: row.ID,
|
||||
Spec: spec,
|
||||
Next: timeutil.TimeStamp(schedule.Next(now).Unix()),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commit transaction
|
||||
return committer.Commit()
|
||||
}
|
||||
|
||||
func DeleteScheduleTaskByRepo(ctx context.Context, id int64) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
|
||||
if _, err := db.GetEngine(ctx).Delete(&ActionSchedule{RepoID: id}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.GetEngine(ctx).Delete(&ActionScheduleSpec{RepoID: id}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return committer.Commit()
|
||||
}
|
94
models/actions/schedule_list.go
Normal file
94
models/actions/schedule_list.go
Normal file
@ -0,0 +1,94 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
type ScheduleList []*ActionSchedule
|
||||
|
||||
// GetUserIDs returns a slice of user's id
|
||||
func (schedules ScheduleList) GetUserIDs() []int64 {
|
||||
ids := make(container.Set[int64], len(schedules))
|
||||
for _, schedule := range schedules {
|
||||
ids.Add(schedule.TriggerUserID)
|
||||
}
|
||||
return ids.Values()
|
||||
}
|
||||
|
||||
func (schedules ScheduleList) GetRepoIDs() []int64 {
|
||||
ids := make(container.Set[int64], len(schedules))
|
||||
for _, schedule := range schedules {
|
||||
ids.Add(schedule.RepoID)
|
||||
}
|
||||
return ids.Values()
|
||||
}
|
||||
|
||||
func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error {
|
||||
userIDs := schedules.GetUserIDs()
|
||||
users := make(map[int64]*user_model.User, len(userIDs))
|
||||
if err := db.GetEngine(ctx).In("id", userIDs).Find(&users); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, schedule := range schedules {
|
||||
if schedule.TriggerUserID == user_model.ActionsUserID {
|
||||
schedule.TriggerUser = user_model.NewActionsUser()
|
||||
} else {
|
||||
schedule.TriggerUser = users[schedule.TriggerUserID]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (schedules ScheduleList) LoadRepos() error {
|
||||
repoIDs := schedules.GetRepoIDs()
|
||||
repos, err := repo_model.GetRepositoriesMapByIDs(repoIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, schedule := range schedules {
|
||||
schedule.Repo = repos[schedule.RepoID]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type FindScheduleOptions struct {
|
||||
db.ListOptions
|
||||
RepoID int64
|
||||
OwnerID int64
|
||||
}
|
||||
|
||||
func (opts FindScheduleOptions) toConds() builder.Cond {
|
||||
cond := builder.NewCond()
|
||||
if opts.RepoID > 0 {
|
||||
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
|
||||
}
|
||||
if opts.OwnerID > 0 {
|
||||
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
func FindSchedules(ctx context.Context, opts FindScheduleOptions) (ScheduleList, int64, error) {
|
||||
e := db.GetEngine(ctx).Where(opts.toConds())
|
||||
if !opts.ListAll && opts.PageSize > 0 && opts.Page >= 1 {
|
||||
e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
|
||||
}
|
||||
var schedules ScheduleList
|
||||
total, err := e.Desc("id").FindAndCount(&schedules)
|
||||
return schedules, total, err
|
||||
}
|
||||
|
||||
func CountSchedules(ctx context.Context, opts FindScheduleOptions) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionSchedule))
|
||||
}
|
50
models/actions/schedule_spec.go
Normal file
50
models/actions/schedule_spec.go
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
// ActionScheduleSpec represents a schedule spec of a workflow file
|
||||
type ActionScheduleSpec struct {
|
||||
ID int64
|
||||
RepoID int64 `xorm:"index"`
|
||||
Repo *repo_model.Repository `xorm:"-"`
|
||||
ScheduleID int64 `xorm:"index"`
|
||||
Schedule *ActionSchedule `xorm:"-"`
|
||||
|
||||
// Next time the job will run, or the zero time if Cron has not been
|
||||
// started or this entry's schedule is unsatisfiable
|
||||
Next timeutil.TimeStamp `xorm:"index"`
|
||||
// Prev is the last time this job was run, or the zero time if never.
|
||||
Prev timeutil.TimeStamp
|
||||
Spec string
|
||||
|
||||
Created timeutil.TimeStamp `xorm:"created"`
|
||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||
}
|
||||
|
||||
func (s *ActionScheduleSpec) Parse() (cron.Schedule, error) {
|
||||
return cronParser.Parse(s.Spec)
|
||||
}
|
||||
|
||||
func init() {
|
||||
db.RegisterModel(new(ActionScheduleSpec))
|
||||
}
|
||||
|
||||
func UpdateScheduleSpec(ctx context.Context, spec *ActionScheduleSpec, cols ...string) error {
|
||||
sess := db.GetEngine(ctx).ID(spec.ID)
|
||||
if len(cols) > 0 {
|
||||
sess.Cols(cols...)
|
||||
}
|
||||
_, err := sess.Update(spec)
|
||||
return err
|
||||
}
|
106
models/actions/schedule_spec_list.go
Normal file
106
models/actions/schedule_spec_list.go
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
type SpecList []*ActionScheduleSpec
|
||||
|
||||
func (specs SpecList) GetScheduleIDs() []int64 {
|
||||
ids := make(container.Set[int64], len(specs))
|
||||
for _, spec := range specs {
|
||||
ids.Add(spec.ScheduleID)
|
||||
}
|
||||
return ids.Values()
|
||||
}
|
||||
|
||||
func (specs SpecList) LoadSchedules() error {
|
||||
scheduleIDs := specs.GetScheduleIDs()
|
||||
schedules, err := GetSchedulesMapByIDs(scheduleIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, spec := range specs {
|
||||
spec.Schedule = schedules[spec.ScheduleID]
|
||||
}
|
||||
|
||||
repoIDs := specs.GetRepoIDs()
|
||||
repos, err := GetReposMapByIDs(repoIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, spec := range specs {
|
||||
spec.Repo = repos[spec.RepoID]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (specs SpecList) GetRepoIDs() []int64 {
|
||||
ids := make(container.Set[int64], len(specs))
|
||||
for _, spec := range specs {
|
||||
ids.Add(spec.RepoID)
|
||||
}
|
||||
return ids.Values()
|
||||
}
|
||||
|
||||
func (specs SpecList) LoadRepos() error {
|
||||
repoIDs := specs.GetRepoIDs()
|
||||
repos, err := repo_model.GetRepositoriesMapByIDs(repoIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, spec := range specs {
|
||||
spec.Repo = repos[spec.RepoID]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type FindSpecOptions struct {
|
||||
db.ListOptions
|
||||
RepoID int64
|
||||
Next int64
|
||||
}
|
||||
|
||||
func (opts FindSpecOptions) toConds() builder.Cond {
|
||||
cond := builder.NewCond()
|
||||
if opts.RepoID > 0 {
|
||||
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
|
||||
}
|
||||
|
||||
if opts.Next > 0 {
|
||||
cond = cond.And(builder.Lte{"next": opts.Next})
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
func FindSpecs(ctx context.Context, opts FindSpecOptions) (SpecList, int64, error) {
|
||||
e := db.GetEngine(ctx).Where(opts.toConds())
|
||||
if opts.PageSize > 0 && opts.Page >= 1 {
|
||||
e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
|
||||
}
|
||||
var specs SpecList
|
||||
total, err := e.Desc("id").FindAndCount(&specs)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err := specs.LoadSchedules(); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return specs, total, nil
|
||||
}
|
||||
|
||||
func CountSpecs(ctx context.Context, opts FindSpecOptions) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionScheduleSpec))
|
||||
}
|
@ -276,4 +276,12 @@
|
||||
email: user2-2@example.com
|
||||
lower_email: user2-2@example.com
|
||||
is_activated: false
|
||||
is_primary: false
|
||||
is_primary: false
|
||||
|
||||
-
|
||||
id: 36
|
||||
uid: 36
|
||||
email: abcde@gitea.com
|
||||
lower_email: abcde@gitea.com
|
||||
is_activated: true
|
||||
is_primary: false
|
||||
|
@ -1 +1,23 @@
|
||||
[] # empty
|
||||
-
|
||||
id: 5
|
||||
owner_id: 36
|
||||
key_id: B15431642629B826
|
||||
primary_key_id:
|
||||
content: xsDNBGTrY3UBDAC2HLBqmMplAV15qSnC7g1c4dV406f5EHNhFr95Nup2My6b2eafTlvedv77s8PT/I7F3fy4apOZs5A7w2SsPlLMcQ3ev4uGOsxRtkq5RLy1Yb6SNueX0Da2UVKR5KTC5Q6BWaqxwS0IjKOLZ/xz0Pbe/ClV3bZSKBEY2omkVo3Z0HZ771vB2clPRvGJ/IdeKOsZ3ZytSFXfyiJBdARmeSPmydXLil8+Ibq5iLAeow5PK8hK1TCOnKHzLWNqcNq70tyjoHvcGi70iGjoVEEUgPCLLuU8WmzTJwlvA3BuDzjtaO7TLo/jdE6iqkHtMSS8x+43sAH6hcFRCWAVh/0Uq7n36uGDfNxGnX3YrmX3LR9x5IsBES1rGGWbpxio4o5GIf/Xd+JgDd9rzJCqRuZ3/sW/TxK38htWaVNZV0kMkHUCTc1ctzWpCm635hbFCHBhPYIp+/z206khkAKDbz/CNuU91Wazsh7KO07wrwDtxfDDbInJ8TfHE2TGjzjQzgChfmcAEQEAAQ==
|
||||
verified: true
|
||||
can_sign: true
|
||||
can_encrypt_comms: true
|
||||
can_encrypt_storage: true
|
||||
can_certify: true
|
||||
|
||||
-
|
||||
id: 6
|
||||
owner_id: 36
|
||||
key_id: EE3AF48454AFD619
|
||||
primary_key_id: B15431642629B826
|
||||
content: zsDNBGTrY3UBDADsHrzuOicQaPdUQm0+0UNrs92cESm/j/4yBBUk+sfLZAo6J99c4eh4nAQzzZ7al080rYKB0G+7xoRz1eHcQH6zrVcqB8KYtf/sdY47WaMiMyxM+kTSvzp7tsv7QuSQZ0neUEXRyYMz5ttBfIjWUd+3NDItuHyB+MtNWlS3zXgaUbe5VifqKaNmzN0Ye4yXTKcpypE3AOqPVz+iIFv3c6TmsqLHJaR4VoicCleAqLyF/28WsJO7M9dDW+EM3MZVnsVpycTURyHAJGfSk10waQZAaRwmarCN/q0KEJ+aEAK/SRliUneBZoMO5hY5iBeG432tofwaQqAahPv9uXIb1n2JEMKwnMlMA9UGD1AcDbywfj1m/ZGBBw95i4Ekkfn43RvV3THr7uJU/dRqqP+iic4MwpUrOxqELW/kmeHXlBcNbZZhEEvwRoW7U2/9eeuog4nRleRJ0pi/xOP9wmxkKjaIPIK3phdBtEpVk4w/UTAWNdyIIrFggukeAnZFyGJwlm8AEQEAAQ==
|
||||
verified: true
|
||||
can_sign: true
|
||||
can_encrypt_comms: true
|
||||
can_encrypt_storage: true
|
||||
can_certify: true
|
||||
|
@ -1301,7 +1301,7 @@
|
||||
lower_name: limited_org36
|
||||
name: limited_org36
|
||||
full_name: Limited Org 36
|
||||
email: limited_org36@example.com
|
||||
email: abcde@gitea.com
|
||||
keep_email_private: false
|
||||
email_notifications_preference: enabled
|
||||
passwd: ZogKvWdyEx:password
|
||||
@ -1320,7 +1320,7 @@
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar22
|
||||
avatar_email: limited_org36@example.com
|
||||
avatar_email: abcde@gitea.com
|
||||
use_custom_avatar: false
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/references"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
@ -181,40 +182,32 @@ func (t CommentType) HasAttachmentSupport() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// RoleDescriptor defines comment tag type
|
||||
type RoleDescriptor int
|
||||
// RoleInRepo presents the user's participation in the repo
|
||||
type RoleInRepo string
|
||||
|
||||
// RoleDescriptor defines comment "role" tags
|
||||
type RoleDescriptor struct {
|
||||
IsPoster bool
|
||||
RoleInRepo RoleInRepo
|
||||
}
|
||||
|
||||
// Enumerate all the role tags.
|
||||
const (
|
||||
RoleDescriptorNone RoleDescriptor = iota
|
||||
RoleDescriptorPoster
|
||||
RoleDescriptorWriter
|
||||
RoleDescriptorOwner
|
||||
RoleRepoOwner RoleInRepo = "owner"
|
||||
RoleRepoMember RoleInRepo = "member"
|
||||
RoleRepoCollaborator RoleInRepo = "collaborator"
|
||||
RoleRepoFirstTimeContributor RoleInRepo = "first_time_contributor"
|
||||
RoleRepoContributor RoleInRepo = "contributor"
|
||||
)
|
||||
|
||||
// WithRole enable a specific tag on the RoleDescriptor.
|
||||
func (rd RoleDescriptor) WithRole(role RoleDescriptor) RoleDescriptor {
|
||||
return rd | (1 << role)
|
||||
// LocaleString returns the locale string name of the role
|
||||
func (r RoleInRepo) LocaleString(lang translation.Locale) string {
|
||||
return lang.Tr("repo.issues.role." + string(r))
|
||||
}
|
||||
|
||||
func stringToRoleDescriptor(role string) RoleDescriptor {
|
||||
switch role {
|
||||
case "Poster":
|
||||
return RoleDescriptorPoster
|
||||
case "Writer":
|
||||
return RoleDescriptorWriter
|
||||
case "Owner":
|
||||
return RoleDescriptorOwner
|
||||
default:
|
||||
return RoleDescriptorNone
|
||||
}
|
||||
}
|
||||
|
||||
// HasRole returns if a certain role is enabled on the RoleDescriptor.
|
||||
func (rd RoleDescriptor) HasRole(role string) bool {
|
||||
roleDescriptor := stringToRoleDescriptor(role)
|
||||
bitValue := rd & (1 << roleDescriptor)
|
||||
return (bitValue > 0)
|
||||
// LocaleHelper returns the locale tooltip of the role
|
||||
func (r RoleInRepo) LocaleHelper(lang translation.Locale) string {
|
||||
return lang.Tr("repo.issues.role." + string(r) + "_helper")
|
||||
}
|
||||
|
||||
// Comment represents a comment in commit and issue page.
|
||||
|
@ -199,3 +199,16 @@ func (prs PullRequestList) GetIssueIDs() []int64 {
|
||||
}
|
||||
return issueIDs
|
||||
}
|
||||
|
||||
// HasMergedPullRequestInRepo returns whether the user(poster) has merged pull-request in the repo
|
||||
func HasMergedPullRequestInRepo(ctx context.Context, repoID, posterID int64) (bool, error) {
|
||||
return db.GetEngine(ctx).
|
||||
Join("INNER", "pull_request", "pull_request.issue_id = issue.id").
|
||||
Where("repo_id=?", repoID).
|
||||
And("poster_id=?", posterID).
|
||||
And("is_pull=?", true).
|
||||
And("pull_request.has_merged=?", true).
|
||||
Select("issue.id").
|
||||
Limit(1).
|
||||
Get(new(Issue))
|
||||
}
|
||||
|
@ -526,6 +526,8 @@ var migrations = []Migration{
|
||||
NewMigration("Allow archiving labels", v1_21.AddArchivedUnixColumInLabelTable),
|
||||
// v272 -> v273
|
||||
NewMigration("Add Version to ActionRun table", v1_21.AddVersionToActionRunTable),
|
||||
// v273 -> v274
|
||||
NewMigration("Add Action Schedule Table", v1_21.AddActionScheduleTable),
|
||||
}
|
||||
|
||||
// GetCurrentDBVersion returns the current db version
|
||||
|
@ -4,7 +4,6 @@
|
||||
package v1_16 //nolint
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"strings"
|
||||
@ -123,13 +122,17 @@ func RemigrateU2FCredentials(x *xorm.Engine) error {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
pubKey, err := parsed.PubKey.ECDH()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
remigrated := &webauthnCredential{
|
||||
ID: reg.ID,
|
||||
Name: reg.Name,
|
||||
LowerName: strings.ToLower(reg.Name),
|
||||
UserID: reg.UserID,
|
||||
CredentialID: base32.HexEncoding.EncodeToString(parsed.KeyHandle),
|
||||
PublicKey: elliptic.Marshal(elliptic.P256(), parsed.PubKey.X, parsed.PubKey.Y),
|
||||
PublicKey: pubKey.Bytes(),
|
||||
AttestationType: "fido-u2f",
|
||||
AAGUID: []byte{},
|
||||
SignCount: reg.Counter,
|
||||
|
45
models/migrations/v1_21/v273.go
Normal file
45
models/migrations/v1_21/v273.go
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_21 //nolint
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func AddActionScheduleTable(x *xorm.Engine) error {
|
||||
type ActionSchedule struct {
|
||||
ID int64
|
||||
Title string
|
||||
Specs []string
|
||||
RepoID int64 `xorm:"index"`
|
||||
OwnerID int64 `xorm:"index"`
|
||||
WorkflowID string
|
||||
TriggerUserID int64
|
||||
Ref string
|
||||
CommitSHA string
|
||||
Event string
|
||||
EventPayload string `xorm:"LONGTEXT"`
|
||||
Content []byte
|
||||
Created timeutil.TimeStamp `xorm:"created"`
|
||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||
}
|
||||
|
||||
type ActionScheduleSpec struct {
|
||||
ID int64
|
||||
RepoID int64 `xorm:"index"`
|
||||
ScheduleID int64 `xorm:"index"`
|
||||
Spec string
|
||||
Next timeutil.TimeStamp `xorm:"index"`
|
||||
Prev timeutil.TimeStamp
|
||||
|
||||
Created timeutil.TimeStamp `xorm:"created"`
|
||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||
}
|
||||
|
||||
return x.Sync(
|
||||
new(ActionSchedule),
|
||||
new(ActionScheduleSpec),
|
||||
)
|
||||
}
|
@ -170,6 +170,8 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
|
||||
&actions_model.ActionRunJob{RepoID: repoID},
|
||||
&actions_model.ActionRun{RepoID: repoID},
|
||||
&actions_model.ActionRunner{RepoID: repoID},
|
||||
&actions_model.ActionScheduleSpec{RepoID: repoID},
|
||||
&actions_model.ActionSchedule{RepoID: repoID},
|
||||
&actions_model.ActionArtifact{RepoID: repoID},
|
||||
); err != nil {
|
||||
return fmt.Errorf("deleteBeans: %w", err)
|
||||
|
@ -128,7 +128,7 @@ func GetPushMirrorsByRepoID(ctx context.Context, repoID int64, listOptions db.Li
|
||||
func GetPushMirrorsSyncedOnCommit(ctx context.Context, repoID int64) ([]*PushMirror, error) {
|
||||
mirrors := make([]*PushMirror, 0, 10)
|
||||
return mirrors, db.GetEngine(ctx).
|
||||
Where("repo_id=? AND sync_on_commit=?", repoID, true).
|
||||
Where("repo_id = ? AND sync_on_commit = ?", repoID, true).
|
||||
Find(&mirrors)
|
||||
}
|
||||
|
||||
|
@ -133,6 +133,11 @@ func (r *Release) HTMLURL() string {
|
||||
return r.Repo.HTMLURL() + "/releases/tag/" + util.PathEscapeSegments(r.TagName)
|
||||
}
|
||||
|
||||
// APIUploadURL the api url to upload assets to a release. release must have attributes loaded
|
||||
func (r *Release) APIUploadURL() string {
|
||||
return r.APIURL() + "/assets"
|
||||
}
|
||||
|
||||
// Link the relative url for a release on the web UI. release must have attributes loaded
|
||||
func (r *Release) Link() string {
|
||||
return r.Repo.Link() + "/releases/tag/" + util.PathEscapeSegments(r.TagName)
|
||||
|
@ -6,12 +6,14 @@ package secret
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
secret_module "code.gitea.io/gitea/modules/secret"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
@ -26,6 +28,25 @@ type Secret struct {
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
|
||||
}
|
||||
|
||||
// ErrSecretNotFound represents a "secret not found" error.
|
||||
type ErrSecretNotFound struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// IsErrSecretNotFound checks if an error is a ErrSecretNotFound.
|
||||
func IsErrSecretNotFound(err error) bool {
|
||||
_, ok := err.(ErrSecretNotFound)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrSecretNotFound) Error() string {
|
||||
return fmt.Sprintf("secret was not found [name: %s]", err.Name)
|
||||
}
|
||||
|
||||
func (err ErrSecretNotFound) Unwrap() error {
|
||||
return util.ErrNotExist
|
||||
}
|
||||
|
||||
// newSecret Creates a new already encrypted secret
|
||||
func newSecret(ownerID, repoID int64, name, data string) *Secret {
|
||||
return &Secret{
|
||||
@ -93,3 +114,77 @@ func FindSecrets(ctx context.Context, opts FindSecretsOptions) ([]*Secret, error
|
||||
func CountSecrets(ctx context.Context, opts *FindSecretsOptions) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(opts.toConds()).Count(new(Secret))
|
||||
}
|
||||
|
||||
// UpdateSecret changes org or user reop secret.
|
||||
func UpdateSecret(ctx context.Context, orgID, repoID int64, name, data string) error {
|
||||
sc := new(Secret)
|
||||
name = strings.ToUpper(name)
|
||||
has, err := db.GetEngine(ctx).
|
||||
Where("owner_id=?", orgID).
|
||||
And("repo_id=?", repoID).
|
||||
And("name=?", name).
|
||||
Get(sc)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return ErrSecretNotFound{Name: name}
|
||||
}
|
||||
|
||||
encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sc.Data = encrypted
|
||||
_, err = db.GetEngine(ctx).ID(sc.ID).Cols("data").Update(sc)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteSecret deletes secret from an organization.
|
||||
func DeleteSecret(ctx context.Context, orgID, repoID int64, name string) error {
|
||||
sc := new(Secret)
|
||||
has, err := db.GetEngine(ctx).
|
||||
Where("owner_id=?", orgID).
|
||||
And("repo_id=?", repoID).
|
||||
And("name=?", strings.ToUpper(name)).
|
||||
Get(sc)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return ErrSecretNotFound{Name: name}
|
||||
}
|
||||
|
||||
if _, err := db.GetEngine(ctx).ID(sc.ID).Delete(new(Secret)); err != nil {
|
||||
return fmt.Errorf("Delete: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateOrUpdateSecret creates or updates a secret and returns true if it was created
|
||||
func CreateOrUpdateSecret(ctx context.Context, orgID, repoID int64, name, data string) (bool, error) {
|
||||
sc := new(Secret)
|
||||
name = strings.ToUpper(name)
|
||||
has, err := db.GetEngine(ctx).
|
||||
Where("owner_id=?", orgID).
|
||||
And("repo_id=?", repoID).
|
||||
And("name=?", name).
|
||||
Get(sc)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
_, err = InsertEncryptedSecret(ctx, orgID, repoID, name, data)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if err := UpdateSecret(ctx, orgID, repoID, name, data); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
@ -318,14 +319,13 @@ var (
|
||||
|
||||
// FindUnitTypes give the unit key names and return valid unique units and invalid keys
|
||||
func FindUnitTypes(nameKeys ...string) (res []Type, invalidKeys []string) {
|
||||
m := map[Type]struct{}{}
|
||||
m := make(container.Set[Type])
|
||||
for _, key := range nameKeys {
|
||||
t := TypeFromKey(key)
|
||||
if t == TypeInvalid {
|
||||
invalidKeys = append(invalidKeys, key)
|
||||
} else if _, ok := m[t]; !ok {
|
||||
} else if m.Add(t) {
|
||||
res = append(res, t)
|
||||
m[t] = struct{}{}
|
||||
}
|
||||
}
|
||||
return res, invalidKeys
|
||||
|
@ -95,18 +95,25 @@ func GetEventsFromContent(content []byte) ([]*jobparser.Event, error) {
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func DetectWorkflows(gitRepo *git.Repository, commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader) ([]*DetectedWorkflow, error) {
|
||||
func DetectWorkflows(
|
||||
gitRepo *git.Repository,
|
||||
commit *git.Commit,
|
||||
triggedEvent webhook_module.HookEventType,
|
||||
payload api.Payloader,
|
||||
) ([]*DetectedWorkflow, []*DetectedWorkflow, error) {
|
||||
entries, err := ListWorkflows(commit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
workflows := make([]*DetectedWorkflow, 0, len(entries))
|
||||
schedules := make([]*DetectedWorkflow, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
content, err := GetContentFromEntry(entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
events, err := GetEventsFromContent(content)
|
||||
if err != nil {
|
||||
log.Warn("ignore invalid workflow %q: %v", entry.Name(), err)
|
||||
@ -114,6 +121,14 @@ func DetectWorkflows(gitRepo *git.Repository, commit *git.Commit, triggedEvent w
|
||||
}
|
||||
for _, evt := range events {
|
||||
log.Trace("detect workflow %q for event %#v matching %q", entry.Name(), evt, triggedEvent)
|
||||
if evt.IsSchedule() {
|
||||
dwf := &DetectedWorkflow{
|
||||
EntryName: entry.Name(),
|
||||
TriggerEvent: evt.Name,
|
||||
Content: content,
|
||||
}
|
||||
schedules = append(schedules, dwf)
|
||||
}
|
||||
if detectMatched(gitRepo, commit, triggedEvent, payload, evt) {
|
||||
dwf := &DetectedWorkflow{
|
||||
EntryName: entry.Name(),
|
||||
@ -125,7 +140,7 @@ func DetectWorkflows(gitRepo *git.Repository, commit *git.Commit, triggedEvent w
|
||||
}
|
||||
}
|
||||
|
||||
return workflows, nil
|
||||
return workflows, schedules, nil
|
||||
}
|
||||
|
||||
func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) bool {
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
const rsaBits = 2048
|
||||
const rsaBits = 3072
|
||||
|
||||
// GetKeyPair function returns a user's private and public keys
|
||||
func GetKeyPair(user *user_model.User) (pub, priv string, err error) {
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
@ -130,7 +131,7 @@ func readDir(layer *Layer, name string) ([]fs.FileInfo, error) {
|
||||
// * false: only directories will be returned.
|
||||
// The returned files are sorted by name.
|
||||
func (l *LayeredFS) ListFiles(name string, fileMode ...bool) ([]string, error) {
|
||||
fileMap := map[string]bool{}
|
||||
fileSet := make(container.Set[string])
|
||||
for _, layer := range l.layers {
|
||||
infos, err := readDir(layer, name)
|
||||
if err != nil {
|
||||
@ -138,14 +139,11 @@ func (l *LayeredFS) ListFiles(name string, fileMode ...bool) ([]string, error) {
|
||||
}
|
||||
for _, info := range infos {
|
||||
if shouldInclude(info, fileMode...) {
|
||||
fileMap[info.Name()] = true
|
||||
fileSet.Add(info.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
files := make([]string, 0, len(fileMap))
|
||||
for file := range fileMap {
|
||||
files = append(files, file)
|
||||
}
|
||||
files := fileSet.Values()
|
||||
sort.Strings(files)
|
||||
return files, nil
|
||||
}
|
||||
@ -161,7 +159,7 @@ func (l *LayeredFS) ListAllFiles(name string, fileMode ...bool) ([]string, error
|
||||
}
|
||||
|
||||
func listAllFiles(layers []*Layer, name string, fileMode ...bool) ([]string, error) {
|
||||
fileMap := map[string]bool{}
|
||||
fileSet := make(container.Set[string])
|
||||
var list func(dir string) error
|
||||
list = func(dir string) error {
|
||||
for _, layer := range layers {
|
||||
@ -172,7 +170,7 @@ func listAllFiles(layers []*Layer, name string, fileMode ...bool) ([]string, err
|
||||
for _, info := range infos {
|
||||
path := util.PathJoinRelX(dir, info.Name())
|
||||
if shouldInclude(info, fileMode...) {
|
||||
fileMap[path] = true
|
||||
fileSet.Add(path)
|
||||
}
|
||||
if info.IsDir() {
|
||||
if err = list(path); err != nil {
|
||||
@ -186,10 +184,7 @@ func listAllFiles(layers []*Layer, name string, fileMode ...bool) ([]string, err
|
||||
if err := list(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var files []string
|
||||
for file := range fileMap {
|
||||
files = append(files, file)
|
||||
}
|
||||
files := fileSet.Values()
|
||||
sort.Strings(files)
|
||||
return files, nil
|
||||
}
|
||||
|
@ -107,6 +107,29 @@ func GetValidateContext(req *http.Request) (ctx *ValidateContext) {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func NewTemplateContextForWeb(ctx *Context) TemplateContext {
|
||||
tmplCtx := NewTemplateContext(ctx)
|
||||
tmplCtx["Locale"] = ctx.Base.Locale
|
||||
tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx)
|
||||
return tmplCtx
|
||||
}
|
||||
|
||||
func NewWebContext(base *Base, render Render, session session.Store) *Context {
|
||||
ctx := &Context{
|
||||
Base: base,
|
||||
Render: render,
|
||||
Session: session,
|
||||
|
||||
Cache: mc.GetCache(),
|
||||
Link: setting.AppSubURL + strings.TrimSuffix(base.Req.URL.EscapedPath(), "/"),
|
||||
Repo: &Repository{PullRequest: &PullRequest{}},
|
||||
Org: &Organization{},
|
||||
}
|
||||
ctx.TemplateContext = NewTemplateContextForWeb(ctx)
|
||||
ctx.Flash = &middleware.Flash{DataStore: ctx, Values: url.Values{}}
|
||||
return ctx
|
||||
}
|
||||
|
||||
// Contexter initializes a classic context for a request.
|
||||
func Contexter() func(next http.Handler) http.Handler {
|
||||
rnd := templates.HTMLRenderer()
|
||||
@ -127,21 +150,8 @@ func Contexter() func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
base, baseCleanUp := NewBaseContext(resp, req)
|
||||
ctx := &Context{
|
||||
Base: base,
|
||||
Cache: mc.GetCache(),
|
||||
Link: setting.AppSubURL + strings.TrimSuffix(req.URL.EscapedPath(), "/"),
|
||||
Render: rnd,
|
||||
Session: session.GetSession(req),
|
||||
Repo: &Repository{PullRequest: &PullRequest{}},
|
||||
Org: &Organization{},
|
||||
}
|
||||
defer baseCleanUp()
|
||||
|
||||
// TODO: "install.go" also shares the same logic, which should be refactored to a general function
|
||||
ctx.TemplateContext = NewTemplateContext(ctx)
|
||||
ctx.TemplateContext["Locale"] = ctx.Locale
|
||||
ctx.TemplateContext["AvatarUtils"] = templates.NewAvatarUtils(ctx)
|
||||
ctx := NewWebContext(base, rnd, session.GetSession(req))
|
||||
|
||||
ctx.Data.MergeFrom(middleware.CommonTemplateContextData())
|
||||
ctx.Data["Context"] = ctx // TODO: use "ctx" in template and remove this
|
||||
@ -172,8 +182,7 @@ func Contexter() func(next http.Handler) http.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
// prepare an empty Flash message for current request
|
||||
ctx.Flash = &middleware.Flash{DataStore: ctx, Values: url.Values{}}
|
||||
// if there are new messages in the ctx.Flash, write them into cookie
|
||||
ctx.Resp.Before(func(resp ResponseWriter) {
|
||||
if val := ctx.Flash.Encode(); val != "" {
|
||||
middleware.SetSiteCookie(ctx.Resp, CookieNameFlash, val, 0)
|
||||
|
@ -154,12 +154,10 @@ func PackageContexter() func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
base, baseCleanUp := NewBaseContext(resp, req)
|
||||
ctx := &Context{
|
||||
Base: base,
|
||||
Render: renderer, // it is still needed when rendering 500 page in a package handler
|
||||
}
|
||||
defer baseCleanUp()
|
||||
|
||||
// it is still needed when rendering 500 page in a package handler
|
||||
ctx := NewWebContext(base, renderer, nil)
|
||||
ctx.Base.AppendContextValue(WebContextKey, ctx)
|
||||
next.ServeHTTP(ctx.Resp, ctx.Req)
|
||||
})
|
||||
|
61
modules/doctor/fix8312.go
Normal file
61
modules/doctor/fix8312.go
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package doctor
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
org_model "code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func fixOwnerTeamCreateOrgRepo(ctx context.Context, logger log.Logger, autofix bool) error {
|
||||
count := 0
|
||||
|
||||
err := db.Iterate(
|
||||
ctx,
|
||||
builder.Eq{"authorize": perm.AccessModeOwner, "can_create_org_repo": false},
|
||||
func(ctx context.Context, team *org_model.Team) error {
|
||||
team.CanCreateOrgRepo = true
|
||||
count++
|
||||
|
||||
if !autofix {
|
||||
return nil
|
||||
}
|
||||
|
||||
return models.UpdateTeam(team, false, false)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
logger.Critical("Unable to iterate across repounits to fix incorrect can_create_org_repo: Error %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if !autofix {
|
||||
if count == 0 {
|
||||
logger.Info("Found no team with incorrect can_create_org_repo")
|
||||
} else {
|
||||
logger.Warn("Found %d teams with incorrect can_create_org_repo", count)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
logger.Info("Fixed %d teams with incorrect can_create_org_repo", count)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(&Check{
|
||||
Title: "Check for incorrect can_create_org_repo for org owner teams",
|
||||
Name: "fix-owner-team-create-org-repo",
|
||||
IsDefault: false,
|
||||
Run: fixOwnerTeamCreateOrgRepo,
|
||||
Priority: 7,
|
||||
})
|
||||
}
|
@ -495,7 +495,7 @@ func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*Commi
|
||||
}()
|
||||
|
||||
stderr := new(bytes.Buffer)
|
||||
err := NewCommand(ctx, "log", "--name-status", "-c", "--pretty=format:", "--parents", "--no-renames", "-z", "-1").AddDynamicArguments(commitID).Run(&RunOpts{
|
||||
err := NewCommand(ctx, "log", "--name-status", "-m", "--pretty=format:", "--first-parent", "--no-renames", "-z", "-1").AddDynamicArguments(commitID).Run(&RunOpts{
|
||||
Dir: repoPath,
|
||||
Stdout: w,
|
||||
Stderr: stderr,
|
||||
|
@ -255,3 +255,26 @@ func TestParseCommitFileStatus(t *testing.T) {
|
||||
assert.Equal(t, kase.modified, fileStatus.Modified)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCommitFileStatusMerges(t *testing.T) {
|
||||
bareRepo1Path := filepath.Join(testReposDir, "repo6_merge")
|
||||
|
||||
commitFileStatus, err := GetCommitFileStatus(DefaultContext, bareRepo1Path, "022f4ce6214973e018f02bf363bf8a2e3691f699")
|
||||
assert.NoError(t, err)
|
||||
|
||||
expected := CommitFileStatus{
|
||||
[]string{
|
||||
"add_file.txt",
|
||||
},
|
||||
[]string{
|
||||
"to_remove.txt",
|
||||
},
|
||||
[]string{
|
||||
"to_modify.txt",
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, commitFileStatus.Added, expected.Added)
|
||||
assert.Equal(t, commitFileStatus.Removed, expected.Removed)
|
||||
assert.Equal(t, commitFileStatus.Modified, expected.Modified)
|
||||
}
|
||||
|
@ -374,27 +374,25 @@ heaploop:
|
||||
break heaploop
|
||||
}
|
||||
parentRemaining.Remove(current.CommitID)
|
||||
if current.Paths != nil {
|
||||
for i, found := range current.Paths {
|
||||
if !found {
|
||||
continue
|
||||
for i, found := range current.Paths {
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
changed[i] = false
|
||||
if results[i] == "" {
|
||||
results[i] = current.CommitID
|
||||
if err := repo.LastCommitCache.Put(headRef, path.Join(treepath, paths[i]), current.CommitID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changed[i] = false
|
||||
if results[i] == "" {
|
||||
results[i] = current.CommitID
|
||||
if err := repo.LastCommitCache.Put(headRef, path.Join(treepath, paths[i]), current.CommitID); err != nil {
|
||||
delete(path2idx, paths[i])
|
||||
remaining--
|
||||
if results[0] == "" {
|
||||
results[0] = current.CommitID
|
||||
if err := repo.LastCommitCache.Put(headRef, treepath, current.CommitID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
delete(path2idx, paths[i])
|
||||
delete(path2idx, "")
|
||||
remaining--
|
||||
if results[0] == "" {
|
||||
results[0] = current.CommitID
|
||||
if err := repo.LastCommitCache.Put(headRef, treepath, current.CommitID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
delete(path2idx, "")
|
||||
remaining--
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1
modules/git/tests/repos/repo6_merge/HEAD
Normal file
1
modules/git/tests/repos/repo6_merge/HEAD
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/main
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
x<01>ÍM
|
||||
1†a×=Eö‚$µÍLAÄ«ô'Á‡‘iæþR½€›g÷~_ÝÖu1 ˜N¶‹@mZ)g<>2…D‘j™Š*_“fŒÌs¥4ïòaÏm“np>—Áˆç€Ì>!œÑ#ºú½1ù;p]ìxÿæuyIwÑN4Ã
|
@ -0,0 +1,2 @@
|
||||
x█нM
|
||||
б0├aв9еЛ≥ЭM2 БU Ф╛∙=©т╦yv/╪С╤╝к гН0:@╠Р$╠│Uя╛╚.≈[й>╚ ■l⌠▀IлsЙxР╘З8'T╞╟R╧д╓S,╙╠$x.
ж И=n[╖│в═СНuГ╢s!+9╟┬ВBGvлfЧm
Э≤▌uШ─зr┤ЫЪа>╝
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,5 @@
|
||||
xŤÎM
|
||||
1@a×=Eö‚¤?iń*mšÁÇ‘™xOŕćŰ=x˛.Ëlŕ™O¶©R˘Z80ŠÄ\[í*Ú%µb
|
||||
<EFBFBD>&qď¶éË –IŠŽČšÔç<C394>ť
|
||||
7ęĚÔ‹F쨜ĽwícŹuÓÝŕzx?¸ÜŔçš0ç
|
||||
ś1 :ům™ţ¸6LóSÝŔí>&
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
modules/git/tests/repos/repo6_merge/refs/heads/main
Normal file
1
modules/git/tests/repos/repo6_merge/refs/heads/main
Normal file
@ -0,0 +1 @@
|
||||
022f4ce6214973e018f02bf363bf8a2e3691f699
|
@ -0,0 +1 @@
|
||||
ae4b035e7c4afbc000576cee3f713ea0c2f1e1e2
|
@ -0,0 +1 @@
|
||||
d1792641396ff7630d35fbb0b74b86b0c71bca77
|
@ -0,0 +1 @@
|
||||
38ec3e0cdc88bde01014bda4a5dd9fc835f41439
|
@ -90,7 +90,7 @@ func (b *EventWriterBaseImpl) Run(ctx context.Context) {
|
||||
|
||||
if exprRegexp != nil {
|
||||
fileLineCaller := fmt.Sprintf("%s:%d:%s", event.Origin.Filename, event.Origin.Line, event.Origin.Caller)
|
||||
matched := exprRegexp.Match([]byte(fileLineCaller)) || exprRegexp.Match([]byte(event.Origin.MsgSimpleText))
|
||||
matched := exprRegexp.MatchString(fileLineCaller) || exprRegexp.MatchString(event.Origin.MsgSimpleText)
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/notification/base"
|
||||
"code.gitea.io/gitea/modules/notification/indexer"
|
||||
"code.gitea.io/gitea/modules/notification/mail"
|
||||
"code.gitea.io/gitea/modules/notification/mirror"
|
||||
"code.gitea.io/gitea/modules/notification/ui"
|
||||
"code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@ -38,7 +37,6 @@ func NewContext() {
|
||||
}
|
||||
RegisterNotifier(indexer.NewNotifier())
|
||||
RegisterNotifier(action.NewNotifier())
|
||||
RegisterNotifier(mirror.NewNotifier())
|
||||
}
|
||||
|
||||
// NotifyNewWikiPage notifies creating new wiki pages to notifiers
|
||||
|
@ -19,9 +19,9 @@ const (
|
||||
packageName = "gitea"
|
||||
packageVersion = "1.0.1"
|
||||
description = "Package Description"
|
||||
projectURL = "https://gitea.io"
|
||||
repositoryURL = "https://gitea.io/gitea/gitea"
|
||||
documentationURL = "https://docs.gitea.io"
|
||||
projectURL = "https://gitea.com"
|
||||
repositoryURL = "https://gitea.com/gitea/gitea"
|
||||
documentationURL = "https://docs.gitea.com"
|
||||
)
|
||||
|
||||
func TestParsePackage(t *testing.T) {
|
||||
|
@ -17,9 +17,9 @@ func TestParseImageConfig(t *testing.T) {
|
||||
description := "Image Description"
|
||||
author := "Gitea"
|
||||
license := "MIT"
|
||||
projectURL := "https://gitea.io"
|
||||
projectURL := "https://gitea.com"
|
||||
repositoryURL := "https://gitea.com/gitea"
|
||||
documentationURL := "https://docs.gitea.io"
|
||||
documentationURL := "https://docs.gitea.com"
|
||||
|
||||
configOCI := `{"config": {"labels": {"` + labelAuthors + `": "` + author + `", "` + labelLicenses + `": "` + license + `", "` + labelURL + `": "` + projectURL + `", "` + labelSource + `": "` + repositoryURL + `", "` + labelDocumentation + `": "` + documentationURL + `", "` + labelDescription + `": "` + description + `"}}, "history": [{"created_by": "do it 1"}, {"created_by": "dummy #(nop) do it 2"}]}`
|
||||
|
||||
|
@ -18,9 +18,9 @@ const (
|
||||
packageName = "gitea"
|
||||
packageVersion = "1.0.1"
|
||||
description = "Package Description"
|
||||
projectURL = "https://gitea.io"
|
||||
repositoryURL = "https://gitea.io/gitea/gitea"
|
||||
documentationURL = "https://docs.gitea.io"
|
||||
projectURL = "https://gitea.com"
|
||||
repositoryURL = "https://gitea.com/gitea/gitea"
|
||||
documentationURL = "https://docs.gitea.com"
|
||||
)
|
||||
|
||||
const pubspecContent = `name: ` + packageName + `
|
||||
|
@ -106,15 +106,15 @@ func SyncRepoBranchesWithRepo(ctx context.Context, repo *repo_model.Repository,
|
||||
return int64(len(allBranches)), nil
|
||||
}
|
||||
|
||||
if err := db.WithTx(ctx, func(subCtx context.Context) error {
|
||||
if err := db.WithTx(ctx, func(ctx context.Context) error {
|
||||
if len(toAdd) > 0 {
|
||||
if err := git_model.AddBranches(subCtx, toAdd); err != nil {
|
||||
if err := git_model.AddBranches(ctx, toAdd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, b := range toUpdate {
|
||||
if _, err := db.GetEngine(subCtx).ID(b.ID).
|
||||
if _, err := db.GetEngine(ctx).ID(b.ID).
|
||||
Cols("commit_id, commit_message, pusher_id, commit_time, is_deleted").
|
||||
Update(b); err != nil {
|
||||
return err
|
||||
@ -122,7 +122,7 @@ func SyncRepoBranchesWithRepo(ctx context.Context, repo *repo_model.Repository,
|
||||
}
|
||||
|
||||
if len(toRemove) > 0 {
|
||||
if err := git_model.DeleteBranches(subCtx, repo.ID, doerID, toRemove); err != nil {
|
||||
if err := git_model.DeleteBranches(ctx, repo.ID, doerID, toRemove); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user