mirror of
https://codeberg.org/forgejo/forgejo
synced 2024-11-25 11:16:11 +01:00
Merge branch 'forgejo' into forgejo-federated-star
This commit is contained in:
commit
af0d0f7745
11
.air.toml
11
.air.toml
|
@ -8,6 +8,15 @@ delay = 1000
|
||||||
include_ext = ["go", "tmpl"]
|
include_ext = ["go", "tmpl"]
|
||||||
include_file = ["main.go"]
|
include_file = ["main.go"]
|
||||||
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
|
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
|
||||||
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"]
|
exclude_dir = [
|
||||||
|
"models/fixtures",
|
||||||
|
"models/migrations/fixtures",
|
||||||
|
"modules/avatar/identicon/testdata",
|
||||||
|
"modules/avatar/testdata",
|
||||||
|
"modules/git/tests",
|
||||||
|
"modules/migration/file_format_testdata",
|
||||||
|
"routers/private/tests",
|
||||||
|
"services/gitdiff/testdata",
|
||||||
|
]
|
||||||
exclude_regex = ["_test.go$", "_gen.go$"]
|
exclude_regex = ["_test.go$", "_gen.go$"]
|
||||||
stop_on_error = true
|
stop_on_error = true
|
||||||
|
|
|
@ -22,7 +22,6 @@ package "code.gitea.io/gitea/models/actions"
|
||||||
func (ScheduleList).GetRepoIDs
|
func (ScheduleList).GetRepoIDs
|
||||||
func (ScheduleList).LoadTriggerUser
|
func (ScheduleList).LoadTriggerUser
|
||||||
func (ScheduleList).LoadRepos
|
func (ScheduleList).LoadRepos
|
||||||
func GetVariableByID
|
|
||||||
|
|
||||||
package "code.gitea.io/gitea/models/asymkey"
|
package "code.gitea.io/gitea/models/asymkey"
|
||||||
func (ErrGPGKeyAccessDenied).Error
|
func (ErrGPGKeyAccessDenied).Error
|
||||||
|
@ -92,7 +91,6 @@ package "code.gitea.io/gitea/models/repo"
|
||||||
func (*releaseSorter).Swap
|
func (*releaseSorter).Swap
|
||||||
func SortReleases
|
func SortReleases
|
||||||
func FindReposMapByIDs
|
func FindReposMapByIDs
|
||||||
func RepositoryListOfMap
|
|
||||||
func (SearchOrderBy).String
|
func (SearchOrderBy).String
|
||||||
func IsErrTopicNotExist
|
func IsErrTopicNotExist
|
||||||
func (ErrTopicNotExist).Error
|
func (ErrTopicNotExist).Error
|
||||||
|
@ -163,9 +161,6 @@ package "code.gitea.io/gitea/modules/cache"
|
||||||
package "code.gitea.io/gitea/modules/charset"
|
package "code.gitea.io/gitea/modules/charset"
|
||||||
func (*BreakWriter).Write
|
func (*BreakWriter).Write
|
||||||
|
|
||||||
package "code.gitea.io/gitea/modules/context"
|
|
||||||
func GetPrivateContext
|
|
||||||
|
|
||||||
package "code.gitea.io/gitea/modules/emoji"
|
package "code.gitea.io/gitea/modules/emoji"
|
||||||
func ReplaceCodes
|
func ReplaceCodes
|
||||||
|
|
||||||
|
@ -182,6 +177,7 @@ package "code.gitea.io/gitea/modules/git"
|
||||||
func (ErrExecTimeout).Error
|
func (ErrExecTimeout).Error
|
||||||
func (ErrUnsupportedVersion).Error
|
func (ErrUnsupportedVersion).Error
|
||||||
func SetUpdateHook
|
func SetUpdateHook
|
||||||
|
func GetObjectFormatOfRepo
|
||||||
func openRepositoryWithDefaultContext
|
func openRepositoryWithDefaultContext
|
||||||
func IsTagExist
|
func IsTagExist
|
||||||
func ToEntryMode
|
func ToEntryMode
|
||||||
|
@ -193,6 +189,7 @@ package "code.gitea.io/gitea/modules/gitgraph"
|
||||||
|
|
||||||
package "code.gitea.io/gitea/modules/gitrepo"
|
package "code.gitea.io/gitea/modules/gitrepo"
|
||||||
func GetBranchCommitID
|
func GetBranchCommitID
|
||||||
|
func GetWikiDefaultBranch
|
||||||
|
|
||||||
package "code.gitea.io/gitea/modules/graceful"
|
package "code.gitea.io/gitea/modules/graceful"
|
||||||
func (*Manager).TerminateContext
|
func (*Manager).TerminateContext
|
||||||
|
@ -225,7 +222,6 @@ package "code.gitea.io/gitea/modules/markup/markdown"
|
||||||
func IsSummary
|
func IsSummary
|
||||||
func IsTaskCheckBoxListItem
|
func IsTaskCheckBoxListItem
|
||||||
func IsIcon
|
func IsIcon
|
||||||
func IsColorPreview
|
|
||||||
func RenderRawString
|
func RenderRawString
|
||||||
|
|
||||||
package "code.gitea.io/gitea/modules/markup/markdown/math"
|
package "code.gitea.io/gitea/modules/markup/markdown/math"
|
||||||
|
@ -275,13 +271,19 @@ package "code.gitea.io/gitea/modules/sync"
|
||||||
|
|
||||||
package "code.gitea.io/gitea/modules/testlogger"
|
package "code.gitea.io/gitea/modules/testlogger"
|
||||||
func (*testLoggerWriterCloser).pushT
|
func (*testLoggerWriterCloser).pushT
|
||||||
func (*testLoggerWriterCloser).Write
|
func (*testLoggerWriterCloser).Log
|
||||||
|
func (*testLoggerWriterCloser).recordError
|
||||||
|
func (*testLoggerWriterCloser).printMsg
|
||||||
func (*testLoggerWriterCloser).popT
|
func (*testLoggerWriterCloser).popT
|
||||||
func (*testLoggerWriterCloser).Close
|
|
||||||
func (*testLoggerWriterCloser).Reset
|
func (*testLoggerWriterCloser).Reset
|
||||||
func PrintCurrentTest
|
func PrintCurrentTest
|
||||||
func Printf
|
func Printf
|
||||||
func NewTestLoggerWriter
|
func NewTestLoggerWriter
|
||||||
|
func (*TestLogEventWriter).Base
|
||||||
|
func (*TestLogEventWriter).GetLevel
|
||||||
|
func (*TestLogEventWriter).GetWriterName
|
||||||
|
func (*TestLogEventWriter).GetWriterType
|
||||||
|
func (*TestLogEventWriter).Run
|
||||||
|
|
||||||
package "code.gitea.io/gitea/modules/timeutil"
|
package "code.gitea.io/gitea/modules/timeutil"
|
||||||
func GetExecutableModTime
|
func GetExecutableModTime
|
||||||
|
@ -293,12 +295,9 @@ package "code.gitea.io/gitea/modules/translation"
|
||||||
func (MockLocale).TrString
|
func (MockLocale).TrString
|
||||||
func (MockLocale).Tr
|
func (MockLocale).Tr
|
||||||
func (MockLocale).TrN
|
func (MockLocale).TrN
|
||||||
|
func (MockLocale).TrSize
|
||||||
func (MockLocale).PrettyNumber
|
func (MockLocale).PrettyNumber
|
||||||
|
|
||||||
package "code.gitea.io/gitea/modules/util"
|
|
||||||
func UnsafeStringToBytes
|
|
||||||
func OptionalBoolFromGeneric
|
|
||||||
|
|
||||||
package "code.gitea.io/gitea/modules/util/filebuffer"
|
package "code.gitea.io/gitea/modules/util/filebuffer"
|
||||||
func CreateFromReader
|
func CreateFromReader
|
||||||
|
|
||||||
|
@ -324,6 +323,9 @@ package "code.gitea.io/gitea/routers/web/org"
|
||||||
func getActionIssues
|
func getActionIssues
|
||||||
func UpdateIssueProject
|
func UpdateIssueProject
|
||||||
|
|
||||||
|
package "code.gitea.io/gitea/services/context"
|
||||||
|
func GetPrivateContext
|
||||||
|
|
||||||
package "code.gitea.io/gitea/services/convert"
|
package "code.gitea.io/gitea/services/convert"
|
||||||
func ToSecret
|
func ToSecret
|
||||||
|
|
||||||
|
@ -335,7 +337,6 @@ package "code.gitea.io/gitea/services/pull"
|
||||||
|
|
||||||
package "code.gitea.io/gitea/services/repository"
|
package "code.gitea.io/gitea/services/repository"
|
||||||
func IsErrForkAlreadyExist
|
func IsErrForkAlreadyExist
|
||||||
func UpdateRepositoryUnits
|
|
||||||
|
|
||||||
package "code.gitea.io/gitea/services/repository/archiver"
|
package "code.gitea.io/gitea/services/repository/archiver"
|
||||||
func ArchiveRepository
|
func ArchiveRepository
|
||||||
|
|
|
@ -4,11 +4,13 @@
|
||||||
"features": {
|
"features": {
|
||||||
// installs nodejs into container
|
// installs nodejs into container
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
"version":"20"
|
"version": "20"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers/features/git-lfs:1.1.0": {},
|
"ghcr.io/devcontainers/features/git-lfs:1.1.0": {},
|
||||||
"ghcr.io/devcontainers-contrib/features/poetry:2": {},
|
"ghcr.io/devcontainers-contrib/features/poetry:2": {},
|
||||||
"ghcr.io/devcontainers/features/python:1": {}
|
"ghcr.io/devcontainers/features/python:1": {
|
||||||
|
"version": "3.12"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
|
@ -22,7 +24,7 @@
|
||||||
"DavidAnson.vscode-markdownlint",
|
"DavidAnson.vscode-markdownlint",
|
||||||
"Vue.volar",
|
"Vue.volar",
|
||||||
"ms-azuretools.vscode-docker",
|
"ms-azuretools.vscode-docker",
|
||||||
"zixuanchen.vitest-explorer",
|
"vitest.explorer",
|
||||||
"qwtel.sqlite-viewer",
|
"qwtel.sqlite-viewer",
|
||||||
"GitHub.vscode-pull-request-github"
|
"GitHub.vscode-pull-request-github"
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,7 +14,7 @@ _test
|
||||||
|
|
||||||
# MS VSCode
|
# MS VSCode
|
||||||
.vscode
|
.vscode
|
||||||
__debug_bin
|
__debug_bin*
|
||||||
|
|
||||||
# Architecture specific extensions/prefixes
|
# Architecture specific extensions/prefixes
|
||||||
*.[568vq]
|
*.[568vq]
|
||||||
|
@ -62,7 +62,6 @@ cpu.out
|
||||||
/data
|
/data
|
||||||
/indexers
|
/indexers
|
||||||
/log
|
/log
|
||||||
/public/img/avatar
|
|
||||||
/tests/integration/gitea-integration-*
|
/tests/integration/gitea-integration-*
|
||||||
/tests/integration/indexers-*
|
/tests/integration/indexers-*
|
||||||
/tests/e2e/gitea-e2e-*
|
/tests/e2e/gitea-e2e-*
|
||||||
|
@ -77,7 +76,7 @@ cpu.out
|
||||||
/public/assets/js
|
/public/assets/js
|
||||||
/public/assets/css
|
/public/assets/css
|
||||||
/public/assets/fonts
|
/public/assets/fonts
|
||||||
/public/assets/img/webpack
|
/public/assets/img/avatar
|
||||||
/vendor
|
/vendor
|
||||||
/web_src/fomantic/node_modules
|
/web_src/fomantic/node_modules
|
||||||
/web_src/fomantic/build/*
|
/web_src/fomantic/build/*
|
||||||
|
|
|
@ -3,6 +3,7 @@ reportUnusedDisableDirectives: true
|
||||||
|
|
||||||
ignorePatterns:
|
ignorePatterns:
|
||||||
- /web_src/js/vendor
|
- /web_src/js/vendor
|
||||||
|
- /web_src/fomantic
|
||||||
|
|
||||||
parserOptions:
|
parserOptions:
|
||||||
sourceType: module
|
sourceType: module
|
||||||
|
@ -42,10 +43,6 @@ overrides:
|
||||||
worker: true
|
worker: true
|
||||||
rules:
|
rules:
|
||||||
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
|
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
|
||||||
- files: ["build/generate-images.js"]
|
|
||||||
rules:
|
|
||||||
i/no-unresolved: [0]
|
|
||||||
i/no-extraneous-dependencies: [0]
|
|
||||||
- files: ["*.config.*"]
|
- files: ["*.config.*"]
|
||||||
rules:
|
rules:
|
||||||
i/no-unused-modules: [0]
|
i/no-unused-modules: [0]
|
||||||
|
@ -123,7 +120,7 @@ rules:
|
||||||
"@stylistic/js/arrow-spacing": [2, {before: true, after: true}]
|
"@stylistic/js/arrow-spacing": [2, {before: true, after: true}]
|
||||||
"@stylistic/js/block-spacing": [0]
|
"@stylistic/js/block-spacing": [0]
|
||||||
"@stylistic/js/brace-style": [2, 1tbs, {allowSingleLine: true}]
|
"@stylistic/js/brace-style": [2, 1tbs, {allowSingleLine: true}]
|
||||||
"@stylistic/js/comma-dangle": [2, only-multiline]
|
"@stylistic/js/comma-dangle": [2, always-multiline]
|
||||||
"@stylistic/js/comma-spacing": [2, {before: false, after: true}]
|
"@stylistic/js/comma-spacing": [2, {before: false, after: true}]
|
||||||
"@stylistic/js/comma-style": [2, last]
|
"@stylistic/js/comma-style": [2, last]
|
||||||
"@stylistic/js/computed-property-spacing": [2, never]
|
"@stylistic/js/computed-property-spacing": [2, never]
|
||||||
|
@ -171,7 +168,7 @@ rules:
|
||||||
"@stylistic/js/semi-spacing": [2, {before: false, after: true}]
|
"@stylistic/js/semi-spacing": [2, {before: false, after: true}]
|
||||||
"@stylistic/js/semi-style": [2, last]
|
"@stylistic/js/semi-style": [2, last]
|
||||||
"@stylistic/js/space-before-blocks": [2, always]
|
"@stylistic/js/space-before-blocks": [2, always]
|
||||||
"@stylistic/js/space-before-function-paren": [0]
|
"@stylistic/js/space-before-function-paren": [2, {anonymous: ignore, named: never, asyncArrow: always}]
|
||||||
"@stylistic/js/space-in-parens": [2, never]
|
"@stylistic/js/space-in-parens": [2, never]
|
||||||
"@stylistic/js/space-infix-ops": [2]
|
"@stylistic/js/space-infix-ops": [2]
|
||||||
"@stylistic/js/space-unary-ops": [2]
|
"@stylistic/js/space-unary-ops": [2]
|
||||||
|
@ -283,14 +280,14 @@ rules:
|
||||||
i/unambiguous: [0]
|
i/unambiguous: [0]
|
||||||
init-declarations: [0]
|
init-declarations: [0]
|
||||||
jquery/no-ajax-events: [2]
|
jquery/no-ajax-events: [2]
|
||||||
jquery/no-ajax: [0]
|
jquery/no-ajax: [2]
|
||||||
jquery/no-animate: [2]
|
jquery/no-animate: [2]
|
||||||
jquery/no-attr: [0]
|
jquery/no-attr: [2]
|
||||||
jquery/no-bind: [2]
|
jquery/no-bind: [2]
|
||||||
jquery/no-class: [0]
|
jquery/no-class: [0]
|
||||||
jquery/no-clone: [2]
|
jquery/no-clone: [2]
|
||||||
jquery/no-closest: [0]
|
jquery/no-closest: [0]
|
||||||
jquery/no-css: [0]
|
jquery/no-css: [2]
|
||||||
jquery/no-data: [0]
|
jquery/no-data: [0]
|
||||||
jquery/no-deferred: [2]
|
jquery/no-deferred: [2]
|
||||||
jquery/no-delegate: [2]
|
jquery/no-delegate: [2]
|
||||||
|
@ -307,7 +304,7 @@ rules:
|
||||||
jquery/no-in-array: [2]
|
jquery/no-in-array: [2]
|
||||||
jquery/no-is-array: [2]
|
jquery/no-is-array: [2]
|
||||||
jquery/no-is-function: [2]
|
jquery/no-is-function: [2]
|
||||||
jquery/no-is: [0]
|
jquery/no-is: [2]
|
||||||
jquery/no-load: [2]
|
jquery/no-load: [2]
|
||||||
jquery/no-map: [2]
|
jquery/no-map: [2]
|
||||||
jquery/no-merge: [2]
|
jquery/no-merge: [2]
|
||||||
|
@ -315,7 +312,7 @@ rules:
|
||||||
jquery/no-parent: [0]
|
jquery/no-parent: [0]
|
||||||
jquery/no-parents: [0]
|
jquery/no-parents: [0]
|
||||||
jquery/no-parse-html: [2]
|
jquery/no-parse-html: [2]
|
||||||
jquery/no-prop: [0]
|
jquery/no-prop: [2]
|
||||||
jquery/no-proxy: [2]
|
jquery/no-proxy: [2]
|
||||||
jquery/no-ready: [2]
|
jquery/no-ready: [2]
|
||||||
jquery/no-serialize: [2]
|
jquery/no-serialize: [2]
|
||||||
|
@ -396,12 +393,12 @@ rules:
|
||||||
no-irregular-whitespace: [2]
|
no-irregular-whitespace: [2]
|
||||||
no-iterator: [2]
|
no-iterator: [2]
|
||||||
no-jquery/no-ajax-events: [2]
|
no-jquery/no-ajax-events: [2]
|
||||||
no-jquery/no-ajax: [0]
|
no-jquery/no-ajax: [2]
|
||||||
no-jquery/no-and-self: [2]
|
no-jquery/no-and-self: [2]
|
||||||
no-jquery/no-animate-toggle: [2]
|
no-jquery/no-animate-toggle: [2]
|
||||||
no-jquery/no-animate: [2]
|
no-jquery/no-animate: [2]
|
||||||
no-jquery/no-append-html: [0]
|
no-jquery/no-append-html: [2]
|
||||||
no-jquery/no-attr: [0]
|
no-jquery/no-attr: [2]
|
||||||
no-jquery/no-bind: [2]
|
no-jquery/no-bind: [2]
|
||||||
no-jquery/no-box-model: [2]
|
no-jquery/no-box-model: [2]
|
||||||
no-jquery/no-browser: [2]
|
no-jquery/no-browser: [2]
|
||||||
|
@ -413,7 +410,7 @@ rules:
|
||||||
no-jquery/no-constructor-attributes: [2]
|
no-jquery/no-constructor-attributes: [2]
|
||||||
no-jquery/no-contains: [2]
|
no-jquery/no-contains: [2]
|
||||||
no-jquery/no-context-prop: [2]
|
no-jquery/no-context-prop: [2]
|
||||||
no-jquery/no-css: [0]
|
no-jquery/no-css: [2]
|
||||||
no-jquery/no-data: [0]
|
no-jquery/no-data: [0]
|
||||||
no-jquery/no-deferred: [2]
|
no-jquery/no-deferred: [2]
|
||||||
no-jquery/no-delegate: [2]
|
no-jquery/no-delegate: [2]
|
||||||
|
@ -444,7 +441,7 @@ rules:
|
||||||
no-jquery/no-is-numeric: [2]
|
no-jquery/no-is-numeric: [2]
|
||||||
no-jquery/no-is-plain-object: [2]
|
no-jquery/no-is-plain-object: [2]
|
||||||
no-jquery/no-is-window: [2]
|
no-jquery/no-is-window: [2]
|
||||||
no-jquery/no-is: [0]
|
no-jquery/no-is: [2]
|
||||||
no-jquery/no-jquery-constructor: [0]
|
no-jquery/no-jquery-constructor: [0]
|
||||||
no-jquery/no-live: [2]
|
no-jquery/no-live: [2]
|
||||||
no-jquery/no-load-shorthand: [2]
|
no-jquery/no-load-shorthand: [2]
|
||||||
|
@ -466,7 +463,7 @@ rules:
|
||||||
no-jquery/no-parse-html: [2]
|
no-jquery/no-parse-html: [2]
|
||||||
no-jquery/no-parse-json: [2]
|
no-jquery/no-parse-json: [2]
|
||||||
no-jquery/no-parse-xml: [2]
|
no-jquery/no-parse-xml: [2]
|
||||||
no-jquery/no-prop: [0]
|
no-jquery/no-prop: [2]
|
||||||
no-jquery/no-proxy: [2]
|
no-jquery/no-proxy: [2]
|
||||||
no-jquery/no-ready-shorthand: [2]
|
no-jquery/no-ready-shorthand: [2]
|
||||||
no-jquery/no-ready: [2]
|
no-jquery/no-ready: [2]
|
||||||
|
@ -487,7 +484,7 @@ rules:
|
||||||
no-jquery/no-visibility: [2]
|
no-jquery/no-visibility: [2]
|
||||||
no-jquery/no-when: [2]
|
no-jquery/no-when: [2]
|
||||||
no-jquery/no-wrap: [2]
|
no-jquery/no-wrap: [2]
|
||||||
no-jquery/variable-pattern: [0]
|
no-jquery/variable-pattern: [2]
|
||||||
no-label-var: [2]
|
no-label-var: [2]
|
||||||
no-labels: [0] # handled by no-restricted-syntax
|
no-labels: [0] # handled by no-restricted-syntax
|
||||||
no-lone-blocks: [2]
|
no-lone-blocks: [2]
|
||||||
|
@ -540,7 +537,7 @@ rules:
|
||||||
no-underscore-dangle: [0]
|
no-underscore-dangle: [0]
|
||||||
no-unexpected-multiline: [2]
|
no-unexpected-multiline: [2]
|
||||||
no-unmodified-loop-condition: [2]
|
no-unmodified-loop-condition: [2]
|
||||||
no-unneeded-ternary: [0]
|
no-unneeded-ternary: [2]
|
||||||
no-unreachable-loop: [2]
|
no-unreachable-loop: [2]
|
||||||
no-unreachable: [2]
|
no-unreachable: [2]
|
||||||
no-unsafe-finally: [2]
|
no-unsafe-finally: [2]
|
||||||
|
@ -719,12 +716,14 @@ rules:
|
||||||
unicorn/import-style: [0]
|
unicorn/import-style: [0]
|
||||||
unicorn/new-for-builtins: [2]
|
unicorn/new-for-builtins: [2]
|
||||||
unicorn/no-abusive-eslint-disable: [0]
|
unicorn/no-abusive-eslint-disable: [0]
|
||||||
|
unicorn/no-anonymous-default-export: [0]
|
||||||
unicorn/no-array-callback-reference: [0]
|
unicorn/no-array-callback-reference: [0]
|
||||||
unicorn/no-array-for-each: [2]
|
unicorn/no-array-for-each: [2]
|
||||||
unicorn/no-array-method-this-argument: [2]
|
unicorn/no-array-method-this-argument: [2]
|
||||||
unicorn/no-array-push-push: [2]
|
unicorn/no-array-push-push: [2]
|
||||||
unicorn/no-array-reduce: [2]
|
unicorn/no-array-reduce: [2]
|
||||||
unicorn/no-await-expression-member: [0]
|
unicorn/no-await-expression-member: [0]
|
||||||
|
unicorn/no-await-in-promise-methods: [2]
|
||||||
unicorn/no-console-spaces: [0]
|
unicorn/no-console-spaces: [0]
|
||||||
unicorn/no-document-cookie: [2]
|
unicorn/no-document-cookie: [2]
|
||||||
unicorn/no-empty-file: [2]
|
unicorn/no-empty-file: [2]
|
||||||
|
@ -741,6 +740,7 @@ rules:
|
||||||
unicorn/no-null: [0]
|
unicorn/no-null: [0]
|
||||||
unicorn/no-object-as-default-parameter: [0]
|
unicorn/no-object-as-default-parameter: [0]
|
||||||
unicorn/no-process-exit: [0]
|
unicorn/no-process-exit: [0]
|
||||||
|
unicorn/no-single-promise-in-promise-methods: [2]
|
||||||
unicorn/no-static-only-class: [2]
|
unicorn/no-static-only-class: [2]
|
||||||
unicorn/no-thenable: [2]
|
unicorn/no-thenable: [2]
|
||||||
unicorn/no-this-assignment: [2]
|
unicorn/no-this-assignment: [2]
|
||||||
|
|
|
@ -5,17 +5,29 @@ set -ex
|
||||||
end_to_end=$1
|
end_to_end=$1
|
||||||
end_to_end_pr=$2
|
end_to_end_pr=$2
|
||||||
forgejo=$3
|
forgejo=$3
|
||||||
forgejo_pr=$4
|
forgejo_pr_or_ref=$4
|
||||||
|
|
||||||
|
cd $forgejo
|
||||||
|
full_version=$(make show-version-full)
|
||||||
|
minor_version=$(make show-version-minor)
|
||||||
|
|
||||||
head_url=$(jq --raw-output .head.repo.html_url < $forgejo_pr)
|
|
||||||
test "$head_url" != null
|
|
||||||
branch=$(jq --raw-output .head.ref < $forgejo_pr)
|
|
||||||
test "$branch" != null
|
|
||||||
cd $end_to_end
|
cd $end_to_end
|
||||||
echo $head_url $branch 7.0.0+0-gitea-1.22.0 > forgejo/sources/1.22
|
|
||||||
|
if ! test -f forgejo/sources/$minor_version ; then
|
||||||
|
echo "FAIL: forgejo/sources/$minor_version does not exist in the end-to-end repository"
|
||||||
|
false
|
||||||
|
fi
|
||||||
|
|
||||||
date > last-upgrade
|
date > last-upgrade
|
||||||
|
|
||||||
base_url=$(jq --raw-output .base.repo.html_url < $forgejo_pr)
|
if test -f "$forgejo_pr_or_ref" ; then
|
||||||
test "$base_url" != null
|
forgejo_pr=$forgejo_pr_or_ref
|
||||||
test "$GITHUB_RUN_NUMBER"
|
head_url=$(jq --raw-output .head.repo.html_url < $forgejo_pr)
|
||||||
echo $base_url/actions/runs/$GITHUB_RUN_NUMBER/artifacts/forgejo > forgejo/binary-url
|
test "$head_url" != null
|
||||||
|
branch=$(jq --raw-output .head.ref < $forgejo_pr)
|
||||||
|
test "$branch" != null
|
||||||
|
echo $head_url $branch $full_version > forgejo/sources/$minor_version
|
||||||
|
else
|
||||||
|
forgejo_ref=$forgejo_pr_or_ref
|
||||||
|
echo $GITHUB_SERVER_URL/$GITHUB_REPOSITORY ${forgejo_ref#refs/heads/} $full_version > forgejo/sources/$minor_version
|
||||||
|
fi
|
||||||
|
|
|
@ -9,4 +9,14 @@ forgejo_ref=$4
|
||||||
|
|
||||||
cd $end_to_end
|
cd $end_to_end
|
||||||
date > last-upgrade
|
date > last-upgrade
|
||||||
echo $FORGEJO_BINARY > forgejo/binary-url
|
organizations=lib/ORGANIZATIONS
|
||||||
|
if ! test -f $organizations ; then
|
||||||
|
echo "$organizations file not found"
|
||||||
|
false
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
# do not include forgejo-experimental so that 7.0-test is found
|
||||||
|
# in forgejo-integration where it was just built instead of
|
||||||
|
# forgejo-experimental which was published by the previous build
|
||||||
|
#
|
||||||
|
echo forgejo forgejo-integration > $organizations
|
||||||
|
|
83
.forgejo/workflows/backport.yml
Normal file
83
.forgejo/workflows/backport.yml
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
# Copyright 2024 The Forgejo Authors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
# To modify this workflow:
|
||||||
|
#
|
||||||
|
# - change pull_request_target: to pull_request:
|
||||||
|
# so that it runs from a pull request instead of the default branch
|
||||||
|
#
|
||||||
|
# - push it to the wip-ci-backport branch on the forgejo repository
|
||||||
|
# otherwise it will not have access to the secrets required to push
|
||||||
|
# the PR
|
||||||
|
#
|
||||||
|
# - open a pull request targetting wip-ci-backport that includes a change
|
||||||
|
# that can be backported without conflict in v1.21 and set the
|
||||||
|
# `backport/v1.21` label.
|
||||||
|
#
|
||||||
|
# - once it works, open a pull request for the sake of keeping track
|
||||||
|
# of the change even if the PR won't run it because it will use
|
||||||
|
# whatever is in the default branch instead
|
||||||
|
#
|
||||||
|
# - after it is merged, double check it works by setting a
|
||||||
|
# `backport/v1.21` label on a merged pull request that can be backported
|
||||||
|
# without conflict.
|
||||||
|
#
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- closed
|
||||||
|
- labeled
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
backporting:
|
||||||
|
if: >
|
||||||
|
!startsWith(vars.ROLE, 'forgejo-') && (
|
||||||
|
github.event.pull_request.merged
|
||||||
|
&&
|
||||||
|
contains(toJSON(github.event.pull_request.labels), 'backport/v')
|
||||||
|
)
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: 'docker.io/node:20-bookworm'
|
||||||
|
steps:
|
||||||
|
- name: event info
|
||||||
|
run: |
|
||||||
|
cat <<'EOF'
|
||||||
|
${{ toJSON(github) }}
|
||||||
|
EOF
|
||||||
|
- name: Fetch labels
|
||||||
|
id: fetch-labels
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
echo "Labels retrieved below"
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get -q install -qq -y jq
|
||||||
|
filtered_labels=$(echo "$LABELS" | jq -c 'map(select(.name | startswith("backport/v")))')
|
||||||
|
echo "FILTERED_LABELS=${filtered_labels}" >> $GITHUB_ENV
|
||||||
|
env:
|
||||||
|
LABELS: ${{ toJSON(github.event.pull_request.labels) }}
|
||||||
|
- name: Extract targets
|
||||||
|
id: extract-targets
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
targets="$(echo $FILTERED_LABELS | jq -c '[.[] | .name | sub("backport/"; "")]')"
|
||||||
|
echo "targets=$(echo $targets)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Printing info
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "targets: ${{ steps.extract-targets.outputs.targets }}"
|
||||||
|
echo "target-branch: ${{ fromJSON(steps.extract-targets.outputs.targets)[0] }}"
|
||||||
|
echo "pull-request: ${{ github.event.pull_request.url }}"
|
||||||
|
|
||||||
|
- uses: https://code.forgejo.org/forgejo/git-backporting@b2554a678d5ea2814f0df3abad2ac4fcdee2d81f
|
||||||
|
with:
|
||||||
|
target-branch: ${{ fromJSON(steps.extract-targets.outputs.targets)[0] }}/forgejo
|
||||||
|
strategy: ort
|
||||||
|
strategy-option: find-renames
|
||||||
|
cherry-pick-options: -x
|
||||||
|
auth: ${{ secrets.BACKPORT_TOKEN }}
|
||||||
|
pull-request: ${{ github.event.pull_request.url }}
|
|
@ -9,6 +9,8 @@ on:
|
||||||
- docker/**
|
- docker/**
|
||||||
- .forgejo/workflows/build-release.yml
|
- .forgejo/workflows/build-release.yml
|
||||||
- .forgejo/workflows/build-release-integration.yml
|
- .forgejo/workflows/build-release-integration.yml
|
||||||
|
branches-ignore:
|
||||||
|
- renovate/**
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- Makefile
|
- Makefile
|
||||||
|
|
|
@ -43,7 +43,7 @@ jobs:
|
||||||
|
|
||||||
- uses: https://code.forgejo.org/actions/setup-go@v4
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.21"
|
go-version: "1.22"
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|
||||||
- name: version from ref
|
- name: version from ref
|
||||||
|
@ -203,11 +203,9 @@ jobs:
|
||||||
destination-url: https://code.forgejo.org
|
destination-url: https://code.forgejo.org
|
||||||
destination-fork-repo: ${{ vars.CASCADE_DESTINATION_DOER }}/end-to-end
|
destination-fork-repo: ${{ vars.CASCADE_DESTINATION_DOER }}/end-to-end
|
||||||
destination-repo: forgejo/end-to-end
|
destination-repo: forgejo/end-to-end
|
||||||
destination-branch: forgejo-pr
|
destination-branch: main
|
||||||
destination-token: ${{ secrets.CASCADE_DESTINATION_TOKEN }}
|
destination-token: ${{ secrets.CASCADE_DESTINATION_TOKEN }}
|
||||||
update: .forgejo/cascading-release-end-to-end
|
update: .forgejo/cascading-release-end-to-end
|
||||||
env:
|
|
||||||
FORGEJO_BINARY: "${{ env.GITHUB_SERVER_URL }}/${{ github.repository }}/releases/download/v${{ steps.release-info.outputs.version }}/forgejo-${{ steps.release-info.outputs.version }}-linux-amd64"
|
|
||||||
|
|
||||||
- name: copy to experimental
|
- name: copy to experimental
|
||||||
if: vars.ROLE == 'forgejo-integration' && secrets.TOKEN != ''
|
if: vars.ROLE == 'forgejo-integration' && secrets.TOKEN != ''
|
||||||
|
|
|
@ -1,5 +1,23 @@
|
||||||
|
# Copyright 2024 The Forgejo Authors
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
# To modify this workflow:
|
||||||
|
#
|
||||||
|
# - push it to the wip-ci-end-to-end branch on the forgejo repository
|
||||||
|
# otherwise it will not have access to the secrets required to push
|
||||||
|
# the cascading PR
|
||||||
|
#
|
||||||
|
# - once it works, open a pull request for the sake of keeping track
|
||||||
|
# of the change even if the PR won't run it because it will use
|
||||||
|
# whatever is in the default branch instead
|
||||||
|
#
|
||||||
|
# - after it is merged, double check it works by setting the
|
||||||
|
# run-end-to-end-test on a pull request (any pull request will doe
|
||||||
|
#
|
||||||
on:
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'wip-ci-end-to-end'
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types:
|
types:
|
||||||
- labeled
|
- labeled
|
||||||
|
@ -20,58 +38,37 @@ jobs:
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
${{ toJSON(github.event.pull_request.labels.*.name) }}
|
${{ toJSON(github.event.pull_request.labels.*.name) }}
|
||||||
EOF
|
EOF
|
||||||
|
cat <<'EOF'
|
||||||
build:
|
${{ toJSON(github.event) }}
|
||||||
if: ${{ !startsWith(vars.ROLE, 'forgejo-') && github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests') }}
|
EOF
|
||||||
runs-on: docker
|
|
||||||
container:
|
|
||||||
image: 'docker.io/node:20-bookworm'
|
|
||||||
steps:
|
|
||||||
- uses: https://code.forgejo.org/actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: '0'
|
|
||||||
show-progress: 'false'
|
|
||||||
- name: adduser forgejo
|
|
||||||
run: |
|
|
||||||
git config --add safe.directory '*'
|
|
||||||
git config user.email "you@example.com"
|
|
||||||
git config user.name "Your Name"
|
|
||||||
adduser --quiet --comment forgejo --disabled-password forgejo
|
|
||||||
chown -R forgejo:forgejo .
|
|
||||||
- uses: https://code.forgejo.org/actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: "1.21"
|
|
||||||
- name: make deps-backend
|
|
||||||
run: |
|
|
||||||
su forgejo -c 'make deps-backend'
|
|
||||||
- name: make forgejo
|
|
||||||
run: |
|
|
||||||
su forgejo -c 'make generate-backend static-executable && ln gitea forgejo'
|
|
||||||
env:
|
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: forgejo
|
|
||||||
path: forgejo
|
|
||||||
|
|
||||||
cascade:
|
cascade:
|
||||||
if: ${{ !startsWith(vars.ROLE, 'forgejo-') && github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests') }}
|
if: >
|
||||||
needs: [build]
|
!startsWith(vars.ROLE, 'forgejo-') && (
|
||||||
|
github.event_name == 'push' ||
|
||||||
|
(
|
||||||
|
github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests')
|
||||||
|
)
|
||||||
|
)
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: node:20-bookworm
|
image: node:20-bookworm
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/cascading-pr@v1
|
with:
|
||||||
|
fetch-depth: '0'
|
||||||
|
show-progress: 'false'
|
||||||
|
- uses: actions/cascading-pr@v2
|
||||||
with:
|
with:
|
||||||
origin-url: ${{ env.GITHUB_SERVER_URL }}
|
origin-url: ${{ env.GITHUB_SERVER_URL }}
|
||||||
origin-repo: ${{ github.repository }}
|
origin-repo: ${{ github.repository }}
|
||||||
origin-token: ${{ secrets.END_TO_END_CASCADING_PR_ORIGIN }}
|
origin-token: ${{ secrets.END_TO_END_CASCADING_PR_ORIGIN }}
|
||||||
origin-pr: ${{ github.event.pull_request.number }}
|
origin-pr: ${{ github.event.pull_request.number }}
|
||||||
|
origin-ref: ${{ github.event_name == 'push' && github.event.ref || '' }}
|
||||||
destination-url: https://code.forgejo.org
|
destination-url: https://code.forgejo.org
|
||||||
destination-fork-repo: cascading-pr/end-to-end
|
destination-fork-repo: cascading-pr/end-to-end
|
||||||
destination-repo: forgejo/end-to-end
|
destination-repo: forgejo/end-to-end
|
||||||
destination-branch: forgejo-pr
|
destination-branch: main
|
||||||
destination-token: ${{ secrets.END_TO_END_CASCADING_PR_DESTINATION }}
|
destination-token: ${{ secrets.END_TO_END_CASCADING_PR_DESTINATION }}
|
||||||
close-merge: true
|
close-merge: true
|
||||||
update: .forgejo/cascading-pr-end-to-end
|
update: .forgejo/cascading-pr-end-to-end
|
||||||
|
|
|
@ -17,7 +17,7 @@ jobs:
|
||||||
- uses: https://code.forgejo.org/actions/checkout@v4
|
- uses: https://code.forgejo.org/actions/checkout@v4
|
||||||
- uses: https://code.forgejo.org/actions/setup-go@v4
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "~1.21"
|
go-version: "1.22"
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- run: |
|
- run: |
|
||||||
apt-get -qq update
|
apt-get -qq update
|
||||||
|
|
|
@ -64,7 +64,7 @@ jobs:
|
||||||
if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''
|
if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''
|
||||||
uses: https://code.forgejo.org/actions/setup-go@v4
|
uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.21"
|
go-version: "1.22"
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: update the _release.experimental DNS record
|
- name: update the _release.experimental DNS record
|
||||||
if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''
|
if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''
|
||||||
|
|
58
.forgejo/workflows/renovate.yml
Normal file
58
.forgejo/workflows/renovate.yml
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#
|
||||||
|
# Runs every 2 hours, but Renovate is limited to create new PR before 4am.
|
||||||
|
# See renovate.json for more settings.
|
||||||
|
# Automerge is enabled for Renovate PR's but need to be approved before.
|
||||||
|
#
|
||||||
|
name: renovate
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'renovate/**' # self-test updates
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0/2 * * *'
|
||||||
|
|
||||||
|
env:
|
||||||
|
RENOVATE_DRY_RUN: ${{ (github.event_name != 'schedule' && github.ref_name != github.event.repository.default_branch) && 'full' || '' }}
|
||||||
|
RENOVATE_REPOSITORIES: ${{ github.repository }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
renovate:
|
||||||
|
if: ${{ secrets.RENOVATE_TOKEN != '' }}
|
||||||
|
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: ghcr.io/visualon/renovate:37.280.0
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
.tmp/cache/renovate/repository
|
||||||
|
key: repo-cache-${{ github.run_id }}
|
||||||
|
restore-keys: |
|
||||||
|
repo-cache-
|
||||||
|
|
||||||
|
- run: renovate
|
||||||
|
env:
|
||||||
|
GITHUB_COM_TOKEN: ${{ secrets.RENOVATE_GITHUB_COM_TOKEN }}
|
||||||
|
LOG_LEVEL: debug
|
||||||
|
RENOVATE_BASE_DIR: ${{ github.workspace }}/.tmp
|
||||||
|
RENOVATE_ENDPOINT: ${{ github.server_url }}
|
||||||
|
RENOVATE_PLATFORM: gitea
|
||||||
|
RENOVATE_REPOSITORY_CACHE: 'enabled'
|
||||||
|
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
|
||||||
|
RENOVATE_GIT_AUTHOR: 'Renovate Bot <forgejo-renovate-action@forgejo.org>'
|
||||||
|
|
||||||
|
GIT_AUTHOR_NAME: 'Renovate Bot'
|
||||||
|
GIT_AUTHOR_EMAIL: 'forgejo-renovate-action@forgejo.org'
|
||||||
|
GIT_COMMITTER_NAME: 'Renovate Bot'
|
||||||
|
GIT_COMMITTER_EMAIL: 'forgejo-renovate-action@forgejo.org'
|
||||||
|
|
||||||
|
- name: Save renovate repo cache
|
||||||
|
if: always() && env.RENOVATE_DRY_RUN != 'full'
|
||||||
|
uses: https://code.forgejo.org/actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
.tmp/cache/renovate/repository
|
||||||
|
key: repo-cache-${{ github.run_id }}
|
|
@ -14,15 +14,18 @@ jobs:
|
||||||
container:
|
container:
|
||||||
image: 'docker.io/node:20-bookworm'
|
image: 'docker.io/node:20-bookworm'
|
||||||
steps:
|
steps:
|
||||||
|
- name: event info
|
||||||
|
run: |
|
||||||
|
cat <<'EOF'
|
||||||
|
${{ toJSON(github) }}
|
||||||
|
EOF
|
||||||
- uses: https://code.forgejo.org/actions/checkout@v3
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
- uses: https://code.forgejo.org/actions/setup-go@v4
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.21"
|
go-version: "1.22"
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- run: make deps-backend deps-tools
|
- run: make deps-backend deps-tools
|
||||||
- run: make --always-make -j$(nproc) lint-backend checks-backend # ensure the "go-licenses" make target runs
|
- run: make --always-make -j$(nproc) lint-backend checks-backend # ensure the "go-licenses" make target runs
|
||||||
env:
|
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
|
||||||
frontend-checks:
|
frontend-checks:
|
||||||
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
|
@ -43,15 +46,18 @@ jobs:
|
||||||
image: 'docker.io/node:20-bookworm'
|
image: 'docker.io/node:20-bookworm'
|
||||||
services:
|
services:
|
||||||
minio:
|
minio:
|
||||||
image: 'docker.io/bitnami/minio:2023.8.31'
|
image: bitnami/minio:2024.3.30
|
||||||
|
options: >-
|
||||||
|
--hostname gitea.minio
|
||||||
env:
|
env:
|
||||||
|
MINIO_DOMAIN: minio
|
||||||
MINIO_ROOT_USER: 123456
|
MINIO_ROOT_USER: 123456
|
||||||
MINIO_ROOT_PASSWORD: 12345678
|
MINIO_ROOT_PASSWORD: 12345678
|
||||||
steps:
|
steps:
|
||||||
- uses: https://code.forgejo.org/actions/checkout@v3
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
- uses: https://code.forgejo.org/actions/setup-go@v4
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.21"
|
go-version: "1.22"
|
||||||
- run: |
|
- run: |
|
||||||
git config --add safe.directory '*'
|
git config --add safe.directory '*'
|
||||||
adduser --quiet --comment forgejo --disabled-password forgejo
|
adduser --quiet --comment forgejo --disabled-password forgejo
|
||||||
|
@ -96,7 +102,7 @@ jobs:
|
||||||
- uses: https://code.forgejo.org/actions/checkout@v3
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
- uses: https://code.forgejo.org/actions/setup-go@v4
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.21"
|
go-version: "1.22"
|
||||||
- name: install dependencies & git >= 2.42
|
- name: install dependencies & git >= 2.42
|
||||||
run: |
|
run: |
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
@ -130,10 +136,10 @@ jobs:
|
||||||
image: 'docker.io/node:20-bookworm'
|
image: 'docker.io/node:20-bookworm'
|
||||||
services:
|
services:
|
||||||
minio:
|
minio:
|
||||||
image: bitnami/minio:2021.3.17
|
image: bitnami/minio:2024.3.30
|
||||||
env:
|
env:
|
||||||
MINIO_ACCESS_KEY: 123456
|
MINIO_ROOT_USER: 123456
|
||||||
MINIO_SECRET_KEY: 12345678
|
MINIO_ROOT_PASSWORD: 12345678
|
||||||
pgsql:
|
pgsql:
|
||||||
image: 'docker.io/postgres:15'
|
image: 'docker.io/postgres:15'
|
||||||
env:
|
env:
|
||||||
|
@ -143,7 +149,7 @@ jobs:
|
||||||
- uses: https://code.forgejo.org/actions/checkout@v3
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
- uses: https://code.forgejo.org/actions/setup-go@v4
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.21"
|
go-version: "1.22"
|
||||||
- name: install dependencies & git >= 2.42
|
- name: install dependencies & git >= 2.42
|
||||||
run: |
|
run: |
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
@ -180,7 +186,7 @@ jobs:
|
||||||
- uses: https://code.forgejo.org/actions/checkout@v3
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
- uses: https://code.forgejo.org/actions/setup-go@v4
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.21"
|
go-version: "1.22"
|
||||||
- name: install dependencies & git >= 2.42
|
- name: install dependencies & git >= 2.42
|
||||||
run: |
|
run: |
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
name: 🦋 Bug Report (web interface / frontend)
|
name: 🦋 Bug Report (web interface / frontend)
|
||||||
description: Something doesn't look quite as it should? Report it here!
|
description: Something doesn't look quite as it should? Report it here!
|
||||||
title: "[BUG] "
|
title: "[BUG] "
|
||||||
labels: ["bug", "forgejo/ui"]
|
labels: ["bug/new-report", "forgejo/ui"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
name: 🐛 Bug Report (server / backend)
|
name: 🐛 Bug Report (server / backend)
|
||||||
description: Found something you weren't expecting? Report it here!
|
description: Found something you weren't expecting? Report it here!
|
||||||
title: "[BUG] "
|
title: "[BUG] "
|
||||||
labels: bug
|
labels: bug/new-report
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
@ -87,4 +87,3 @@ body:
|
||||||
- SQLite
|
- SQLite
|
||||||
- PostgreSQL
|
- PostgreSQL
|
||||||
- MySQL
|
- MySQL
|
||||||
- MSSQL
|
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
name: "Pull Request Template"
|
||||||
|
about: "Template for all Pull Requests"
|
||||||
|
labels:
|
||||||
|
|
||||||
|
- test/needed
|
||||||
|
|
||||||
|
---
|
||||||
<!--
|
<!--
|
||||||
Before submitting a PR, please read the contributing guidelines:
|
Before submitting a PR, please read the contributing guidelines:
|
||||||
https://codeberg.org/forgejo/forgejo/src/branch/forgejo/CONTRIBUTING.md
|
https://codeberg.org/forgejo/forgejo/src/branch/forgejo/CONTRIBUTING.md
|
||||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -18,7 +18,7 @@ _test
|
||||||
|
|
||||||
# MS VSCode
|
# MS VSCode
|
||||||
.vscode
|
.vscode
|
||||||
__debug_bin
|
__debug_bin*
|
||||||
|
|
||||||
*.cgo1.go
|
*.cgo1.go
|
||||||
*.cgo2.c
|
*.cgo2.c
|
||||||
|
@ -64,7 +64,7 @@ cpu.out
|
||||||
/data
|
/data
|
||||||
/indexers
|
/indexers
|
||||||
/log
|
/log
|
||||||
/public/img/avatar
|
/public/assets/img/avatar
|
||||||
/tests/integration/gitea-integration-*
|
/tests/integration/gitea-integration-*
|
||||||
/tests/integration/indexers-*
|
/tests/integration/indexers-*
|
||||||
/tests/e2e/gitea-e2e-*
|
/tests/e2e/gitea-e2e-*
|
||||||
|
@ -83,7 +83,6 @@ cpu.out
|
||||||
/public/assets/css
|
/public/assets/css
|
||||||
/public/assets/fonts
|
/public/assets/fonts
|
||||||
/public/assets/licenses.txt
|
/public/assets/licenses.txt
|
||||||
/public/assets/img/webpack
|
|
||||||
/vendor
|
/vendor
|
||||||
/web_src/fomantic/node_modules
|
/web_src/fomantic/node_modules
|
||||||
/web_src/fomantic/build/*
|
/web_src/fomantic/build/*
|
||||||
|
|
|
@ -42,7 +42,7 @@ vscode:
|
||||||
- DavidAnson.vscode-markdownlint
|
- DavidAnson.vscode-markdownlint
|
||||||
- Vue.volar
|
- Vue.volar
|
||||||
- ms-azuretools.vscode-docker
|
- ms-azuretools.vscode-docker
|
||||||
- zixuanchen.vitest-explorer
|
- vitest.explorer
|
||||||
- qwtel.sqlite-viewer
|
- qwtel.sqlite-viewer
|
||||||
- GitHub.vscode-pull-request-github
|
- GitHub.vscode-pull-request-github
|
||||||
|
|
||||||
|
|
4
.ignore
4
.ignore
|
@ -4,6 +4,8 @@
|
||||||
/modules/options/bindata.go
|
/modules/options/bindata.go
|
||||||
/modules/public/bindata.go
|
/modules/public/bindata.go
|
||||||
/modules/templates/bindata.go
|
/modules/templates/bindata.go
|
||||||
/vendor
|
/options/gitignore
|
||||||
|
/options/license
|
||||||
/public/assets
|
/public/assets
|
||||||
|
/vendor
|
||||||
node_modules
|
node_modules
|
||||||
|
|
|
@ -1,221 +0,0 @@
|
||||||
plugins:
|
|
||||||
- stylelint-declaration-strict-value
|
|
||||||
- stylelint-declaration-block-no-ignored-properties
|
|
||||||
- "@stylistic/stylelint-plugin"
|
|
||||||
|
|
||||||
ignoreFiles:
|
|
||||||
- "**/*.go"
|
|
||||||
|
|
||||||
overrides:
|
|
||||||
- files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console.css", "font_i18n.css"]
|
|
||||||
rules:
|
|
||||||
scale-unlimited/declaration-strict-value: null
|
|
||||||
- files: ["**/chroma/*", "**/codemirror/*"]
|
|
||||||
rules:
|
|
||||||
block-no-empty: null
|
|
||||||
- files: ["**/*.vue"]
|
|
||||||
customSyntax: postcss-html
|
|
||||||
|
|
||||||
rules:
|
|
||||||
"@stylistic/at-rule-name-case": null
|
|
||||||
"@stylistic/at-rule-name-newline-after": null
|
|
||||||
"@stylistic/at-rule-name-space-after": null
|
|
||||||
"@stylistic/at-rule-semicolon-newline-after": null
|
|
||||||
"@stylistic/at-rule-semicolon-space-before": null
|
|
||||||
"@stylistic/block-closing-brace-empty-line-before": null
|
|
||||||
"@stylistic/block-closing-brace-newline-after": null
|
|
||||||
"@stylistic/block-closing-brace-newline-before": null
|
|
||||||
"@stylistic/block-closing-brace-space-after": null
|
|
||||||
"@stylistic/block-closing-brace-space-before": null
|
|
||||||
"@stylistic/block-opening-brace-newline-after": null
|
|
||||||
"@stylistic/block-opening-brace-newline-before": null
|
|
||||||
"@stylistic/block-opening-brace-space-after": null
|
|
||||||
"@stylistic/block-opening-brace-space-before": null
|
|
||||||
"@stylistic/color-hex-case": lower
|
|
||||||
"@stylistic/declaration-bang-space-after": never
|
|
||||||
"@stylistic/declaration-bang-space-before": null
|
|
||||||
"@stylistic/declaration-block-semicolon-newline-after": null
|
|
||||||
"@stylistic/declaration-block-semicolon-newline-before": null
|
|
||||||
"@stylistic/declaration-block-semicolon-space-after": null
|
|
||||||
"@stylistic/declaration-block-semicolon-space-before": never
|
|
||||||
"@stylistic/declaration-block-trailing-semicolon": null
|
|
||||||
"@stylistic/declaration-colon-newline-after": null
|
|
||||||
"@stylistic/declaration-colon-space-after": null
|
|
||||||
"@stylistic/declaration-colon-space-before": never
|
|
||||||
"@stylistic/function-comma-newline-after": null
|
|
||||||
"@stylistic/function-comma-newline-before": null
|
|
||||||
"@stylistic/function-comma-space-after": null
|
|
||||||
"@stylistic/function-comma-space-before": null
|
|
||||||
"@stylistic/function-max-empty-lines": 0
|
|
||||||
"@stylistic/function-parentheses-newline-inside": never-multi-line
|
|
||||||
"@stylistic/function-parentheses-space-inside": null
|
|
||||||
"@stylistic/function-whitespace-after": null
|
|
||||||
"@stylistic/indentation": 2
|
|
||||||
"@stylistic/linebreaks": null
|
|
||||||
"@stylistic/max-empty-lines": 1
|
|
||||||
"@stylistic/max-line-length": null
|
|
||||||
"@stylistic/media-feature-colon-space-after": null
|
|
||||||
"@stylistic/media-feature-colon-space-before": never
|
|
||||||
"@stylistic/media-feature-name-case": null
|
|
||||||
"@stylistic/media-feature-parentheses-space-inside": null
|
|
||||||
"@stylistic/media-feature-range-operator-space-after": always
|
|
||||||
"@stylistic/media-feature-range-operator-space-before": always
|
|
||||||
"@stylistic/media-query-list-comma-newline-after": null
|
|
||||||
"@stylistic/media-query-list-comma-newline-before": null
|
|
||||||
"@stylistic/media-query-list-comma-space-after": null
|
|
||||||
"@stylistic/media-query-list-comma-space-before": null
|
|
||||||
"@stylistic/no-empty-first-line": null
|
|
||||||
"@stylistic/no-eol-whitespace": true
|
|
||||||
"@stylistic/no-extra-semicolons": true
|
|
||||||
"@stylistic/no-missing-end-of-source-newline": null
|
|
||||||
"@stylistic/number-leading-zero": null
|
|
||||||
"@stylistic/number-no-trailing-zeros": null
|
|
||||||
"@stylistic/property-case": lower
|
|
||||||
"@stylistic/selector-attribute-brackets-space-inside": null
|
|
||||||
"@stylistic/selector-attribute-operator-space-after": null
|
|
||||||
"@stylistic/selector-attribute-operator-space-before": null
|
|
||||||
"@stylistic/selector-combinator-space-after": null
|
|
||||||
"@stylistic/selector-combinator-space-before": null
|
|
||||||
"@stylistic/selector-descendant-combinator-no-non-space": null
|
|
||||||
"@stylistic/selector-list-comma-newline-after": null
|
|
||||||
"@stylistic/selector-list-comma-newline-before": null
|
|
||||||
"@stylistic/selector-list-comma-space-after": always-single-line
|
|
||||||
"@stylistic/selector-list-comma-space-before": never-single-line
|
|
||||||
"@stylistic/selector-max-empty-lines": 0
|
|
||||||
"@stylistic/selector-pseudo-class-case": lower
|
|
||||||
"@stylistic/selector-pseudo-class-parentheses-space-inside": never
|
|
||||||
"@stylistic/selector-pseudo-element-case": lower
|
|
||||||
"@stylistic/string-quotes": double
|
|
||||||
"@stylistic/unicode-bom": null
|
|
||||||
"@stylistic/unit-case": lower
|
|
||||||
"@stylistic/value-list-comma-newline-after": null
|
|
||||||
"@stylistic/value-list-comma-newline-before": null
|
|
||||||
"@stylistic/value-list-comma-space-after": null
|
|
||||||
"@stylistic/value-list-comma-space-before": null
|
|
||||||
"@stylistic/value-list-max-empty-lines": 0
|
|
||||||
alpha-value-notation: null
|
|
||||||
annotation-no-unknown: true
|
|
||||||
at-rule-allowed-list: null
|
|
||||||
at-rule-disallowed-list: null
|
|
||||||
at-rule-empty-line-before: null
|
|
||||||
at-rule-no-unknown: [true, {ignoreAtRules: [tailwind]}]
|
|
||||||
at-rule-no-vendor-prefix: true
|
|
||||||
at-rule-property-required-list: null
|
|
||||||
block-no-empty: true
|
|
||||||
color-function-notation: null
|
|
||||||
color-hex-alpha: null
|
|
||||||
color-hex-length: null
|
|
||||||
color-named: null
|
|
||||||
color-no-hex: null
|
|
||||||
color-no-invalid-hex: true
|
|
||||||
comment-empty-line-before: null
|
|
||||||
comment-no-empty: true
|
|
||||||
comment-pattern: null
|
|
||||||
comment-whitespace-inside: null
|
|
||||||
comment-word-disallowed-list: null
|
|
||||||
custom-media-pattern: null
|
|
||||||
custom-property-empty-line-before: null
|
|
||||||
custom-property-no-missing-var-function: true
|
|
||||||
custom-property-pattern: null
|
|
||||||
declaration-block-no-duplicate-custom-properties: true
|
|
||||||
declaration-block-no-duplicate-properties: [true, {ignore: [consecutive-duplicates-with-different-values]}]
|
|
||||||
declaration-block-no-redundant-longhand-properties: null
|
|
||||||
declaration-block-no-shorthand-property-overrides: null
|
|
||||||
declaration-block-single-line-max-declarations: null
|
|
||||||
declaration-empty-line-before: null
|
|
||||||
declaration-no-important: null
|
|
||||||
declaration-property-max-values: null
|
|
||||||
declaration-property-unit-allowed-list: null
|
|
||||||
declaration-property-unit-disallowed-list: {line-height: [em]}
|
|
||||||
declaration-property-value-allowed-list: null
|
|
||||||
declaration-property-value-disallowed-list: null
|
|
||||||
declaration-property-value-no-unknown: true
|
|
||||||
font-family-name-quotes: always-where-recommended
|
|
||||||
font-family-no-duplicate-names: true
|
|
||||||
font-family-no-missing-generic-family-keyword: true
|
|
||||||
font-weight-notation: null
|
|
||||||
function-allowed-list: null
|
|
||||||
function-calc-no-unspaced-operator: true
|
|
||||||
function-disallowed-list: null
|
|
||||||
function-linear-gradient-no-nonstandard-direction: true
|
|
||||||
function-name-case: lower
|
|
||||||
function-no-unknown: null
|
|
||||||
function-url-no-scheme-relative: null
|
|
||||||
function-url-quotes: always
|
|
||||||
function-url-scheme-allowed-list: null
|
|
||||||
function-url-scheme-disallowed-list: null
|
|
||||||
hue-degree-notation: null
|
|
||||||
import-notation: string
|
|
||||||
keyframe-block-no-duplicate-selectors: true
|
|
||||||
keyframe-declaration-no-important: true
|
|
||||||
keyframe-selector-notation: null
|
|
||||||
keyframes-name-pattern: null
|
|
||||||
length-zero-no-unit: [true, ignore: [custom-properties], ignoreFunctions: [var]]
|
|
||||||
max-nesting-depth: null
|
|
||||||
media-feature-name-allowed-list: null
|
|
||||||
media-feature-name-disallowed-list: null
|
|
||||||
media-feature-name-no-unknown: true
|
|
||||||
media-feature-name-no-vendor-prefix: true
|
|
||||||
media-feature-name-unit-allowed-list: null
|
|
||||||
media-feature-name-value-allowed-list: null
|
|
||||||
media-feature-name-value-no-unknown: true
|
|
||||||
media-feature-range-notation: null
|
|
||||||
media-query-no-invalid: true
|
|
||||||
named-grid-areas-no-invalid: true
|
|
||||||
no-descending-specificity: null
|
|
||||||
no-duplicate-at-import-rules: true
|
|
||||||
no-duplicate-selectors: true
|
|
||||||
no-empty-source: true
|
|
||||||
no-invalid-double-slash-comments: true
|
|
||||||
no-invalid-position-at-import-rule: null
|
|
||||||
no-irregular-whitespace: true
|
|
||||||
no-unknown-animations: null
|
|
||||||
no-unknown-custom-properties: null
|
|
||||||
number-max-precision: null
|
|
||||||
plugin/declaration-block-no-ignored-properties: true
|
|
||||||
property-allowed-list: null
|
|
||||||
property-disallowed-list: null
|
|
||||||
property-no-unknown: true
|
|
||||||
property-no-vendor-prefix: null
|
|
||||||
rule-empty-line-before: null
|
|
||||||
rule-selector-property-disallowed-list: null
|
|
||||||
scale-unlimited/declaration-strict-value: [[/color$/, font-weight], {ignoreValues: /^(inherit|transparent|unset|initial|currentcolor|none)$/, ignoreFunctions: false, disableFix: true, expandShorthand: true}]
|
|
||||||
selector-attribute-name-disallowed-list: null
|
|
||||||
selector-attribute-operator-allowed-list: null
|
|
||||||
selector-attribute-operator-disallowed-list: null
|
|
||||||
selector-attribute-quotes: always
|
|
||||||
selector-class-pattern: null
|
|
||||||
selector-combinator-allowed-list: null
|
|
||||||
selector-combinator-disallowed-list: null
|
|
||||||
selector-disallowed-list: null
|
|
||||||
selector-id-pattern: null
|
|
||||||
selector-max-attribute: null
|
|
||||||
selector-max-class: null
|
|
||||||
selector-max-combinators: null
|
|
||||||
selector-max-compound-selectors: null
|
|
||||||
selector-max-id: null
|
|
||||||
selector-max-pseudo-class: null
|
|
||||||
selector-max-specificity: null
|
|
||||||
selector-max-type: null
|
|
||||||
selector-max-universal: null
|
|
||||||
selector-nested-pattern: null
|
|
||||||
selector-no-qualifying-type: null
|
|
||||||
selector-no-vendor-prefix: true
|
|
||||||
selector-not-notation: null
|
|
||||||
selector-pseudo-class-allowed-list: null
|
|
||||||
selector-pseudo-class-disallowed-list: null
|
|
||||||
selector-pseudo-class-no-unknown: true
|
|
||||||
selector-pseudo-element-allowed-list: null
|
|
||||||
selector-pseudo-element-colon-notation: double
|
|
||||||
selector-pseudo-element-disallowed-list: null
|
|
||||||
selector-pseudo-element-no-unknown: true
|
|
||||||
selector-type-case: lower
|
|
||||||
selector-type-no-unknown: [true, {ignore: [custom-elements]}]
|
|
||||||
shorthand-property-no-redundant-values: true
|
|
||||||
string-no-newline: true
|
|
||||||
time-min-milliseconds: null
|
|
||||||
unit-allowed-list: null
|
|
||||||
unit-disallowed-list: null
|
|
||||||
unit-no-unknown: true
|
|
||||||
value-keyword-case: null
|
|
||||||
value-no-vendor-prefix: [true, {ignoreValues: [box, inline-box]}]
|
|
8355
CHANGELOG.md
8355
CHANGELOG.md
File diff suppressed because it is too large
Load diff
|
@ -30,3 +30,9 @@ models/.* @dachary @earl-warren @gusted
|
||||||
# of how Forgejo comes together. It's tedious to write good integration testing
|
# of how Forgejo comes together. It's tedious to write good integration testing
|
||||||
# for code that lives in here.
|
# for code that lives in here.
|
||||||
routers/.* @dachary @earl-warren @gusted
|
routers/.* @dachary @earl-warren @gusted
|
||||||
|
|
||||||
|
# Let new strings be checked by the translation team.
|
||||||
|
options/locale/locale_en-US.ini @0ko
|
||||||
|
|
||||||
|
# Personal interest
|
||||||
|
.*/webhook.* @oliverpool
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
|
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.21-alpine3.19 as build-env
|
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.22-alpine3.19 as build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY ${GOPROXY:-direct}
|
ENV GOPROXY ${GOPROXY:-direct}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
|
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.21-alpine3.19 as build-env
|
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.22-alpine3.19 as build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY ${GOPROXY:-direct}
|
ENV GOPROXY ${GOPROXY:-direct}
|
||||||
|
|
191
Makefile
191
Makefile
|
@ -44,9 +44,6 @@ DOCKER_TAG ?= latest
|
||||||
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
|
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
|
||||||
|
|
||||||
ifeq ($(HAS_GO), yes)
|
ifeq ($(HAS_GO), yes)
|
||||||
GOPATH ?= $(shell $(GO) env GOPATH)
|
|
||||||
export PATH := $(GOPATH)/bin:$(PATH)
|
|
||||||
|
|
||||||
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
|
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
|
||||||
CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
|
CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
|
||||||
endif
|
endif
|
||||||
|
@ -91,24 +88,49 @@ STORED_VERSION=$(shell cat $(STORED_VERSION_FILE) 2>/dev/null)
|
||||||
ifneq ($(STORED_VERSION),)
|
ifneq ($(STORED_VERSION),)
|
||||||
FORGEJO_VERSION ?= $(STORED_VERSION)
|
FORGEJO_VERSION ?= $(STORED_VERSION)
|
||||||
else
|
else
|
||||||
FORGEJO_VERSION ?= $(shell git describe --exclude '*-test' --tags --always | sed 's/^v//')+${GITEA_COMPATIBILITY}
|
ifneq ($(GITEA_VERSION),)
|
||||||
|
FORGEJO_VERSION ?= $(GITEA_VERSION)
|
||||||
|
FORGEJO_VERSION_API ?= $(GITEA_VERSION)+${GITEA_COMPATIBILITY}
|
||||||
|
else
|
||||||
|
# drop the "g" prefix prepended by git describe to the commit hash
|
||||||
|
FORGEJO_VERSION ?= $(shell git describe --exclude '*-test' --tags --always | sed 's/^v//' | sed 's/\-g/-/')+${GITEA_COMPATIBILITY}
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
FORGEJO_VERSION_MAJOR=$(shell echo $(FORGEJO_VERSION) | sed -e 's/\..*//')
|
||||||
|
FORGEJO_VERSION_MINOR=$(shell echo $(FORGEJO_VERSION) | sed -E -e 's/^([0-9]+\.[0-9]+).*/\1/')
|
||||||
|
|
||||||
|
show-version-full:
|
||||||
|
@echo ${FORGEJO_VERSION}
|
||||||
|
|
||||||
|
show-version-major:
|
||||||
|
@echo ${FORGEJO_VERSION_MAJOR}
|
||||||
|
|
||||||
|
show-version-minor:
|
||||||
|
@echo ${FORGEJO_VERSION_MINOR}
|
||||||
|
|
||||||
RELEASE_VERSION ?= ${FORGEJO_VERSION}
|
RELEASE_VERSION ?= ${FORGEJO_VERSION}
|
||||||
VERSION ?= ${RELEASE_VERSION}
|
VERSION ?= ${RELEASE_VERSION}
|
||||||
|
|
||||||
LDFLAGS := $(LDFLAGS) -X "main.ReleaseVersion=$(RELEASE_VERSION)" -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(FORGEJO_VERSION)" -X "main.Tags=$(TAGS)" -X "main.ForgejoVersion=$(FORGEJO_VERSION)"
|
FORGEJO_VERSION_API ?= ${FORGEJO_VERSION}
|
||||||
|
|
||||||
|
show-version-api:
|
||||||
|
@echo ${FORGEJO_VERSION_API}
|
||||||
|
|
||||||
|
LDFLAGS := $(LDFLAGS) -X "main.ReleaseVersion=$(RELEASE_VERSION)" -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(FORGEJO_VERSION)" -X "main.Tags=$(TAGS)" -X "main.ForgejoVersion=$(FORGEJO_VERSION_API)"
|
||||||
|
|
||||||
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
|
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
|
||||||
|
|
||||||
GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
|
ifeq ($(HAS_GO), yes)
|
||||||
GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) $(shell $(GO) list code.gitea.io/gitea/models/forgejo_migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
|
GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
|
||||||
|
GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) $(shell $(GO) list code.gitea.io/gitea/models/forgejo_migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
|
||||||
|
endif
|
||||||
|
|
||||||
FOMANTIC_WORK_DIR := web_src/fomantic
|
FOMANTIC_WORK_DIR := web_src/fomantic
|
||||||
|
|
||||||
WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
|
WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
|
||||||
WEBPACK_CONFIGS := webpack.config.js tailwind.config.js
|
WEBPACK_CONFIGS := webpack.config.js tailwind.config.js
|
||||||
WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css
|
WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css
|
||||||
WEBPACK_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts public/assets/img/webpack
|
WEBPACK_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts
|
||||||
|
|
||||||
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
|
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
|
||||||
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
|
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
|
||||||
|
@ -133,6 +155,8 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMAN
|
||||||
GO_DIRS := build cmd models modules routers services tests
|
GO_DIRS := build cmd models modules routers services tests
|
||||||
WEB_DIRS := web_src/js web_src/css
|
WEB_DIRS := web_src/js web_src/css
|
||||||
|
|
||||||
|
ESLINT_FILES := web_src/js tools *.config.js tests/e2e
|
||||||
|
STYLELINT_FILES := web_src/css web_src/js/components/*.vue
|
||||||
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github
|
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github
|
||||||
|
|
||||||
GO_SOURCES := $(wildcard *.go)
|
GO_SOURCES := $(wildcard *.go)
|
||||||
|
@ -140,7 +164,9 @@ GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" ! -path modules/optio
|
||||||
GO_SOURCES += $(GENERATED_GO_DEST)
|
GO_SOURCES += $(GENERATED_GO_DEST)
|
||||||
GO_SOURCES_NO_BINDATA := $(GO_SOURCES)
|
GO_SOURCES_NO_BINDATA := $(GO_SOURCES)
|
||||||
|
|
||||||
MIGRATION_PACKAGES := $(shell $(GO) list code.gitea.io/gitea/models/migrations/... code.gitea.io/gitea/models/forgejo_migrations/...)
|
ifeq ($(HAS_GO), yes)
|
||||||
|
MIGRATION_PACKAGES := $(shell $(GO) list code.gitea.io/gitea/models/migrations/... code.gitea.io/gitea/models/forgejo_migrations/...)
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
|
ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
|
||||||
GO_SOURCES += $(BINDATA_DEST)
|
GO_SOURCES += $(BINDATA_DEST)
|
||||||
|
@ -170,10 +196,6 @@ TEST_PGSQL_DBNAME ?= testgitea
|
||||||
TEST_PGSQL_USERNAME ?= postgres
|
TEST_PGSQL_USERNAME ?= postgres
|
||||||
TEST_PGSQL_PASSWORD ?= postgres
|
TEST_PGSQL_PASSWORD ?= postgres
|
||||||
TEST_PGSQL_SCHEMA ?= gtestschema
|
TEST_PGSQL_SCHEMA ?= gtestschema
|
||||||
TEST_MSSQL_HOST ?= mssql:1433
|
|
||||||
TEST_MSSQL_DBNAME ?= gitea
|
|
||||||
TEST_MSSQL_USERNAME ?= sa
|
|
||||||
TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
|
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: build
|
all: build
|
||||||
|
@ -219,6 +241,8 @@ help:
|
||||||
@echo " - checks-frontend check frontend files"
|
@echo " - checks-frontend check frontend files"
|
||||||
@echo " - checks-backend check backend files"
|
@echo " - checks-backend check backend files"
|
||||||
@echo " - test test everything"
|
@echo " - test test everything"
|
||||||
|
@echo " - show-version-full show the same version as the API endpoint"
|
||||||
|
@echo " - show-version-major show major release number only"
|
||||||
@echo " - test-frontend test frontend files"
|
@echo " - test-frontend test frontend files"
|
||||||
@echo " - test-backend test backend files"
|
@echo " - test-backend test backend files"
|
||||||
@echo " - test-e2e[\#TestSpecificName] test end to end using playwright"
|
@echo " - test-e2e[\#TestSpecificName] test end to end using playwright"
|
||||||
|
@ -281,7 +305,7 @@ clean:
|
||||||
e2e*.test \
|
e2e*.test \
|
||||||
tests/integration/gitea-integration-* \
|
tests/integration/gitea-integration-* \
|
||||||
tests/integration/indexers-* \
|
tests/integration/indexers-* \
|
||||||
tests/mysql.ini tests/pgsql.ini tests/mssql.ini man/ \
|
tests/mysql.ini tests/pgsql.ini man/ \
|
||||||
tests/e2e/gitea-e2e-*/ \
|
tests/e2e/gitea-e2e-*/ \
|
||||||
tests/e2e/indexers-*/ \
|
tests/e2e/indexers-*/ \
|
||||||
tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/
|
tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/
|
||||||
|
@ -299,12 +323,8 @@ fmt:
|
||||||
|
|
||||||
.PHONY: fmt-check
|
.PHONY: fmt-check
|
||||||
fmt-check: fmt
|
fmt-check: fmt
|
||||||
@diff=$$(git diff --color=always $(GO_SOURCES) templates $(WEB_DIRS)); \
|
@git diff --exit-code --color=always $(GO_SOURCES) templates $(WEB_DIRS) \
|
||||||
if [ -n "$$diff" ]; then \
|
|| (code=$$?; echo "Please run 'make fmt' and commit the result"; exit $${code})
|
||||||
echo "Please run 'make fmt' and commit the result:"; \
|
|
||||||
echo "$${diff}"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
.PHONY: $(TAGS_EVIDENCE)
|
.PHONY: $(TAGS_EVIDENCE)
|
||||||
$(TAGS_EVIDENCE):
|
$(TAGS_EVIDENCE):
|
||||||
|
@ -325,12 +345,8 @@ generate-forgejo-api: $(FORGEJO_API_SPEC)
|
||||||
|
|
||||||
.PHONY: forgejo-api-check
|
.PHONY: forgejo-api-check
|
||||||
forgejo-api-check: generate-forgejo-api
|
forgejo-api-check: generate-forgejo-api
|
||||||
@diff=$$(git diff $(FORGEJO_API_SERVER) ; \
|
@git diff --exit-code --color=always $(FORGEJO_API_SERVER) \
|
||||||
if [ -n "$$diff" ]; then \
|
|| (code=$$?; echo "Please run 'make generate-forgejo-api' and commit the result"; exit $${code})
|
||||||
echo "Please run 'make generate-forgejo-api' and commit the result:"; \
|
|
||||||
echo "$${diff}"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
.PHONY: forgejo-api-validate
|
.PHONY: forgejo-api-validate
|
||||||
forgejo-api-validate:
|
forgejo-api-validate:
|
||||||
|
@ -347,12 +363,8 @@ $(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA)
|
||||||
|
|
||||||
.PHONY: swagger-check
|
.PHONY: swagger-check
|
||||||
swagger-check: generate-swagger
|
swagger-check: generate-swagger
|
||||||
@diff=$$(git diff --color=always '$(SWAGGER_SPEC)'); \
|
@git diff --exit-code --color=always '$(SWAGGER_SPEC)' \
|
||||||
if [ -n "$$diff" ]; then \
|
|| (code=$$?; echo "Please run 'make generate-swagger' and commit the result"; exit $${code})
|
||||||
echo "Please run 'make generate-swagger' and commit the result:"; \
|
|
||||||
echo "$${diff}"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
.PHONY: swagger-validate
|
.PHONY: swagger-validate
|
||||||
swagger-validate:
|
swagger-validate:
|
||||||
|
@ -389,19 +401,19 @@ lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig
|
||||||
|
|
||||||
.PHONY: lint-js
|
.PHONY: lint-js
|
||||||
lint-js: node_modules
|
lint-js: node_modules
|
||||||
npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js tests/e2e
|
npx eslint --color --max-warnings=0 --ext js,vue $(ESLINT_FILES)
|
||||||
|
|
||||||
.PHONY: lint-js-fix
|
.PHONY: lint-js-fix
|
||||||
lint-js-fix: node_modules
|
lint-js-fix: node_modules
|
||||||
npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js tests/e2e --fix
|
npx eslint --color --max-warnings=0 --ext js,vue $(ESLINT_FILES) --fix
|
||||||
|
|
||||||
.PHONY: lint-css
|
.PHONY: lint-css
|
||||||
lint-css: node_modules
|
lint-css: node_modules
|
||||||
npx stylelint --color --max-warnings=0 web_src/css web_src/js/components/*.vue
|
npx stylelint --color --max-warnings=0 $(STYLELINT_FILES)
|
||||||
|
|
||||||
.PHONY: lint-css-fix
|
.PHONY: lint-css-fix
|
||||||
lint-css-fix: node_modules
|
lint-css-fix: node_modules
|
||||||
npx stylelint --color --max-warnings=0 web_src/css web_src/js/components/*.vue --fix
|
npx stylelint --color --max-warnings=0 $(STYLELINT_FILES) --fix
|
||||||
|
|
||||||
.PHONY: lint-swagger
|
.PHONY: lint-swagger
|
||||||
lint-swagger: node_modules
|
lint-swagger: node_modules
|
||||||
|
@ -423,11 +435,8 @@ lint-spell-fix:
|
||||||
lint-go:
|
lint-go:
|
||||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run $(GOLANGCI_LINT_ARGS)
|
$(GO) run $(GOLANGCI_LINT_PACKAGE) run $(GOLANGCI_LINT_ARGS)
|
||||||
$(GO) run $(DEADCODE_PACKAGE) -generated=false -test code.gitea.io/gitea > .cur-deadcode-out
|
$(GO) run $(DEADCODE_PACKAGE) -generated=false -test code.gitea.io/gitea > .cur-deadcode-out
|
||||||
@$(DIFF) .deadcode-out .cur-deadcode-out; \
|
@$(DIFF) .deadcode-out .cur-deadcode-out \
|
||||||
if [ $$? -eq 1 ]; then \
|
|| (code=$$?; echo "Please run 'make lint-go-fix' and commit the result"; exit $${code})
|
||||||
echo "Please run 'make lint-go-fix' and commit the result"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
.PHONY: lint-go-fix
|
.PHONY: lint-go-fix
|
||||||
lint-go-fix:
|
lint-go-fix:
|
||||||
|
@ -455,7 +464,8 @@ lint-actions:
|
||||||
$(GO) run $(ACTIONLINT_PACKAGE)
|
$(GO) run $(ACTIONLINT_PACKAGE)
|
||||||
|
|
||||||
.PHONY: lint-templates
|
.PHONY: lint-templates
|
||||||
lint-templates: .venv
|
lint-templates: .venv node_modules
|
||||||
|
@node tools/lint-templates-svg.js
|
||||||
@poetry run djlint $(shell find templates -type f -iname '*.tmpl')
|
@poetry run djlint $(shell find templates -type f -iname '*.tmpl')
|
||||||
|
|
||||||
.PHONY: lint-yaml
|
.PHONY: lint-yaml
|
||||||
|
@ -464,7 +474,7 @@ lint-yaml: .venv
|
||||||
|
|
||||||
.PHONY: watch
|
.PHONY: watch
|
||||||
watch:
|
watch:
|
||||||
@bash build/watch.sh
|
@bash tools/watch.sh
|
||||||
|
|
||||||
.PHONY: watch-frontend
|
.PHONY: watch-frontend
|
||||||
watch-frontend: node-check node_modules
|
watch-frontend: node-check node_modules
|
||||||
|
@ -527,12 +537,8 @@ vendor: go.mod go.sum
|
||||||
|
|
||||||
.PHONY: tidy-check
|
.PHONY: tidy-check
|
||||||
tidy-check: tidy
|
tidy-check: tidy
|
||||||
@diff=$$(git diff --color=always go.mod go.sum $(GO_LICENSE_FILE)); \
|
@git diff --exit-code --color=always go.mod go.sum $(GO_LICENSE_FILE) \
|
||||||
if [ -n "$$diff" ]; then \
|
|| (code=$$?; echo "Please run 'make tidy' and commit the result"; exit $${code})
|
||||||
echo "Please run 'make tidy' and commit the result:"; \
|
|
||||||
echo "$${diff}"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
.PHONY: go-licenses
|
.PHONY: go-licenses
|
||||||
go-licenses: $(GO_LICENSE_FILE)
|
go-licenses: $(GO_LICENSE_FILE)
|
||||||
|
@ -602,27 +608,6 @@ test-pgsql\#%: integrations.pgsql.test generate-ini-pgsql
|
||||||
.PHONY: test-pgsql-migration
|
.PHONY: test-pgsql-migration
|
||||||
test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test
|
test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test
|
||||||
|
|
||||||
generate-ini-mssql:
|
|
||||||
sed -e 's|{{TEST_MSSQL_HOST}}|${TEST_MSSQL_HOST}|g' \
|
|
||||||
-e 's|{{TEST_MSSQL_DBNAME}}|${TEST_MSSQL_DBNAME}|g' \
|
|
||||||
-e 's|{{TEST_MSSQL_USERNAME}}|${TEST_MSSQL_USERNAME}|g' \
|
|
||||||
-e 's|{{TEST_MSSQL_PASSWORD}}|${TEST_MSSQL_PASSWORD}|g' \
|
|
||||||
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
|
|
||||||
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
|
|
||||||
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
|
|
||||||
tests/mssql.ini.tmpl > tests/mssql.ini
|
|
||||||
|
|
||||||
.PHONY: test-mssql
|
|
||||||
test-mssql: integrations.mssql.test generate-ini-mssql
|
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test
|
|
||||||
|
|
||||||
.PHONY: test-mssql\#%
|
|
||||||
test-mssql\#%: integrations.mssql.test generate-ini-mssql
|
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
|
|
||||||
|
|
||||||
.PHONY: test-mssql-migration
|
|
||||||
test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test
|
|
||||||
|
|
||||||
.PHONY: playwright
|
.PHONY: playwright
|
||||||
playwright: deps-frontend
|
playwright: deps-frontend
|
||||||
npx playwright install $(PLAYWRIGHT_FLAGS)
|
npx playwright install $(PLAYWRIGHT_FLAGS)
|
||||||
|
@ -659,14 +644,6 @@ test-e2e-pgsql: playwright e2e.pgsql.test generate-ini-pgsql
|
||||||
test-e2e-pgsql\#%: playwright e2e.pgsql.test generate-ini-pgsql
|
test-e2e-pgsql\#%: playwright e2e.pgsql.test generate-ini-pgsql
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test -test.run TestE2e/$*
|
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test -test.run TestE2e/$*
|
||||||
|
|
||||||
.PHONY: test-e2e-mssql
|
|
||||||
test-e2e-mssql: playwright e2e.mssql.test generate-ini-mssql
|
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test -test.run TestE2e
|
|
||||||
|
|
||||||
.PHONY: test-e2e-mssql\#%
|
|
||||||
test-e2e-mssql\#%: playwright e2e.mssql.test generate-ini-mssql
|
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test -test.run TestE2e/$*
|
|
||||||
|
|
||||||
.PHONY: test-e2e-debugserver
|
.PHONY: test-e2e-debugserver
|
||||||
test-e2e-debugserver: e2e.sqlite.test generate-ini-sqlite
|
test-e2e-debugserver: e2e.sqlite.test generate-ini-sqlite
|
||||||
sed -i s/3003/3000/g tests/sqlite.ini
|
sed -i s/3003/3000/g tests/sqlite.ini
|
||||||
|
@ -680,10 +657,6 @@ bench-sqlite: integrations.sqlite.test generate-ini-sqlite
|
||||||
bench-mysql: integrations.mysql.test generate-ini-mysql
|
bench-mysql: integrations.mysql.test generate-ini-mysql
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||||
|
|
||||||
.PHONY: bench-mssql
|
|
||||||
bench-mssql: integrations.mssql.test generate-ini-mssql
|
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
|
||||||
|
|
||||||
.PHONY: bench-pgsql
|
.PHONY: bench-pgsql
|
||||||
bench-pgsql: integrations.pgsql.test generate-ini-pgsql
|
bench-pgsql: integrations.pgsql.test generate-ini-pgsql
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||||
|
@ -702,9 +675,6 @@ integrations.mysql.test: git-check $(GO_SOURCES)
|
||||||
integrations.pgsql.test: git-check $(GO_SOURCES)
|
integrations.pgsql.test: git-check $(GO_SOURCES)
|
||||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.pgsql.test
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.pgsql.test
|
||||||
|
|
||||||
integrations.mssql.test: git-check $(GO_SOURCES)
|
|
||||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mssql.test
|
|
||||||
|
|
||||||
integrations.sqlite.test: git-check $(GO_SOURCES)
|
integrations.sqlite.test: git-check $(GO_SOURCES)
|
||||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.sqlite.test -tags '$(TEST_TAGS)'
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.sqlite.test -tags '$(TEST_TAGS)'
|
||||||
|
|
||||||
|
@ -724,11 +694,6 @@ migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql
|
||||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./migrations.pgsql.test
|
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./migrations.pgsql.test
|
||||||
|
|
||||||
.PHONY: migrations.mssql.test
|
|
||||||
migrations.mssql.test: $(GO_SOURCES) generate-ini-mssql
|
|
||||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mssql.test
|
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./migrations.mssql.test
|
|
||||||
|
|
||||||
.PHONY: migrations.sqlite.test
|
.PHONY: migrations.sqlite.test
|
||||||
migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
|
migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
|
||||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)'
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)'
|
||||||
|
@ -754,17 +719,6 @@ migrations.individual.pgsql.test: $(GO_SOURCES)
|
||||||
migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql
|
migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||||
|
|
||||||
|
|
||||||
.PHONY: migrations.individual.mssql.test
|
|
||||||
migrations.individual.mssql.test: $(GO_SOURCES) generate-ini-mssql
|
|
||||||
for pkg in $(MIGRATION_PACKAGES); do \
|
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' -test.failfast $$pkg || exit 1; \
|
|
||||||
done
|
|
||||||
|
|
||||||
.PHONY: migrations.individual.mssql.test\#%
|
|
||||||
migrations.individual.mssql.test\#%: $(GO_SOURCES) generate-ini-mssql
|
|
||||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
|
||||||
|
|
||||||
.PHONY: migrations.individual.sqlite.test
|
.PHONY: migrations.individual.sqlite.test
|
||||||
migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
|
migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
|
||||||
for pkg in $(MIGRATION_PACKAGES); do \
|
for pkg in $(MIGRATION_PACKAGES); do \
|
||||||
|
@ -781,9 +735,6 @@ e2e.mysql.test: $(GO_SOURCES)
|
||||||
e2e.pgsql.test: $(GO_SOURCES)
|
e2e.pgsql.test: $(GO_SOURCES)
|
||||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.pgsql.test
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.pgsql.test
|
||||||
|
|
||||||
e2e.mssql.test: $(GO_SOURCES)
|
|
||||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mssql.test
|
|
||||||
|
|
||||||
e2e.sqlite.test: $(GO_SOURCES)
|
e2e.sqlite.test: $(GO_SOURCES)
|
||||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.sqlite.test -tags '$(TEST_TAGS)'
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.sqlite.test -tags '$(TEST_TAGS)'
|
||||||
|
|
||||||
|
@ -815,6 +766,10 @@ generate-go: $(TAGS_PREREQ)
|
||||||
@echo "Running go generate..."
|
@echo "Running go generate..."
|
||||||
@CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' $(GO_PACKAGES)
|
@CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' $(GO_PACKAGES)
|
||||||
|
|
||||||
|
.PHONY: merge-locales
|
||||||
|
merge-locales:
|
||||||
|
@echo "NOT NEEDED: THIS IS A NOOP AS OF Forgejo 7.0 BUT KEPT FOR BACKWARD COMPATIBILITY"
|
||||||
|
|
||||||
.PHONY: security-check
|
.PHONY: security-check
|
||||||
security-check:
|
security-check:
|
||||||
go run $(GOVULNCHECK_PACKAGE) ./...
|
go run $(GOVULNCHECK_PACKAGE) ./...
|
||||||
|
@ -885,10 +840,6 @@ release-sources: | $(DIST_DIRS)
|
||||||
release-docs: | $(DIST_DIRS) docs
|
release-docs: | $(DIST_DIRS) docs
|
||||||
tar -czf $(DIST)/release/gitea-docs-$(VERSION).tar.gz -C ./docs .
|
tar -czf $(DIST)/release/gitea-docs-$(VERSION).tar.gz -C ./docs .
|
||||||
|
|
||||||
.PHONY: docs
|
|
||||||
docs:
|
|
||||||
cd docs; bash scripts/trans-copy.sh;
|
|
||||||
|
|
||||||
.PHONY: deps
|
.PHONY: deps
|
||||||
deps: deps-frontend deps-backend deps-tools deps-py
|
deps: deps-frontend deps-backend deps-tools deps-py
|
||||||
|
|
||||||
|
@ -947,6 +898,7 @@ fomantic:
|
||||||
cd $(FOMANTIC_WORK_DIR) && npm install --no-save
|
cd $(FOMANTIC_WORK_DIR) && npm install --no-save
|
||||||
cp -f $(FOMANTIC_WORK_DIR)/theme.config.less $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/theme.config
|
cp -f $(FOMANTIC_WORK_DIR)/theme.config.less $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/theme.config
|
||||||
cp -rf $(FOMANTIC_WORK_DIR)/_site $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/
|
cp -rf $(FOMANTIC_WORK_DIR)/_site $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/
|
||||||
|
$(SED_INPLACE) -e 's/ overrideBrowserslist\r/ overrideBrowserslist: ["defaults"]\r/g' $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/tasks/config/tasks.js
|
||||||
cd $(FOMANTIC_WORK_DIR) && npx gulp -f node_modules/fomantic-ui/gulpfile.js build
|
cd $(FOMANTIC_WORK_DIR) && npx gulp -f node_modules/fomantic-ui/gulpfile.js build
|
||||||
# fomantic uses "touchstart" as click event for some browsers, it's not ideal, so we force fomantic to always use "click" as click event
|
# fomantic uses "touchstart" as click event for some browsers, it's not ideal, so we force fomantic to always use "click" as click event
|
||||||
$(SED_INPLACE) -e 's/clickEvent[ \t]*=/clickEvent = "click", unstableClickEvent =/g' $(FOMANTIC_WORK_DIR)/build/semantic.js
|
$(SED_INPLACE) -e 's/clickEvent[ \t]*=/clickEvent = "click", unstableClickEvent =/g' $(FOMANTIC_WORK_DIR)/build/semantic.js
|
||||||
|
@ -965,28 +917,19 @@ $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json
|
||||||
.PHONY: svg
|
.PHONY: svg
|
||||||
svg: node-check | node_modules
|
svg: node-check | node_modules
|
||||||
rm -rf $(SVG_DEST_DIR)
|
rm -rf $(SVG_DEST_DIR)
|
||||||
node build/generate-svg.js
|
node tools/generate-svg.js
|
||||||
|
|
||||||
.PHONY: svg-check
|
.PHONY: svg-check
|
||||||
svg-check: svg
|
svg-check: svg
|
||||||
@git add $(SVG_DEST_DIR)
|
@git add $(SVG_DEST_DIR)
|
||||||
@diff=$$(git diff --color=always --cached $(SVG_DEST_DIR)); \
|
@git diff --exit-code --color=always --cached $(SVG_DEST_DIR) \
|
||||||
if [ -n "$$diff" ]; then \
|
|| (code=$$?; echo "Please run 'make svg' and commit the result"; exit $${code})
|
||||||
echo "Please run 'make svg' and 'git add $(SVG_DEST_DIR)' and commit the result:"; \
|
|
||||||
echo "$${diff}"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
.PHONY: lockfile-check
|
.PHONY: lockfile-check
|
||||||
lockfile-check:
|
lockfile-check:
|
||||||
npm install --package-lock-only
|
npm install --package-lock-only
|
||||||
@diff=$$(git diff --color=always package-lock.json); \
|
@git diff --exit-code --color=always package-lock.json \
|
||||||
if [ -n "$$diff" ]; then \
|
|| (code=$$?; echo "Please run 'npm install --package-lock-only' and commit the result"; exit $${code})
|
||||||
echo "package-lock.json is inconsistent with package.json"; \
|
|
||||||
echo "Please run 'npm install --package-lock-only' and commit the result:"; \
|
|
||||||
echo "$${diff}"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
.PHONY: update-translations
|
.PHONY: update-translations
|
||||||
update-translations:
|
update-translations:
|
||||||
|
@ -1008,8 +951,8 @@ generate-gitignore:
|
||||||
|
|
||||||
.PHONY: generate-images
|
.PHONY: generate-images
|
||||||
generate-images: | node_modules
|
generate-images: | node_modules
|
||||||
npm install --no-save fabric@6.0.0-beta19 imagemin-zopfli@7
|
npm install --no-save fabric@6.0.0-beta20 imagemin-zopfli@7
|
||||||
node build/generate-images.js $(TAGS)
|
node tools/generate-images.js $(TAGS)
|
||||||
|
|
||||||
.PHONY: generate-manpage
|
.PHONY: generate-manpage
|
||||||
generate-manpage:
|
generate-manpage:
|
||||||
|
|
111
RELEASE-NOTES.md
111
RELEASE-NOTES.md
|
@ -4,6 +4,117 @@ A Forgejo release is published shortly after a Gitea release is published and th
|
||||||
|
|
||||||
The Forgejo admin should carefully read the required manual actions before upgrading. A point release (e.g. v1.21.1-0 or v1.21.2-0) does not require manual actions but others might (e.g. v1.20, v1.21).
|
The Forgejo admin should carefully read the required manual actions before upgrading. A point release (e.g. v1.21.1-0 or v1.21.2-0) does not require manual actions but others might (e.g. v1.20, v1.21).
|
||||||
|
|
||||||
|
## 1.21.10-0
|
||||||
|
|
||||||
|
The [complete list of commits](https://codeberg.org/forgejo/forgejo/commits/branch/v1.21/forgejo) included in the `Forgejo v1.21.10-0` release can be reviewed from the command line with:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ git clone https://codeberg.org/forgejo/forgejo/
|
||||||
|
$ git -C forgejo log --oneline --no-merges v1.21.8-0..v1.21.10-0
|
||||||
|
```
|
||||||
|
|
||||||
|
This stable release contains bug fixes and a **security fix**.
|
||||||
|
|
||||||
|
Note that there is no `Forgejo v1.21.9-0` release. The release numbering of the `Forgejo v1.21` patch series follows the Gitea release numbering. However, the publication of `Gitea v1.21.9` and `Gitea v1.21.10` were a few days appart because of a regression that is not present on Forgejo and there was no need to publish `Forgejo v1.21.9-0`.
|
||||||
|
|
||||||
|
* Recommended Action
|
||||||
|
|
||||||
|
We recommend that all Forgejo installations are [upgraded](https://forgejo.org/docs/v1.21/admin/upgrade/) to the latest version as soon as possible.
|
||||||
|
|
||||||
|
* [Forgejo Semantic Version](https://forgejo.org/docs/v1.21/user/semver/)
|
||||||
|
|
||||||
|
The semantic version was updated to `6.0.10+0-gitea-1.21.10`
|
||||||
|
|
||||||
|
* Built with Go 1.21.9 and `golang.org/x/net` v0.23.0
|
||||||
|
|
||||||
|
It [includes vulnerability fixes](https://groups.google.com/g/golang-announce/c/YgW0sx8mN3M/m/khALNYGdAAAJ).
|
||||||
|
|
||||||
|
* [CVE-2023-45288](https://pkg.go.dev/vuln/GO-2024-2687) which permits an attacker to cause an HTTP/2 endpoint to read arbitrary amounts of header data, all associated with a request which is going to be rejected. These headers can include Huffman-encoded data which is significantly more expensive for the receiver to decode than for an attacker to send. A Forgejo instance is affected if it is configured to listen to HTTPS instead of doing this via a reverse proxy.
|
||||||
|
|
||||||
|
* Bug fixes
|
||||||
|
|
||||||
|
The most prominent ones are described here, others can be found in the list of commits included in the release as described above.
|
||||||
|
|
||||||
|
* [Fix to not remove repository avatars when the doctor runs with --fix on the repository archives](https://codeberg.org/forgejo/forgejo/commit/e9932a404d4bb5b22a87797094dff615eb38171a).
|
||||||
|
* [Detect protected branch on branch rename](https://codeberg.org/forgejo/forgejo/commit/611610c3c4cba12f2a835b41438a7ed54da9bc23). If a branch cannot be renamed due to a protected branch rule, show this error in the UI instead of throwing an internal server error.
|
||||||
|
* [Don't delete inactive emails explicitly](https://codeberg.org/forgejo/forgejo/commit/fb4c42deb23a67379afb29870e430e47687ccc6c). This can cause issues as the associated user might not have been deleted. It would lead to a database inconsistency and internal server errors if the user tries to activate their account.
|
||||||
|
* [Fix user interface when a review is deleted without refreshing](https://codeberg.org/forgejo/forgejo/commit/456a33e8bb770a86341dc883edc6b62264b950a1).
|
||||||
|
* [Fix paths when finding files via the web interface that were not escaped](https://codeberg.org/forgejo/forgejo/commit/b22be0c03fa4814c1b8b892346de5d4547782ce7).
|
||||||
|
* [Respect `DEFAULT_ORG_MEMBER_VISIBLE` setting when adding creator to org](https://codeberg.org/forgejo/forgejo/commit/5e5574c7b328e2c500d497517047b8d1fd0ca478).
|
||||||
|
* [Fix duplicate migrated milestones](https://codeberg.org/forgejo/forgejo/commit/706ff7aa9fcfe4c43893dc12e27d064064e80635).
|
||||||
|
* [Fix inline math blocks can't be preceeded/followed by alphanumerical characters](https://codeberg.org/forgejo/forgejo/commit/0d3f446460b22a29c259e7d42ed89f90fd216ca7).
|
||||||
|
|
||||||
|
## 1.21.8-0
|
||||||
|
|
||||||
|
The [complete list of commits](https://codeberg.org/forgejo/forgejo/commits/branch/v1.21/forgejo) included in the `Forgejo v1.21.8-0` release can be reviewed from the command line with:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ git clone https://codeberg.org/forgejo/forgejo/
|
||||||
|
$ git -C forgejo log --oneline --no-merges v1.21.7-0..v1.21.8-0
|
||||||
|
```
|
||||||
|
|
||||||
|
This stable release contains bug fixes.
|
||||||
|
|
||||||
|
* Recommended Action
|
||||||
|
|
||||||
|
We recommend that all Forgejo installations are [upgraded](https://forgejo.org/docs/v1.21/admin/upgrade/) to the latest version.
|
||||||
|
|
||||||
|
* [Forgejo Semantic Version](https://forgejo.org/docs/v1.21/user/semver/)
|
||||||
|
|
||||||
|
The semantic version was updated to `6.0.8+0-gitea-1.21.8`
|
||||||
|
|
||||||
|
* Bug fixes
|
||||||
|
|
||||||
|
The most prominent ones are described here, others can be found in the list of commits included in the release as described above.
|
||||||
|
|
||||||
|
* [Fix `/api/v1/{owner}/{repo}/issue_templates`](https://codeberg.org/forgejo/forgejo/commit/969d3f44101402afd9dd848e79dd5823d547a00d) which was always failing with a 500 error.
|
||||||
|
* [Prevent error 500 on /user/settings/security when SignedUser has a linked account from a deactivated authentication source](https://codeberg.org/forgejo/forgejo/commit/d9418651af8c8a3276ebc40a516109c0f33139b0).
|
||||||
|
* [Fix error 500 when pushing release to an empty repo](https://codeberg.org/forgejo/forgejo/commit/b76f370a3f8993638cad91547491b46631776f59).
|
||||||
|
* [Fix incorrect rendering csv file when file size is larger than UI.CSV.MaxFileSize](https://codeberg.org/forgejo/forgejo/commit/e151e0467341bd25a2465ca15e81ebc0c8fa3fc4).
|
||||||
|
* [Fix error 500 when deleting account with incorrect password or unsupported login type](https://codeberg.org/forgejo/forgejo/commit/66061d28286ee3adf69747c284d40121e2e4b280).
|
||||||
|
* [handle user-defined `name` anchors like `[Link](#link)` linking to `<a name="link"></a>Link`](https://codeberg.org/forgejo/forgejo/commit/03caefbb02854d5c98a26d889e0e30c910651395).
|
||||||
|
* [Use correct head commit for CODEOWNER](https://codeberg.org/forgejo/forgejo/commit/d1cebb0e884a88941e27e2280e117cc04d2665fe).
|
||||||
|
* [Fix manual merge button](https://codeberg.org/forgejo/forgejo/commit/c70719c59c410e5378c04926c66461d7b9f72884).
|
||||||
|
* [Make meilisearch do exact search for issues](https://codeberg.org/forgejo/forgejo/commit/a876ac2c7934fa0f8a66424e178b501e4a341e0f).
|
||||||
|
* [Fix PR creation via api between branches of same repo with head field namespaced](https://codeberg.org/forgejo/forgejo/commit/120a173e24fd359b0b57f2bd1021168645fab5a8).
|
||||||
|
|
||||||
|
## 1.21.7-0
|
||||||
|
|
||||||
|
The [complete list of commits](https://codeberg.org/forgejo/forgejo/commits/branch/v1.21/forgejo) included in the `Forgejo v1.21.7-0` release can be reviewed from the command line with:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ git clone https://codeberg.org/forgejo/forgejo/
|
||||||
|
$ git -C forgejo log --oneline --no-merges v1.21.6-0..v1.21.7-0
|
||||||
|
```
|
||||||
|
|
||||||
|
This stable release contains bug fixes and a **security fix**.
|
||||||
|
|
||||||
|
* Recommended Action
|
||||||
|
|
||||||
|
We recommend that all Forgejo installations are [upgraded](https://forgejo.org/docs/v1.21/admin/upgrade/) to the latest version as soon as possible.
|
||||||
|
|
||||||
|
* [Forgejo Semantic Version](https://forgejo.org/docs/v1.21/user/semver/)
|
||||||
|
|
||||||
|
The semantic version was updated to `6.0.7+0-gitea-1.21.7`
|
||||||
|
|
||||||
|
* Built with Go 1.21.8
|
||||||
|
|
||||||
|
It [includes vulnerability fixes](https://groups.google.com/g/golang-announce/c/5pwGVUPoMbg).
|
||||||
|
|
||||||
|
* [CVE-2023-45290](https://go.dev/issue/65383) which could lead to memory exhaustion when parsing a multipart form.
|
||||||
|
* [CVE-2023-45289](https://go.dev/issue/65065) which could allow incorrect forwarding of sensitive headers and cookies on HTTP redirect.
|
||||||
|
|
||||||
|
* Security fix
|
||||||
|
|
||||||
|
* The google.golang.org/protobuf module was bumped to version v1.33.0 to fix a bug in the google.golang.org/protobuf/encoding/protojson package which could cause the Unmarshal function to enter an infinite loop when handling some invalid inputs. [Read more in the announcement](https://groups.google.com/g/golang-announce/c/ArQ6CDgtEjY).
|
||||||
|
|
||||||
|
* Bug fixes
|
||||||
|
|
||||||
|
The most prominent ones are described here, others can be found in the list of commits included in the release as described above.
|
||||||
|
|
||||||
|
* [Fix tarball/zipball download bug](https://codeberg.org/forgejo/forgejo/commit/8e2c991b35de8c94899ad053e89339cea4538589).
|
||||||
|
* [Ensure `HasIssueContentHistory` takes into account `comment_id`](https://codeberg.org/forgejo/forgejo/commit/8fb027fea5e9525293802d977fd3ee0c374ba9ba).
|
||||||
|
|
||||||
## 1.21.6-0
|
## 1.21.6-0
|
||||||
|
|
||||||
The [complete list of commits](https://codeberg.org/forgejo/forgejo/commits/branch/v1.21/forgejo) included in the `Forgejo v1.21.6-0` release can be reviewed from the command line with:
|
The [complete list of commits](https://codeberg.org/forgejo/forgejo/commits/branch/v1.21/forgejo) included in the `Forgejo v1.21.6-0` release can be reviewed from the command line with:
|
||||||
|
|
30
assets/go-licenses.json
generated
30
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
|
@ -1,27 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Copyright 2024 The Forgejo Authors
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
D=/tmp/crowdin-to-weblate
|
|
||||||
mkdir -p $D
|
|
||||||
|
|
||||||
function checkout() {
|
|
||||||
if test -d $D/gitea ; then
|
|
||||||
git -C $D/gitea reset --hard
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
git clone --depth 1 https://github.com/go-gitea/gitea $D/gitea
|
|
||||||
}
|
|
||||||
|
|
||||||
function replace() {
|
|
||||||
go run build/merge-forgejo-locales.go $D/gitea/options/locale
|
|
||||||
cp -a $D/gitea/options/locale/* options/locale
|
|
||||||
}
|
|
||||||
|
|
||||||
function run() {
|
|
||||||
checkout
|
|
||||||
replace
|
|
||||||
}
|
|
||||||
|
|
||||||
"$@"
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2022 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -7,103 +7,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
trimPrefix = "gitea_"
|
|
||||||
sourceFolder = "options/locales/"
|
|
||||||
)
|
|
||||||
|
|
||||||
// returns list of locales, still containing the file extension!
|
|
||||||
func generate_locale_list() []string {
|
|
||||||
localeFiles, _ := os.ReadDir(sourceFolder)
|
|
||||||
locales := []string{}
|
|
||||||
for _, localeFile := range localeFiles {
|
|
||||||
if !localeFile.IsDir() && strings.HasPrefix(localeFile.Name(), trimPrefix) {
|
|
||||||
locales = append(locales, strings.TrimPrefix(localeFile.Name(), trimPrefix))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return locales
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace all occurrences of Gitea with Forgejo
|
|
||||||
func renameGiteaForgejo(filename string) []byte {
|
|
||||||
file, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
replacements := []string{
|
|
||||||
"Gitea", "Forgejo",
|
|
||||||
"https://docs.gitea.com/installation/install-from-binary", "https://forgejo.org/download/#installation-from-binary",
|
|
||||||
"https://github.com/go-gitea/gitea/tree/master/docker", "https://forgejo.org/download/#container-image",
|
|
||||||
"https://docs.gitea.com/installation/install-from-package", "https://forgejo.org/download",
|
|
||||||
"https://code.gitea.io/gitea", "https://forgejo.org/download",
|
|
||||||
"code.gitea.io/gitea", "Forgejo",
|
|
||||||
`<a href="https://github.com/go-gitea/gitea/issues" target="_blank">GitHub</a>`, `<a href="https://codeberg.org/forgejo/forgejo/issues" target="_blank">Codeberg</a>`,
|
|
||||||
"https://github.com/go-gitea/gitea", "https://codeberg.org/forgejo/forgejo",
|
|
||||||
"https://blog.gitea.io", "https://forgejo.org/news",
|
|
||||||
"https://docs.gitea.com/usage/protected-tags", "https://forgejo.org/docs/latest/user/protection/#protected-tags",
|
|
||||||
"https://docs.gitea.com/usage/webhooks", "https://forgejo.org/docs/latest/user/webhooks/",
|
|
||||||
}
|
|
||||||
replacer := strings.NewReplacer(replacements...)
|
|
||||||
replaced := make(map[string]bool, len(replacements)/2)
|
|
||||||
count_replaced := func(original string) {
|
|
||||||
for i := 0; i < len(replacements); i += 2 {
|
|
||||||
if strings.Contains(original, replacements[i]) {
|
|
||||||
replaced[replacements[i]] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make([]byte, 0, 1024)
|
|
||||||
scanner := bufio.NewScanner(file)
|
|
||||||
scanner.Split(bufio.ScanLines)
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
|
|
||||||
if strings.HasPrefix(line, "license_desc=") {
|
|
||||||
line = strings.Replace(line, "GitHub", "Forgejo", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
|
|
||||||
out = append(out, []byte(line+"\n")...)
|
|
||||||
} else if strings.HasPrefix(line, "settings.web_hook_name_gitea") {
|
|
||||||
out = append(out, []byte(line+"\n")...)
|
|
||||||
out = append(out, []byte("settings.web_hook_name_forgejo = Forgejo\n")...)
|
|
||||||
} else if strings.HasPrefix(line, "migrate.gitea.description") {
|
|
||||||
re := regexp.MustCompile(`(.*Gitea)`)
|
|
||||||
out = append(out, []byte(re.ReplaceAllString(line, "${1}/Forgejo")+"\n")...)
|
|
||||||
} else {
|
|
||||||
count_replaced(line)
|
|
||||||
out = append(out, []byte(replacer.Replace(line)+"\n")...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file.Close()
|
|
||||||
if strings.HasSuffix(filename, "gitea_en-US.ini") {
|
|
||||||
for i := 0; i < len(replacements); i += 2 {
|
|
||||||
if replaced[replacements[i]] == false {
|
|
||||||
log.Fatalf("%s was never used to replace something in %s, it is obsolete and must be updated", replacements[i], filename)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
d := os.Args[1]
|
fmt.Println("NOT NEEDED: THIS IS A NOOP AS OF Forgejo 7.0 BUT KEPT FOR BACKWARD COMPATIBILITY")
|
||||||
files, err := os.ReadDir(d)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range files {
|
|
||||||
p := d + "/" + f.Name()
|
|
||||||
os.WriteFile(p, renameGiteaForgejo(p), 0o644)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,8 @@ var microcmdUserCreate = &cli.Command{
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "must-change-password",
|
Name: "must-change-password",
|
||||||
Usage: "Set this option to false to prevent forcing the user to change their password after initial login, (Default: true)",
|
Usage: "Set this option to false to prevent forcing the user to change their password after initial login",
|
||||||
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "random-password-length",
|
Name: "random-password-length",
|
||||||
|
@ -110,8 +111,7 @@ func runCreateUser(c *cli.Context) error {
|
||||||
return errors.New("must set either password or random-password flag")
|
return errors.New("must set either password or random-password flag")
|
||||||
}
|
}
|
||||||
|
|
||||||
// always default to true
|
changePassword := c.Bool("must-change-password")
|
||||||
changePassword := true
|
|
||||||
|
|
||||||
// If this is the first user being created.
|
// If this is the first user being created.
|
||||||
// Take it as the admin and don't force a password update.
|
// Take it as the admin and don't force a password update.
|
||||||
|
@ -119,10 +119,6 @@ func runCreateUser(c *cli.Context) error {
|
||||||
changePassword = false
|
changePassword = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.IsSet("must-change-password") {
|
|
||||||
changePassword = c.Bool("must-change-password")
|
|
||||||
}
|
|
||||||
|
|
||||||
restricted := optional.None[bool]()
|
restricted := optional.None[bool]()
|
||||||
|
|
||||||
if c.IsSet("restricted") {
|
if c.IsSet("restricted") {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
var cmdDoctorConvert = &cli.Command{
|
var cmdDoctorConvert = &cli.Command{
|
||||||
Name: "convert",
|
Name: "convert",
|
||||||
Usage: "Convert the database",
|
Usage: "Convert the database",
|
||||||
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4 or MSSQL database from varchar to nvarchar",
|
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
||||||
Action: runDoctorConvert,
|
Action: runDoctorConvert,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,21 +35,14 @@ func runDoctorConvert(ctx *cli.Context) error {
|
||||||
log.Info("Log path: %s", setting.Log.RootPath)
|
log.Info("Log path: %s", setting.Log.RootPath)
|
||||||
log.Info("Configuration file: %s", setting.CustomConf)
|
log.Info("Configuration file: %s", setting.CustomConf)
|
||||||
|
|
||||||
switch {
|
if setting.Database.Type.IsMySQL() {
|
||||||
case setting.Database.Type.IsMySQL():
|
|
||||||
if err := db.ConvertDatabaseTable(); err != nil {
|
if err := db.ConvertDatabaseTable(); err != nil {
|
||||||
log.Fatal("Failed to convert database & table: %v", err)
|
log.Fatal("Failed to convert database & table: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4")
|
fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4")
|
||||||
case setting.Database.Type.IsMSSQL():
|
} else {
|
||||||
if err := db.ConvertVarcharToNVarchar(); err != nil {
|
fmt.Println("This command can only be used with a MySQL database")
|
||||||
log.Fatal("Failed to convert database from varchar to nvarchar: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println("Converted successfully, please confirm your database's all columns character is NVARCHAR now")
|
|
||||||
default:
|
|
||||||
fmt.Println("This command can only be used with a MySQL or MSSQL database")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
20
cmd/dump.go
20
cmd/dump.go
|
@ -128,7 +128,7 @@ It can be used for backup and capture Forgejo server image to send to maintainer
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "database",
|
Name: "database",
|
||||||
Aliases: []string{"d"},
|
Aliases: []string{"d"},
|
||||||
Usage: "Specify the database SQL syntax: sqlite3, mysql, mssql, postgres",
|
Usage: "Specify the database SQL syntax: sqlite3, mysql, postgres",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "skip-repository",
|
Name: "skip-repository",
|
||||||
|
@ -454,14 +454,18 @@ func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeA
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
currentAbsPath := filepath.Join(absPath, file.Name())
|
currentAbsPath := filepath.Join(absPath, file.Name())
|
||||||
currentInsidePath := path.Join(insidePath, file.Name())
|
currentInsidePath := path.Join(insidePath, file.Name())
|
||||||
|
|
||||||
|
if util.SliceContainsString(excludeAbsPath, currentAbsPath) {
|
||||||
|
log.Debug("Skipping %q because matched an excluded path.", currentAbsPath)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if file.IsDir() {
|
if file.IsDir() {
|
||||||
if !util.SliceContainsString(excludeAbsPath, currentAbsPath) {
|
if err := addFile(w, currentInsidePath, currentAbsPath, false); err != nil {
|
||||||
if err := addFile(w, currentInsidePath, currentAbsPath, false); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
if err = addRecursiveExclude(w, currentInsidePath, currentAbsPath, excludeAbsPath, verbose); err != nil {
|
||||||
if err = addRecursiveExclude(w, currentInsidePath, currentAbsPath, excludeAbsPath, verbose); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// only copy regular files and symlink regular files, skip non-regular files like socket/pipe/...
|
// only copy regular files and symlink regular files, skip non-regular files like socket/pipe/...
|
||||||
|
|
117
cmd/dump_test.go
Normal file
117
cmd/dump_test.go
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mholt/archiver/v3"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mockArchiver struct {
|
||||||
|
addedFiles []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mockArchiver) Create(out io.Writer) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockArchiver) Write(f archiver.File) error {
|
||||||
|
m.addedFiles = append(m.addedFiles, f.Name())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mockArchiver) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddRecursiveExclude(t *testing.T) {
|
||||||
|
t.Run("Empty", func(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
archiver := &mockArchiver{}
|
||||||
|
|
||||||
|
err := addRecursiveExclude(archiver, "", dir, []string{}, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, archiver.addedFiles)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Single file", func(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
err := os.WriteFile(dir+"/example", nil, 0o666)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("No exclude", func(t *testing.T) {
|
||||||
|
archiver := &mockArchiver{}
|
||||||
|
|
||||||
|
err = addRecursiveExclude(archiver, "", dir, nil, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, archiver.addedFiles, 1)
|
||||||
|
assert.EqualValues(t, "example", archiver.addedFiles[0])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("With exclude", func(t *testing.T) {
|
||||||
|
archiver := &mockArchiver{}
|
||||||
|
|
||||||
|
err = addRecursiveExclude(archiver, "", dir, []string{dir + "/example"}, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, archiver.addedFiles)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("File inside directory", func(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
err := os.MkdirAll(dir+"/deep/nested/folder", 0o750)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = os.WriteFile(dir+"/deep/nested/folder/example", nil, 0o666)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = os.WriteFile(dir+"/deep/nested/folder/another-file", nil, 0o666)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("No exclude", func(t *testing.T) {
|
||||||
|
archiver := &mockArchiver{}
|
||||||
|
|
||||||
|
err = addRecursiveExclude(archiver, "", dir, nil, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, archiver.addedFiles, 5)
|
||||||
|
assert.EqualValues(t, "deep", archiver.addedFiles[0])
|
||||||
|
assert.EqualValues(t, "deep/nested", archiver.addedFiles[1])
|
||||||
|
assert.EqualValues(t, "deep/nested/folder", archiver.addedFiles[2])
|
||||||
|
assert.EqualValues(t, "deep/nested/folder/example", archiver.addedFiles[3])
|
||||||
|
assert.EqualValues(t, "deep/nested/folder/another-file", archiver.addedFiles[4])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Exclude first directory", func(t *testing.T) {
|
||||||
|
archiver := &mockArchiver{}
|
||||||
|
|
||||||
|
err = addRecursiveExclude(archiver, "", dir, []string{dir + "/deep"}, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, archiver.addedFiles)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Exclude nested directory", func(t *testing.T) {
|
||||||
|
archiver := &mockArchiver{}
|
||||||
|
|
||||||
|
err = addRecursiveExclude(archiver, "", dir, []string{dir + "/deep/nested/folder"}, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, archiver.addedFiles, 2)
|
||||||
|
assert.EqualValues(t, "deep", archiver.addedFiles[0])
|
||||||
|
assert.EqualValues(t, "deep/nested", archiver.addedFiles[1])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Exclude file", func(t *testing.T) {
|
||||||
|
archiver := &mockArchiver{}
|
||||||
|
|
||||||
|
err = addRecursiveExclude(archiver, "", dir, []string{dir + "/deep/nested/folder/example"}, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, archiver.addedFiles, 4)
|
||||||
|
assert.EqualValues(t, "deep", archiver.addedFiles[0])
|
||||||
|
assert.EqualValues(t, "deep/nested", archiver.addedFiles[1])
|
||||||
|
assert.EqualValues(t, "deep/nested/folder", archiver.addedFiles[2])
|
||||||
|
assert.EqualValues(t, "deep/nested/folder/another-file", archiver.addedFiles[3])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
115
cmd/hook.go
115
cmd/hook.go
|
@ -139,11 +139,10 @@ func (d *delayWriter) WriteString(s string) (n int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *delayWriter) Close() error {
|
func (d *delayWriter) Close() error {
|
||||||
if d == nil {
|
if d.timer.Stop() {
|
||||||
return nil
|
d.buf = nil
|
||||||
}
|
}
|
||||||
stopped := d.timer.Stop()
|
if d.buf == nil {
|
||||||
if stopped || d.buf == nil {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, err := d.internal.Write(d.buf.Bytes())
|
_, err := d.internal.Write(d.buf.Bytes())
|
||||||
|
@ -293,9 +292,36 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runHookUpdate process the update hook: https://git-scm.com/docs/githooks#update
|
||||||
func runHookUpdate(c *cli.Context) error {
|
func runHookUpdate(c *cli.Context) error {
|
||||||
// Update is empty and is kept only for backwards compatibility
|
// Now if we're an internal don't do anything else
|
||||||
return nil
|
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if c.NArg() != 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
args := c.Args().Slice()
|
||||||
|
|
||||||
|
// The arguments given to the hook are in order: reference name, old commit ID and new commit ID.
|
||||||
|
refFullName := git.RefName(args[0])
|
||||||
|
newCommitID := args[2]
|
||||||
|
|
||||||
|
// Only process pull references.
|
||||||
|
if !refFullName.IsPull() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletion of the ref means that the new commit ID is only composed of '0'.
|
||||||
|
if strings.ContainsFunc(newCommitID, func(e rune) bool { return e != '0' }) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fail(ctx, fmt.Sprintf("The deletion of %s is skipped as it's an internal reference.", refFullName), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookPostReceive(c *cli.Context) error {
|
func runHookPostReceive(c *cli.Context) error {
|
||||||
|
@ -324,11 +350,10 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
var out io.Writer
|
var out io.Writer
|
||||||
var dWriter *delayWriter
|
|
||||||
out = &nilWriter{}
|
out = &nilWriter{}
|
||||||
if setting.Git.VerbosePush {
|
if setting.Git.VerbosePush {
|
||||||
if setting.Git.VerbosePushDelay > 0 {
|
if setting.Git.VerbosePushDelay > 0 {
|
||||||
dWriter = newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay)
|
dWriter := newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay)
|
||||||
defer dWriter.Close()
|
defer dWriter.Close()
|
||||||
out = dWriter
|
out = dWriter
|
||||||
} else {
|
} else {
|
||||||
|
@ -391,7 +416,6 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
hookOptions.RefFullNames = refFullNames
|
hookOptions.RefFullNames = refFullNames
|
||||||
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
||||||
if extra.HasError() {
|
if extra.HasError() {
|
||||||
_ = dWriter.Close()
|
|
||||||
hookPrintResults(results)
|
hookPrintResults(results)
|
||||||
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
|
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
|
||||||
}
|
}
|
||||||
|
@ -411,7 +435,6 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(out, "Processed %d references in total\n", total)
|
fmt.Fprintf(out, "Processed %d references in total\n", total)
|
||||||
|
|
||||||
_ = dWriter.Close()
|
|
||||||
hookPrintResults(results)
|
hookPrintResults(results)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -424,7 +447,6 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
|
|
||||||
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
||||||
if resp == nil {
|
if resp == nil {
|
||||||
_ = dWriter.Close()
|
|
||||||
hookPrintResults(results)
|
hookPrintResults(results)
|
||||||
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
|
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
|
||||||
}
|
}
|
||||||
|
@ -440,9 +462,8 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
|
return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = dWriter.Close()
|
|
||||||
hookPrintResults(results)
|
|
||||||
|
|
||||||
|
hookPrintResults(results)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,10 +491,11 @@ func pushOptions() map[string]string {
|
||||||
if pushCount, err := strconv.Atoi(os.Getenv(private.GitPushOptionCount)); err == nil {
|
if pushCount, err := strconv.Atoi(os.Getenv(private.GitPushOptionCount)); err == nil {
|
||||||
for idx := 0; idx < pushCount; idx++ {
|
for idx := 0; idx < pushCount; idx++ {
|
||||||
opt := os.Getenv(fmt.Sprintf("GIT_PUSH_OPTION_%d", idx))
|
opt := os.Getenv(fmt.Sprintf("GIT_PUSH_OPTION_%d", idx))
|
||||||
kv := strings.SplitN(opt, "=", 2)
|
key, value, found := strings.Cut(opt, "=")
|
||||||
if len(kv) == 2 {
|
if !found {
|
||||||
opts[kv[0]] = kv[1]
|
value = "true"
|
||||||
}
|
}
|
||||||
|
opts[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
|
@ -583,7 +605,7 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed
|
// note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed
|
||||||
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
|
rs, err = readPktLine(ctx, reader, pktLineTypeUnknown)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -604,7 +626,7 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
|
|
||||||
if hasPushOptions {
|
if hasPushOptions {
|
||||||
for {
|
for {
|
||||||
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
|
rs, err = readPktLine(ctx, reader, pktLineTypeUnknown)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -613,10 +635,11 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
kv := strings.SplitN(string(rs.Data), "=", 2)
|
key, value, found := strings.Cut(string(rs.Data), "=")
|
||||||
if len(kv) == 2 {
|
if !found {
|
||||||
hookOptions.GitPushOptions[kv[0]] = kv[1]
|
value = "true"
|
||||||
}
|
}
|
||||||
|
hookOptions.GitPushOptions[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,8 +722,8 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
type pktLineType int64
|
type pktLineType int64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// UnKnow type
|
// Unknown type
|
||||||
pktLineTypeUnknow pktLineType = 0
|
pktLineTypeUnknown pktLineType = 0
|
||||||
// flush-pkt "0000"
|
// flush-pkt "0000"
|
||||||
pktLineTypeFlush pktLineType = iota
|
pktLineTypeFlush pktLineType = iota
|
||||||
// data line
|
// data line
|
||||||
|
@ -714,22 +737,16 @@ type gitPktLine struct {
|
||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reads an Pkt-Line from `in`. If requestType is not unknown, it will a
|
||||||
func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
|
func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
|
||||||
var (
|
// Read length prefix
|
||||||
err error
|
|
||||||
r *gitPktLine
|
|
||||||
)
|
|
||||||
|
|
||||||
// read prefix
|
|
||||||
lengthBytes := make([]byte, 4)
|
lengthBytes := make([]byte, 4)
|
||||||
for i := 0; i < 4; i++ {
|
if n, err := in.Read(lengthBytes); n != 4 || err != nil {
|
||||||
lengthBytes[i], err = in.ReadByte()
|
return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err)
|
||||||
if err != nil {
|
|
||||||
return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r = new(gitPktLine)
|
var err error
|
||||||
|
r := &gitPktLine{}
|
||||||
r.Length, err = strconv.ParseUint(string(lengthBytes), 16, 32)
|
r.Length, err = strconv.ParseUint(string(lengthBytes), 16, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fail(ctx, "Protocol: format parse error", "Pkt-Line format is wrong :%v", err)
|
return nil, fail(ctx, "Protocol: format parse error", "Pkt-Line format is wrong :%v", err)
|
||||||
|
@ -748,11 +765,8 @@ func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Data = make([]byte, r.Length-4)
|
r.Data = make([]byte, r.Length-4)
|
||||||
for i := range r.Data {
|
if n, err := io.ReadFull(in, r.Data); uint64(n) != r.Length-4 || err != nil {
|
||||||
r.Data[i], err = in.ReadByte()
|
return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err)
|
||||||
if err != nil {
|
|
||||||
return nil, fail(ctx, "Protocol: data error", "Pkt-Line: read stdin failed : %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Type = pktLineTypeData
|
r.Type = pktLineTypeData
|
||||||
|
@ -768,20 +782,23 @@ func writeFlushPktLine(ctx context.Context, out io.Writer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write an Pkt-Line based on `data` to `out` according to the specifcation.
|
||||||
|
// https://git-scm.com/docs/protocol-common
|
||||||
func writeDataPktLine(ctx context.Context, out io.Writer, data []byte) error {
|
func writeDataPktLine(ctx context.Context, out io.Writer, data []byte) error {
|
||||||
hexchar := []byte("0123456789abcdef")
|
// Implementations SHOULD NOT send an empty pkt-line ("0004").
|
||||||
hex := func(n uint64) byte {
|
if len(data) == 0 {
|
||||||
return hexchar[(n)&15]
|
return fail(ctx, "Protocol: write error", "Not allowed to write empty Pkt-Line")
|
||||||
}
|
}
|
||||||
|
|
||||||
length := uint64(len(data) + 4)
|
length := uint64(len(data) + 4)
|
||||||
tmp := make([]byte, 4)
|
|
||||||
tmp[0] = hex(length >> 12)
|
|
||||||
tmp[1] = hex(length >> 8)
|
|
||||||
tmp[2] = hex(length >> 4)
|
|
||||||
tmp[3] = hex(length)
|
|
||||||
|
|
||||||
lr, err := out.Write(tmp)
|
// The maximum length of a pkt-line’s data component is 65516 bytes.
|
||||||
|
// Implementations MUST NOT send pkt-line whose length exceeds 65520 (65516 bytes of payload + 4 bytes of length data).
|
||||||
|
if length > 65520 {
|
||||||
|
return fail(ctx, "Protocol: write error", "Pkt-Line exceeds maximum of 65520 bytes")
|
||||||
|
}
|
||||||
|
|
||||||
|
lr, err := fmt.Fprintf(out, "%04x", length)
|
||||||
if err != nil || lr != 4 {
|
if err != nil || lr != 4 {
|
||||||
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
|
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
215
cmd/hook_test.go
215
cmd/hook_test.go
|
@ -7,36 +7,205 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/private"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPktLine(t *testing.T) {
|
// Capture what's being written into a standard file descriptor.
|
||||||
// test read
|
func captureOutput(t *testing.T, stdFD *os.File) (finish func() (output string)) {
|
||||||
ctx := context.Background()
|
t.Helper()
|
||||||
s := strings.NewReader("0000")
|
|
||||||
r := bufio.NewReader(s)
|
|
||||||
result, err := readPktLine(ctx, r, pktLineTypeFlush)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, pktLineTypeFlush, result.Type)
|
|
||||||
|
|
||||||
s = strings.NewReader("0006a\n")
|
r, w, err := os.Pipe()
|
||||||
r = bufio.NewReader(s)
|
require.NoError(t, err)
|
||||||
result, err = readPktLine(ctx, r, pktLineTypeData)
|
resetStdout := test.MockVariableValue(stdFD, *w)
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, pktLineTypeData, result.Type)
|
|
||||||
assert.Equal(t, []byte("a\n"), result.Data)
|
|
||||||
|
|
||||||
// test write
|
return func() (output string) {
|
||||||
w := bytes.NewBuffer([]byte{})
|
w.Close()
|
||||||
err = writeFlushPktLine(ctx, w)
|
resetStdout()
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, []byte("0000"), w.Bytes())
|
|
||||||
|
|
||||||
w.Reset()
|
out, err := io.ReadAll(r)
|
||||||
err = writeDataPktLine(ctx, w, []byte("a\nb"))
|
require.NoError(t, err)
|
||||||
assert.NoError(t, err)
|
return string(out)
|
||||||
assert.Equal(t, []byte("0007a\nb"), w.Bytes())
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPktLine(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Run("Read", func(t *testing.T) {
|
||||||
|
s := strings.NewReader("0000")
|
||||||
|
r := bufio.NewReader(s)
|
||||||
|
result, err := readPktLine(ctx, r, pktLineTypeFlush)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, pktLineTypeFlush, result.Type)
|
||||||
|
|
||||||
|
s = strings.NewReader("0006a\n")
|
||||||
|
r = bufio.NewReader(s)
|
||||||
|
result, err = readPktLine(ctx, r, pktLineTypeData)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, pktLineTypeData, result.Type)
|
||||||
|
assert.Equal(t, []byte("a\n"), result.Data)
|
||||||
|
|
||||||
|
s = strings.NewReader("0004")
|
||||||
|
r = bufio.NewReader(s)
|
||||||
|
result, err = readPktLine(ctx, r, pktLineTypeData)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, result)
|
||||||
|
|
||||||
|
data := strings.Repeat("x", 65516)
|
||||||
|
r = bufio.NewReader(strings.NewReader("fff0" + data))
|
||||||
|
result, err = readPktLine(ctx, r, pktLineTypeData)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, pktLineTypeData, result.Type)
|
||||||
|
assert.Equal(t, []byte(data), result.Data)
|
||||||
|
|
||||||
|
r = bufio.NewReader(strings.NewReader("fff1a"))
|
||||||
|
result, err = readPktLine(ctx, r, pktLineTypeData)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, result)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Write", func(t *testing.T) {
|
||||||
|
w := bytes.NewBuffer([]byte{})
|
||||||
|
err := writeFlushPktLine(ctx, w)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("0000"), w.Bytes())
|
||||||
|
|
||||||
|
w.Reset()
|
||||||
|
err = writeDataPktLine(ctx, w, []byte("a\nb"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("0007a\nb"), w.Bytes())
|
||||||
|
|
||||||
|
w.Reset()
|
||||||
|
data := bytes.Repeat([]byte{0x05}, 288)
|
||||||
|
err = writeDataPktLine(ctx, w, data)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, append([]byte("0124"), data...), w.Bytes())
|
||||||
|
|
||||||
|
w.Reset()
|
||||||
|
err = writeDataPktLine(ctx, w, nil)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Empty(t, w.Bytes())
|
||||||
|
|
||||||
|
w.Reset()
|
||||||
|
data = bytes.Repeat([]byte{0x64}, 65516)
|
||||||
|
err = writeDataPktLine(ctx, w, data)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, append([]byte("fff0"), data...), w.Bytes())
|
||||||
|
|
||||||
|
w.Reset()
|
||||||
|
err = writeDataPktLine(ctx, w, bytes.Repeat([]byte{0x64}, 65516+1))
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Empty(t, w.Bytes())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelayWriter(t *testing.T) {
|
||||||
|
// Setup the environment.
|
||||||
|
defer test.MockVariableValue(&setting.InternalToken, "Random")()
|
||||||
|
defer test.MockVariableValue(&setting.InstallLock, true)()
|
||||||
|
defer test.MockVariableValue(&setting.Git.VerbosePush, true)()
|
||||||
|
require.NoError(t, os.Setenv("SSH_ORIGINAL_COMMAND", "true"))
|
||||||
|
|
||||||
|
// Setup the Stdin.
|
||||||
|
f, err := os.OpenFile(t.TempDir()+"/stdin", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o666)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = f.Write([]byte("00000000000000000000 00000000000000000001 refs/head/main\n"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = f.Seek(0, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer test.MockVariableValue(os.Stdin, *f)()
|
||||||
|
|
||||||
|
// Setup the server that processes the hooks.
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
time.Sleep(time.Millisecond * 600)
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
defer test.MockVariableValue(&setting.LocalURL, ts.URL+"/")()
|
||||||
|
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Commands = []*cli.Command{subcmdHookPreReceive}
|
||||||
|
|
||||||
|
t.Run("Should delay", func(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Millisecond*500)()
|
||||||
|
finish := captureOutput(t, os.Stdout)
|
||||||
|
|
||||||
|
err = app.Run([]string{"./forgejo", "pre-receive"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
out := finish()
|
||||||
|
|
||||||
|
require.Contains(t, out, "* Checking 1 references")
|
||||||
|
require.Contains(t, out, "Checked 1 references in total")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Shouldn't delay", func(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Second*5)()
|
||||||
|
finish := captureOutput(t, os.Stdout)
|
||||||
|
|
||||||
|
err = app.Run([]string{"./forgejo", "pre-receive"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
out := finish()
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Empty(t, out)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPushOptions(t *testing.T) {
|
||||||
|
require.NoError(t, os.Setenv(private.GitPushOptionCount, "3"))
|
||||||
|
require.NoError(t, os.Setenv("GIT_PUSH_OPTION_0", "force-push"))
|
||||||
|
require.NoError(t, os.Setenv("GIT_PUSH_OPTION_1", "option=value"))
|
||||||
|
require.NoError(t, os.Setenv("GIT_PUSH_OPTION_2", "option-double=another=value"))
|
||||||
|
require.NoError(t, os.Setenv("GIT_PUSH_OPTION_3", "not=valid"))
|
||||||
|
|
||||||
|
assert.Equal(t, map[string]string{
|
||||||
|
"force-push": "true",
|
||||||
|
"option": "value",
|
||||||
|
"option-double": "another=value",
|
||||||
|
}, pushOptions())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunHookUpdate(t *testing.T) {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Commands = []*cli.Command{subcmdHookUpdate}
|
||||||
|
|
||||||
|
t.Run("Removal of internal reference", func(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
||||||
|
defer test.MockVariableValue(&setting.IsProd, false)()
|
||||||
|
finish := captureOutput(t, os.Stderr)
|
||||||
|
|
||||||
|
err := app.Run([]string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
||||||
|
out := finish()
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
assert.Contains(t, out, "The deletion of refs/pull/1/head is skipped as it's an internal reference.")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Update of internal reference", func(t *testing.T) {
|
||||||
|
err := app.Run([]string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000001"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Removal of branch", func(t *testing.T) {
|
||||||
|
err := app.Run([]string{"./forgejo", "update", "refs/head/main", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Not enough arguments", func(t *testing.T) {
|
||||||
|
err := app.Run([]string{"./forgejo", "update"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
@ -106,7 +107,10 @@ func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error
|
||||||
logMsg = userMessage + ". " + logMsg
|
logMsg = userMessage + ". " + logMsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = private.SSHLog(ctx, true, logMsg)
|
// Don't send an log if this is done in a test and no InternalToken is set.
|
||||||
|
if !testing.Testing() || setting.InternalToken != "" {
|
||||||
|
_ = private.SSHLog(ctx, true, logMsg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return cli.Exit("", 1)
|
return cli.Exit("", 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -441,7 +441,7 @@ INTERNAL_TOKEN =
|
||||||
;INTERNAL_TOKEN_URI = file:/etc/gitea/internal_token
|
;INTERNAL_TOKEN_URI = file:/etc/gitea/internal_token
|
||||||
;;
|
;;
|
||||||
;; How long to remember that a user is logged in before requiring relogin (in days)
|
;; How long to remember that a user is logged in before requiring relogin (in days)
|
||||||
;LOGIN_REMEMBER_DAYS = 7
|
;LOGIN_REMEMBER_DAYS = 31
|
||||||
;;
|
;;
|
||||||
;; Name of the cookie used to store the current username.
|
;; Name of the cookie used to store the current username.
|
||||||
;COOKIE_USERNAME = gitea_awesome
|
;COOKIE_USERNAME = gitea_awesome
|
||||||
|
@ -969,6 +969,12 @@ LEVEL = Info
|
||||||
;GO_GET_CLONE_URL_PROTOCOL = https
|
;GO_GET_CLONE_URL_PROTOCOL = https
|
||||||
;;
|
;;
|
||||||
;; Close issues as long as a commit on any branch marks it as fixed
|
;; Close issues as long as a commit on any branch marks it as fixed
|
||||||
|
;DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH = false
|
||||||
|
;;
|
||||||
|
;; Allow users to push local repositories to Gitea and have them automatically created for a user or an org
|
||||||
|
;ENABLE_PUSH_CREATE_USER = false
|
||||||
|
;ENABLE_PUSH_CREATE_ORG = false
|
||||||
|
;;
|
||||||
;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions.
|
;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions.
|
||||||
;DISABLED_REPO_UNITS =
|
;DISABLED_REPO_UNITS =
|
||||||
;;
|
;;
|
||||||
|
@ -1492,9 +1498,16 @@ LEVEL = Info
|
||||||
;DEFAULT_EMAIL_NOTIFICATIONS = enabled
|
;DEFAULT_EMAIL_NOTIFICATIONS = enabled
|
||||||
;; Send an email to all admins when a new user signs up to inform the admins about this act. Options: true, false
|
;; Send an email to all admins when a new user signs up to inform the admins about this act. Options: true, false
|
||||||
;SEND_NOTIFICATION_EMAIL_ON_NEW_USER = false
|
;SEND_NOTIFICATION_EMAIL_ON_NEW_USER = false
|
||||||
;; Disabled features for users, could be "deletion", more features can be disabled in future
|
;; Disabled features for users, could be "deletion", "manage_ssh_keys","manage_gpg_keys" more features can be disabled in future
|
||||||
;; - deletion: a user cannot delete their own account
|
;; - deletion: a user cannot delete their own account
|
||||||
|
;; - manage_ssh_keys: a user cannot configure ssh keys
|
||||||
|
;; - manage_gpg_keys: a user cannot configure gpg keys
|
||||||
;USER_DISABLED_FEATURES =
|
;USER_DISABLED_FEATURES =
|
||||||
|
;; Comma separated list of disabled features ONLY if the user has an external login type (eg. LDAP, Oauth, etc.), could be `deletion`, `manage_ssh_keys`, `manage_gpg_keys`. This setting is independent from `USER_DISABLED_FEATURES` and supplements its behavior.
|
||||||
|
;; - deletion: a user cannot delete their own account
|
||||||
|
;; - manage_ssh_keys: a user cannot configure ssh keys
|
||||||
|
;; - manage_gpg_keys: a user cannot configure gpg keys
|
||||||
|
;;EXTERNAL_USER_DISABLE_FEATURES =
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -2318,6 +2331,8 @@ LEVEL = Info
|
||||||
;SHOW_FOOTER_VERSION = true
|
;SHOW_FOOTER_VERSION = true
|
||||||
;; Show template execution time in the footer
|
;; Show template execution time in the footer
|
||||||
;SHOW_FOOTER_TEMPLATE_LOAD_TIME = true
|
;SHOW_FOOTER_TEMPLATE_LOAD_TIME = true
|
||||||
|
;; Show the "powered by" text in the footer
|
||||||
|
;SHOW_FOOTER_POWERED_BY = true
|
||||||
;; Generate sitemap. Defaults to `true`.
|
;; Generate sitemap. Defaults to `true`.
|
||||||
;ENABLE_SITEMAP = true
|
;ENABLE_SITEMAP = true
|
||||||
;; Enable/Disable RSS/Atom feed
|
;; Enable/Disable RSS/Atom feed
|
||||||
|
@ -2330,6 +2345,8 @@ LEVEL = Info
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Set the maximum number of characters in a mermaid source. (Set to -1 to disable limits)
|
;; Set the maximum number of characters in a mermaid source. (Set to -1 to disable limits)
|
||||||
;MERMAID_MAX_SOURCE_CHARACTERS = 5000
|
;MERMAID_MAX_SOURCE_CHARACTERS = 5000
|
||||||
|
;; Set the maximum number of lines allowed for a filepreview. (Set to -1 to disable limits; set to 0 to disable the feature)
|
||||||
|
;FILEPREVIEW_MAX_LINES = 50
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -2615,7 +2632,7 @@ LEVEL = Info
|
||||||
;ENDLESS_TASK_TIMEOUT = 3h
|
;ENDLESS_TASK_TIMEOUT = 3h
|
||||||
;; Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time
|
;; Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time
|
||||||
;ABANDONED_JOB_TIMEOUT = 24h
|
;ABANDONED_JOB_TIMEOUT = 24h
|
||||||
;; Strings committers can place inside a commit message to skip executing the corresponding actions workflow
|
;; Strings committers can place inside a commit message or PR title to skip executing the corresponding actions workflow
|
||||||
;SKIP_WORKFLOW_STRINGS = [skip ci],[ci skip],[no ci],[skip actions],[actions skip]
|
;SKIP_WORKFLOW_STRINGS = [skip ci],[ci skip],[no ci],[skip actions],[actions skip]
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
7
docs/.gitignore
vendored
7
docs/.gitignore
vendored
|
@ -1,7 +0,0 @@
|
||||||
public/
|
|
||||||
templates/swagger/v1_json.tmpl
|
|
||||||
themes/
|
|
||||||
resources/
|
|
||||||
|
|
||||||
# Temporary lock file while building
|
|
||||||
/.hugo_build.lock
|
|
202
docs/LICENSE
202
docs/LICENSE
|
@ -1,202 +0,0 @@
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
|
@ -1,22 +0,0 @@
|
||||||
# Gitea: Docs
|
|
||||||
|
|
||||||
[![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea)
|
|
||||||
[![](https://images.microbadger.com/badges/image/gitea/docs.svg)](http://microbadger.com/images/gitea/docs "Get your own image badge on microbadger.com")
|
|
||||||
|
|
||||||
These docs are ingested by our [docs repo](https://gitea.com/gitea/gitea-docusaurus).
|
|
||||||
|
|
||||||
## Authors
|
|
||||||
|
|
||||||
* [Maintainers](https://github.com/orgs/go-gitea/people)
|
|
||||||
* [Contributors](https://github.com/go-gitea/docs/graphs/contributors)
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This project is under the Apache-2.0 License. See the [LICENSE](LICENSE) file
|
|
||||||
for the full license text.
|
|
||||||
|
|
||||||
## Copyright
|
|
||||||
|
|
||||||
```
|
|
||||||
Copyright (c) 2016 The Gitea Authors <https://gitea.io>
|
|
||||||
```
|
|
|
@ -1,22 +0,0 @@
|
||||||
# Gitea: 文档
|
|
||||||
|
|
||||||
[![Build Status](http://drone.gitea.io/api/badges/go-gitea/docs/status.svg)](http://drone.gitea.io/go-gitea/docs)
|
|
||||||
[![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea)
|
|
||||||
[![](https://images.microbadger.com/badges/image/gitea/docs.svg)](http://microbadger.com/images/gitea/docs "Get your own image badge on microbadger.com")
|
|
||||||
|
|
||||||
https://gitea.com/gitea/gitea-docusaurus
|
|
||||||
|
|
||||||
## 关于我们
|
|
||||||
|
|
||||||
* [维护者信息](https://github.com/orgs/go-gitea/people)
|
|
||||||
* [代码贡献者信息](https://github.com/go-gitea/docs/graphs/contributors)
|
|
||||||
|
|
||||||
## 许可证
|
|
||||||
|
|
||||||
此项目采用 Apache-2.0 许可协议,请参见 [协议文件](LICENSE) 获取更多信息。
|
|
||||||
|
|
||||||
## 版权声明
|
|
||||||
|
|
||||||
```
|
|
||||||
Copyright (c) 2016 The Gitea Authors <https://gitea.io>
|
|
||||||
```
|
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-04-27T14:00:00+08:00"
|
|
||||||
title: "Actions"
|
|
||||||
slug: "actions"
|
|
||||||
sidebar_position: 36
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
name: "Usage - Actions"
|
|
||||||
sidebar_position: 31
|
|
||||||
identifier: "actions"
|
|
||||||
---
|
|
|
@ -1,14 +0,0 @@
|
||||||
---
|
|
||||||
date: "2016-12-01T16:00:00+02:00"
|
|
||||||
title: "Administration"
|
|
||||||
slug: "administration"
|
|
||||||
sidebar_position: 30
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
name: "Administration"
|
|
||||||
sidebar_position: 20
|
|
||||||
collapse: true
|
|
||||||
identifier: "administration"
|
|
||||||
---
|
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
date: "2016-12-01T16:00:00+02:00"
|
|
||||||
title: "运维"
|
|
||||||
slug: "administration"
|
|
||||||
sidebar_position: 30
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
name: "运维"
|
|
||||||
sidebar_position: 20
|
|
||||||
identifier: "administration"
|
|
||||||
---
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-12-28"
|
|
||||||
title: "Adding Legal Pages"
|
|
||||||
slug: adding-legal-pages
|
|
||||||
sidebar_position: 110
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/adding-legal-pages
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Adding Legal Pages"
|
|
||||||
identifier: "adding-legal-pages"
|
|
||||||
sidebar_position: 110
|
|
||||||
---
|
|
||||||
|
|
||||||
Some jurisdictions (such as EU), requires certain legal pages (e.g. Privacy Policy) to be added to website. Follow these steps to add them to your Gitea instance.
|
|
||||||
|
|
||||||
## Getting Pages
|
|
||||||
|
|
||||||
Gitea source code ships with sample pages, available in `contrib/legal` directory. Copy them to `custom/public/assets/`. For example, to add Privacy Policy:
|
|
||||||
|
|
||||||
```
|
|
||||||
wget -O /path/to/custom/public/assets/privacy.html https://raw.githubusercontent.com/go-gitea/gitea/main/contrib/legal/privacy.html.sample
|
|
||||||
```
|
|
||||||
|
|
||||||
Now you need to edit the page to meet your requirements. In particular you must change the email addresses, web addresses and references to "Your Gitea Instance" to match your situation.
|
|
||||||
|
|
||||||
You absolutely must not place a general ToS or privacy statement that implies that the Gitea project is responsible for your server.
|
|
||||||
|
|
||||||
## Make it Visible
|
|
||||||
|
|
||||||
Create or append to `/path/to/custom/templates/custom/extra_links_footer.tmpl`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
<a class="item" href="{{AppSubUrl}}/assets/privacy.html">Privacy Policy</a>
|
|
||||||
```
|
|
||||||
|
|
||||||
Restart Gitea to see the changes.
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "添加法律页面"
|
|
||||||
slug: adding-legal-pages
|
|
||||||
sidebar_position: 110
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/adding-legal-pages
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "添加法律页面"
|
|
||||||
identifier: "adding-legal-pages"
|
|
||||||
sidebar_position: 110
|
|
||||||
---
|
|
||||||
|
|
||||||
一些法域(例如欧盟)要求在网站上添加特定的法律页面(例如隐私政策)。按照以下步骤将它们添加到你的 Gitea 实例中。
|
|
||||||
|
|
||||||
## 获取页面
|
|
||||||
|
|
||||||
Gitea 源代码附带了示例页面,位于 `contrib/legal` 目录中。将它们复制到 `custom/public/assets/` 目录下。例如,如果要添加隐私政策:
|
|
||||||
|
|
||||||
```
|
|
||||||
wget -O /path/to/custom/public/assets/privacy.html https://raw.githubusercontent.com/go-gitea/gitea/main/contrib/legal/privacy.html.sample
|
|
||||||
```
|
|
||||||
|
|
||||||
现在,你需要编辑该页面以满足你的需求。特别是,你必须更改电子邮件地址、网址以及与 "Your Gitea Instance" 相关的引用,以匹配你的情况。
|
|
||||||
|
|
||||||
请务必不要放置会暗示 Gitea 项目对你的服务器负责的一般服务条款或隐私声明。
|
|
||||||
|
|
||||||
## 使其可见
|
|
||||||
|
|
||||||
创建或追加到 `/path/to/custom/templates/custom/extra_links_footer.tmpl` 文件中:
|
|
||||||
|
|
||||||
```go
|
|
||||||
<a class="item" href="{{AppSubUrl}}/assets/privacy.html">隐私政策</a>
|
|
||||||
```
|
|
||||||
|
|
||||||
重启 Gitea 以查看更改。
|
|
|
@ -1,158 +0,0 @@
|
||||||
---
|
|
||||||
date: "2017-01-01T16:00:00+02:00"
|
|
||||||
title: "Backup and Restore"
|
|
||||||
slug: "backup-and-restore"
|
|
||||||
sidebar_position: 11
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/backup-and-restore
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Backup and Restore"
|
|
||||||
sidebar_position: 11
|
|
||||||
identifier: "backup-and-restore"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Backup and Restore
|
|
||||||
|
|
||||||
Gitea currently has a `dump` command that will save the installation to a ZIP file. This
|
|
||||||
file can be unpacked and used to restore an instance.
|
|
||||||
|
|
||||||
## Backup Consistency
|
|
||||||
|
|
||||||
To ensure the consistency of the Gitea instance, it must be shutdown during backup.
|
|
||||||
|
|
||||||
Gitea consists of a database, files and git repositories, all of which change when it is used. For instance, when a migration is in progress, a transaction is created in the database while the git repository is being copied over. If the backup happens in the middle of the migration, the git repository may be incomplete although the database claims otherwise because it was dumped afterwards. The only way to avoid such race conditions is by stopping the Gitea instance during the backups.
|
|
||||||
|
|
||||||
## Backup Command (`dump`)
|
|
||||||
|
|
||||||
Switch to the user running Gitea: `su git`. Run `./gitea dump -c /path/to/app.ini` in the Gitea installation
|
|
||||||
directory. There should be some output similar to the following:
|
|
||||||
|
|
||||||
```none
|
|
||||||
2016/12/27 22:32:09 Creating tmp work dir: /tmp/gitea-dump-417443001
|
|
||||||
2016/12/27 22:32:09 Dumping local repositories.../home/git/gitea-repositories
|
|
||||||
2016/12/27 22:32:22 Dumping database...
|
|
||||||
2016/12/27 22:32:22 Packing dump files...
|
|
||||||
2016/12/27 22:32:34 Removing tmp work dir: /tmp/gitea-dump-417443001
|
|
||||||
2016/12/27 22:32:34 Finish dumping in file gitea-dump-1482906742.zip
|
|
||||||
```
|
|
||||||
|
|
||||||
Inside the `gitea-dump-1482906742.zip` file, will be the following:
|
|
||||||
|
|
||||||
- `app.ini` - Optional copy of configuration file if originally stored outside the default `custom/` directory
|
|
||||||
- `custom/` - All config or customization files in `custom/`.
|
|
||||||
- `data/` - Data directory (APP_DATA_PATH), except sessions if you are using file session. This directory includes `attachments`, `avatars`, `lfs`, `indexers`, SQLite file if you are using SQLite.
|
|
||||||
- `repos/` - Complete copy of the repository directory.
|
|
||||||
- `gitea-db.sql` - SQL dump of database
|
|
||||||
- `log/` - Various logs. They are not needed for a recovery or migration.
|
|
||||||
|
|
||||||
Intermediate backup files are created in a temporary directory specified either with the
|
|
||||||
`--tempdir` command-line parameter or the `TMPDIR` environment variable.
|
|
||||||
|
|
||||||
## Backup the database
|
|
||||||
|
|
||||||
The SQL dump created by `gitea dump` uses XORM and Gitea admins may prefer to use the native the MySQL and PostgreSQL dump tools instead. There are still open issues when using XORM for dumping the database that may cause problems when attempting to restore it.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# mysql
|
|
||||||
mysqldump -u$USER -p$PASS --database $DATABASE > gitea-db.sql
|
|
||||||
# postgres
|
|
||||||
pg_dump -U $USER $DATABASE > gitea-db.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using Docker (`dump`)
|
|
||||||
|
|
||||||
There are a few caveats for using the `dump` command with Docker.
|
|
||||||
|
|
||||||
The command has to be executed with the `RUN_USER = <OS_USERNAME>` specified in `gitea/conf/app.ini`; and, for the zipping of the backup folder to occur without permission error the command `docker exec` must be executed inside of the `--tempdir`.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```none
|
|
||||||
docker exec -u <OS_USERNAME> -it -w <--tempdir> $(docker ps -qf 'name=^<NAME_OF_DOCKER_CONTAINER>$') bash -c '/usr/local/bin/gitea dump -c </path/to/app.ini>'
|
|
||||||
```
|
|
||||||
|
|
||||||
\*Note: `--tempdir` refers to the temporary directory of the docker environment used by Gitea; if you have not specified a custom `--tempdir`, then Gitea uses `/tmp` or the `TMPDIR` environment variable of the docker container. For `--tempdir` adjust your `docker exec` command options accordingly.
|
|
||||||
|
|
||||||
The result should be a file, stored in the `--tempdir` specified, along the lines of: `gitea-dump-1482906742.zip`
|
|
||||||
|
|
||||||
## Restore Command (`restore`)
|
|
||||||
|
|
||||||
There is currently no support for a recovery command. It is a manual process that mostly
|
|
||||||
involves moving files to their correct locations and restoring a database dump.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
unzip gitea-dump-1610949662.zip
|
|
||||||
cd gitea-dump-1610949662
|
|
||||||
mv app.ini /etc/gitea/conf/app.ini
|
|
||||||
mv data/* /var/lib/gitea/data/
|
|
||||||
mv log/* /var/lib/gitea/log/
|
|
||||||
mv repos/* /var/lib/gitea/gitea-repositories/
|
|
||||||
chown -R gitea:gitea /etc/gitea/conf/app.ini /var/lib/gitea
|
|
||||||
|
|
||||||
# mysql
|
|
||||||
mysql --default-character-set=utf8mb4 -u$USER -p$PASS $DATABASE <gitea-db.sql
|
|
||||||
# sqlite3
|
|
||||||
sqlite3 $DATABASE_PATH <gitea-db.sql
|
|
||||||
# postgres
|
|
||||||
psql -U $USER -d $DATABASE < gitea-db.sql
|
|
||||||
|
|
||||||
service gitea restart
|
|
||||||
```
|
|
||||||
|
|
||||||
Repository Git Hooks should be regenerated if installation method is changed (eg. binary -> Docker), or if Gitea is installed to a different directory than the previous installation.
|
|
||||||
|
|
||||||
With Gitea running, and from the directory Gitea's binary is located, execute: `./gitea admin regenerate hooks`
|
|
||||||
|
|
||||||
This ensures that application and configuration file paths in repository Git Hooks are consistent and applicable to the current installation. If these paths are not updated, repository `push` actions will fail.
|
|
||||||
|
|
||||||
### Using Docker (`restore`)
|
|
||||||
|
|
||||||
There is also no support for a recovery command in a Docker-based gitea instance. The restore process contains the same steps as described in the previous section but with different paths.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# open bash session in container
|
|
||||||
docker exec --user git -it 2a83b293548e bash
|
|
||||||
# unzip your backup file within the container
|
|
||||||
unzip gitea-dump-1610949662.zip
|
|
||||||
cd gitea-dump-1610949662
|
|
||||||
# restore the gitea data
|
|
||||||
mv data/* /data/gitea
|
|
||||||
# restore the repositories itself
|
|
||||||
mv repos/* /data/git/gitea-repositories/
|
|
||||||
# adjust file permissions
|
|
||||||
chown -R git:git /data
|
|
||||||
# Regenerate Git Hooks
|
|
||||||
/usr/local/bin/gitea -c '/data/gitea/conf/app.ini' admin regenerate hooks
|
|
||||||
```
|
|
||||||
|
|
||||||
The default user in the gitea container is `git` (1000:1000). Please replace `2a83b293548e` with your gitea container id or name.
|
|
||||||
|
|
||||||
### Using Docker-rootless (`restore`)
|
|
||||||
|
|
||||||
The restore workflow in Docker-rootless containers differs only in the directories to be used:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# open bash session in container
|
|
||||||
docker exec --user git -it 2a83b293548e bash
|
|
||||||
# unzip your backup file within the container
|
|
||||||
unzip gitea-dump-1610949662.zip
|
|
||||||
cd gitea-dump-1610949662
|
|
||||||
# restore the app.ini
|
|
||||||
mv data/conf/app.ini /etc/gitea/app.ini
|
|
||||||
# restore the gitea data
|
|
||||||
mv data/* /var/lib/gitea
|
|
||||||
# restore the repositories itself
|
|
||||||
mv repos/* /var/lib/gitea/git/gitea-repositories
|
|
||||||
# adjust file permissions
|
|
||||||
chown -R git:git /etc/gitea/app.ini /var/lib/gitea
|
|
||||||
# Regenerate Git Hooks
|
|
||||||
/usr/local/bin/gitea -c '/etc/gitea/app.ini' admin regenerate hooks
|
|
||||||
```
|
|
|
@ -1,68 +0,0 @@
|
||||||
---
|
|
||||||
date: "2018-06-06T09:33:00+08:00"
|
|
||||||
title: "备份与恢复"
|
|
||||||
slug: "backup-and-restore"
|
|
||||||
sidebar_position: 11
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/backup-and-restore
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "备份与恢复"
|
|
||||||
sidebar_position: 11
|
|
||||||
identifier: "backup-and-restore"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 备份与恢复
|
|
||||||
|
|
||||||
Gitea 已经实现了 `dump` 命令可以用来备份所有需要的文件到一个zip压缩文件。该压缩文件可以被用来进行数据恢复。
|
|
||||||
|
|
||||||
## 备份命令 (`dump`)
|
|
||||||
|
|
||||||
先转到git用户的权限: `su git`. 再Gitea目录运行 `./gitea dump`。一般会显示类似如下的输出:
|
|
||||||
|
|
||||||
```
|
|
||||||
2016/12/27 22:32:09 Creating tmp work dir: /tmp/gitea-dump-417443001
|
|
||||||
2016/12/27 22:32:09 Dumping local repositories.../home/git/gitea-repositories
|
|
||||||
2016/12/27 22:32:22 Dumping database...
|
|
||||||
2016/12/27 22:32:22 Packing dump files...
|
|
||||||
2016/12/27 22:32:34 Removing tmp work dir: /tmp/gitea-dump-417443001
|
|
||||||
2016/12/27 22:32:34 Finish dumping in file gitea-dump-1482906742.zip
|
|
||||||
```
|
|
||||||
|
|
||||||
最后生成的 `gitea-dump-1482906742.zip` 文件将会包含如下内容:
|
|
||||||
|
|
||||||
* `custom` - 所有保存在 `custom/` 目录下的配置和自定义的文件。
|
|
||||||
* `data` - 数据目录下的所有内容不包含使用文件session的文件。该目录包含 `attachments`, `avatars`, `lfs`, `indexers`, 如果使用sqlite 还会包含 sqlite 数据库文件。
|
|
||||||
* `gitea-db.sql` - 数据库dump出来的 SQL。
|
|
||||||
* `gitea-repo.zip` - Git仓库压缩文件。
|
|
||||||
* `log/` - Logs文件,如果用作迁移不是必须的。
|
|
||||||
|
|
||||||
中间备份文件将会在临时目录进行创建,如果您要重新指定临时目录,可以用 `--tempdir` 参数,或者用 `TMPDIR` 环境变量。
|
|
||||||
|
|
||||||
## Restore Command (`restore`)
|
|
||||||
|
|
||||||
当前还没有恢复命令,恢复需要人工进行。主要是把文件和数据库进行恢复。
|
|
||||||
|
|
||||||
例如:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
unzip gitea-dump-1610949662.zip
|
|
||||||
cd gitea-dump-1610949662
|
|
||||||
mv data/conf/app.ini /etc/gitea/conf/app.ini
|
|
||||||
mv data/* /var/lib/gitea/data/
|
|
||||||
mv log/* /var/lib/gitea/log/
|
|
||||||
mv repos/* /var/lib/gitea/repositories/
|
|
||||||
chown -R gitea:gitea /etc/gitea/conf/app.ini /var/lib/gitea
|
|
||||||
|
|
||||||
# mysql
|
|
||||||
mysql --default-character-set=utf8mb4 -u$USER -p$PASS $DATABASE <gitea-db.sql
|
|
||||||
# sqlite3
|
|
||||||
sqlite3 $DATABASE_PATH <gitea-db.sql
|
|
||||||
# postgres
|
|
||||||
psql -U $USER -d $DATABASE < gitea-db.sql
|
|
||||||
|
|
||||||
service gitea restart
|
|
||||||
```
|
|
|
@ -1,119 +0,0 @@
|
||||||
---
|
|
||||||
date: "2020-01-25T21:00:00-03:00"
|
|
||||||
title: "Embedded data extraction tool"
|
|
||||||
slug: "cmd-embedded"
|
|
||||||
sidebar_position: 20
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/cmd-embedded
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Embedded data extraction tool"
|
|
||||||
sidebar_position: 20
|
|
||||||
identifier: "cmd-embedded"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Embedded data extraction tool
|
|
||||||
|
|
||||||
Gitea's executable contains all the resources required to run: templates, images, style-sheets
|
|
||||||
and translations. Any of them can be overridden by placing a replacement in a matching path
|
|
||||||
inside the `custom` directory (see [Customizing Gitea](administration/customizing-gitea.md)).
|
|
||||||
|
|
||||||
To obtain a copy of the embedded resources ready for editing, the `embedded` command from the CLI
|
|
||||||
can be used from the OS shell interface.
|
|
||||||
|
|
||||||
**NOTE:** The embedded data extraction tool is included in Gitea versions 1.12 and above.
|
|
||||||
|
|
||||||
## Listing resources
|
|
||||||
|
|
||||||
To list resources embedded in Gitea's executable, use the following syntax:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
gitea embedded list [--include-vendored] [patterns...]
|
|
||||||
```
|
|
||||||
|
|
||||||
The `--include-vendored` flag makes the command include vendored files, which are
|
|
||||||
normally excluded; that is, files from external libraries that are required for Gitea
|
|
||||||
(e.g. [octicons](https://octicons.github.com/), etc).
|
|
||||||
|
|
||||||
A list of file search patterns can be provided. Gitea uses [gobwas/glob](https://github.com/gobwas/glob)
|
|
||||||
for its glob syntax. Here are some examples:
|
|
||||||
|
|
||||||
- List all template files, in any virtual directory: `**.tmpl`
|
|
||||||
- List all mail template files: `templates/mail/**.tmpl`
|
|
||||||
- List all files inside `public/assets/img`: `public/assets/img/**`
|
|
||||||
|
|
||||||
Don't forget to use quotes for the patterns, as spaces, `*` and other characters might have
|
|
||||||
a special meaning for your command shell.
|
|
||||||
|
|
||||||
If no pattern is provided, all files are listed.
|
|
||||||
|
|
||||||
### Example: Listing all embedded files
|
|
||||||
|
|
||||||
Listing all embedded files with `openid` in their path:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ gitea embedded list '**openid**'
|
|
||||||
public/assets/img/auth/openid_connect.svg
|
|
||||||
public/assets/img/openid-16x16.png
|
|
||||||
templates/user/auth/finalize_openid.tmpl
|
|
||||||
templates/user/auth/signin_openid.tmpl
|
|
||||||
templates/user/auth/signup_openid_connect.tmpl
|
|
||||||
templates/user/auth/signup_openid_navbar.tmpl
|
|
||||||
templates/user/auth/signup_openid_register.tmpl
|
|
||||||
templates/user/settings/security_openid.tmpl
|
|
||||||
```
|
|
||||||
|
|
||||||
## Extracting resources
|
|
||||||
|
|
||||||
To extract resources embedded in Gitea's executable, use the following syntax:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
gitea [--config {file}] embedded extract [--destination {dir}|--custom] [--overwrite|--rename] [--include-vendored] {patterns...}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `--config` option tells Gitea the location of the `app.ini` configuration file if
|
|
||||||
it's not in its default location. This option is only used with the `--custom` flag.
|
|
||||||
|
|
||||||
The `--destination` option tells Gitea the directory where the files must be extracted to.
|
|
||||||
The default is the current directory.
|
|
||||||
|
|
||||||
The `--custom` flag tells Gitea to extract the files directly into the `custom` directory.
|
|
||||||
For this to work, the command needs to know the location of the `app.ini` configuration
|
|
||||||
file (`--config`) and, depending of the configuration, be ran from the directory where
|
|
||||||
Gitea normally starts. See [Customizing Gitea](administration/customizing-gitea.md) for details.
|
|
||||||
|
|
||||||
The `--overwrite` flag allows any existing files in the destination directory to be overwritten.
|
|
||||||
|
|
||||||
The `--rename` flag tells Gitea to rename any existing files in the destination directory
|
|
||||||
as `filename.bak`. Previous `.bak` files are overwritten.
|
|
||||||
|
|
||||||
At least one file search pattern must be provided; see `list` subcomand above for pattern
|
|
||||||
syntax and examples.
|
|
||||||
|
|
||||||
### Important notice
|
|
||||||
|
|
||||||
Make sure to **only extract those files that require customization**. Files that
|
|
||||||
are present in the `custom` directory are not upgraded by Gitea's upgrade process.
|
|
||||||
When Gitea is upgraded to a new version (by replacing the executable), many of the
|
|
||||||
embedded files will suffer changes. Gitea will honor and use any files found
|
|
||||||
in the `custom` directory, even if they are old and incompatible.
|
|
||||||
|
|
||||||
### Example: Extracting mail templates
|
|
||||||
|
|
||||||
Extracting mail templates to a temporary directory:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ mkdir tempdir
|
|
||||||
$ gitea embedded extract --destination tempdir 'templates/mail/**.tmpl'
|
|
||||||
Extracting to tempdir:
|
|
||||||
tempdir/templates/mail/auth/activate.tmpl
|
|
||||||
tempdir/templates/mail/auth/activate_email.tmpl
|
|
||||||
tempdir/templates/mail/auth/register_notify.tmpl
|
|
||||||
tempdir/templates/mail/auth/reset_passwd.tmpl
|
|
||||||
tempdir/templates/mail/issue/assigned.tmpl
|
|
||||||
tempdir/templates/mail/issue/default.tmpl
|
|
||||||
tempdir/templates/mail/notify/collaborator.tmpl
|
|
||||||
```
|
|
|
@ -1,101 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "嵌入资源提取工具"
|
|
||||||
slug: "cmd-embedded"
|
|
||||||
sidebar_position: 20
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/cmd-embedded
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "嵌入资源提取工具"
|
|
||||||
sidebar_position: 20
|
|
||||||
identifier: "cmd-embedded"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 嵌入资源提取工具
|
|
||||||
|
|
||||||
Gitea 的可执行文件包含了运行所需的所有资源:模板、图片、样式表和翻译文件。你可以通过在 `custom` 目录下的相应路径中放置替换文件来覆盖其中的任何资源(详见 [自定义 Gitea 配置](administration/customizing-gitea.md))。
|
|
||||||
|
|
||||||
要获取嵌入资源的副本以进行编辑,可以使用 CLI 中的 `embedded` 命令,通过操作系统的 shell 执行。
|
|
||||||
|
|
||||||
**注意:** 嵌入资源提取工具包含在 Gitea 1.12 及以上版本中。
|
|
||||||
|
|
||||||
## 资源列表
|
|
||||||
|
|
||||||
要列出嵌入在 Gitea 可执行文件中的资源,请使用以下语法:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
gitea embedded list [--include-vendored] [patterns...]
|
|
||||||
```
|
|
||||||
|
|
||||||
`--include-vendored` 标志使命令包括被供应的文件,这些文件通常被排除在外;即来自外部库的文件,这些文件是 Gitea 所需的(例如 [octicons](https://octicons.github.com/) 等)。
|
|
||||||
|
|
||||||
可以提供一系列文件搜索模式。Gitea 使用 [gobwas/glob](https://github.com/gobwas/glob) 作为其 glob 语法。以下是一些示例:
|
|
||||||
|
|
||||||
- 列出所有模板文件,无论在哪个虚拟目录下:`**.tmpl`
|
|
||||||
- 列出所有邮件模板文件:`templates/mail/**.tmpl`
|
|
||||||
- 列出 `public/img` 目录下的所有文件:`public/img/**`
|
|
||||||
|
|
||||||
不要忘记为模式使用引号,因为空格、`*` 和其他字符可能对命令行解释器有特殊含义。
|
|
||||||
|
|
||||||
如果未提供模式,则列出所有文件。
|
|
||||||
|
|
||||||
### 示例:列出所有嵌入文件
|
|
||||||
|
|
||||||
列出所有路径中包含 `openid` 的嵌入文件:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ gitea embedded list '**openid**'
|
|
||||||
public/img/auth/openid_connect.svg
|
|
||||||
public/img/openid-16x16.png
|
|
||||||
templates/user/auth/finalize_openid.tmpl
|
|
||||||
templates/user/auth/signin_openid.tmpl
|
|
||||||
templates/user/auth/signup_openid_connect.tmpl
|
|
||||||
templates/user/auth/signup_openid_navbar.tmpl
|
|
||||||
templates/user/auth/signup_openid_register.tmpl
|
|
||||||
templates/user/settings/security_openid.tmpl
|
|
||||||
```
|
|
||||||
|
|
||||||
## 提取资源
|
|
||||||
|
|
||||||
要提取嵌入在 Gitea 可执行文件中的资源,请使用以下语法:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
gitea [--config {file}] embedded extract [--destination {dir}|--custom] [--overwrite|--rename] [--include-vendored] {patterns...}
|
|
||||||
```
|
|
||||||
|
|
||||||
`--config` 选项用于告知 Gitea `app.ini` 配置文件的位置(如果不在默认位置)。此选项仅在使用 `--custom` 标志时使用。
|
|
||||||
|
|
||||||
`--destination` 选项用于指定提取文件的目标目录。默认为当前目录。
|
|
||||||
|
|
||||||
`--custom` 标志告知 Gitea 直接将文件提取到 `custom` 目录中。为使其正常工作,该命令需要知道 `app.ini` 配置文件的位置(通过 `--config` 指定),并且根据配置的不同,需要从 Gitea 通常启动的目录运行。有关详细信息,请参阅 [自定义 Gitea 配置](administration/customizing-gitea.md)。
|
|
||||||
|
|
||||||
`--overwrite` 标志允许覆盖目标目录中的任何现有文件。
|
|
||||||
|
|
||||||
`--rename` 标志告知 Gitea 将目标目录中的任何现有文件重命名为 `filename.bak`。之前的 `.bak` 文件将被覆盖。
|
|
||||||
|
|
||||||
至少需要提供一个文件搜索模式;有关模式的语法和示例,请参阅上述 `list` 子命令。
|
|
||||||
|
|
||||||
### 重要提示
|
|
||||||
|
|
||||||
请确保**只提取需要自定义的文件**。位于 `custom` 目录中的文件不会受到 Gitea 的升级过程的影响。当 Gitea 升级到新版本(通过替换可执行文件)时,许多嵌入文件将发生变化。Gitea 将尊重并使用在 `custom` 目录中找到的任何文件,即使这些文件是旧的和不兼容的。
|
|
||||||
|
|
||||||
### 示例:提取邮件模板
|
|
||||||
|
|
||||||
将邮件模板提取到临时目录:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ mkdir tempdir
|
|
||||||
$ gitea embedded extract --destination tempdir 'templates/mail/**.tmpl'
|
|
||||||
Extracting to tempdir:
|
|
||||||
tempdir/templates/mail/auth/activate.tmpl
|
|
||||||
tempdir/templates/mail/auth/activate_email.tmpl
|
|
||||||
tempdir/templates/mail/auth/register_notify.tmpl
|
|
||||||
tempdir/templates/mail/auth/reset_passwd.tmpl
|
|
||||||
tempdir/templates/mail/issue/assigned.tmpl
|
|
||||||
tempdir/templates/mail/issue/default.tmpl
|
|
||||||
tempdir/templates/mail/notify/collaborator.tmpl
|
|
||||||
```
|
|
|
@ -1,572 +0,0 @@
|
||||||
---
|
|
||||||
date: "2017-01-01T16:00:00+02:00"
|
|
||||||
title: "Gitea Command Line"
|
|
||||||
slug: "command-line"
|
|
||||||
sidebar_position: 1
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/command-line
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Command Line"
|
|
||||||
sidebar_position: 1
|
|
||||||
identifier: "command-line"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Command Line
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
`gitea [global options] command [command or global options] [arguments...]`
|
|
||||||
|
|
||||||
## Global options
|
|
||||||
|
|
||||||
All global options can be placed at the command level.
|
|
||||||
|
|
||||||
- `--help`, `-h`: Show help text and exit. Optional.
|
|
||||||
- `--version`, `-v`: Show version and exit. Optional. (example: `Gitea version 1.1.0+218-g7b907ed built with: bindata, sqlite`).
|
|
||||||
- `--work-path path`, `-w path`: Gitea's work path. Optional. (default: the binary's path or `$GITEA_WORK_DIR`)
|
|
||||||
- `--custom-path path`, `-C path`: Gitea's custom folder path. Optional. (default: `WorkPath`/custom or `$GITEA_CUSTOM`).
|
|
||||||
- `--config path`, `-c path`: Gitea configuration file path. Optional. (default: `CustomPath`/conf/app.ini).
|
|
||||||
|
|
||||||
NB: The defaults custom-path, config and work-path can also be
|
|
||||||
changed at build time (if preferred).
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
### web
|
|
||||||
|
|
||||||
Starts the server:
|
|
||||||
|
|
||||||
- Options:
|
|
||||||
- `--port number`, `-p number`: Port number. Optional. (default: 3000). Overrides configuration file.
|
|
||||||
- `--install-port number`: Port number to run the install page on. Optional. (default: 3000). Overrides configuration file.
|
|
||||||
- `--pid path`, `-P path`: Pidfile path. Optional.
|
|
||||||
- `--quiet`, `-q`: Only emit Fatal logs on the console for logs emitted before logging set up.
|
|
||||||
- `--verbose`: Emit tracing logs on the console for logs emitted before logging is set-up.
|
|
||||||
- Examples:
|
|
||||||
- `gitea web`
|
|
||||||
- `gitea web --port 80`
|
|
||||||
- `gitea web --config /etc/gitea.ini --pid /some/custom/gitea.pid`
|
|
||||||
- Notes:
|
|
||||||
- Gitea should not be run as root. To bind to a port below 1024, you can use setcap on
|
|
||||||
Linux: `sudo setcap 'cap_net_bind_service=+ep' /path/to/gitea`. This will need to be
|
|
||||||
redone every time you update Gitea.
|
|
||||||
|
|
||||||
### admin
|
|
||||||
|
|
||||||
Admin operations:
|
|
||||||
|
|
||||||
- Commands:
|
|
||||||
- `user`:
|
|
||||||
- `list`:
|
|
||||||
- Options:
|
|
||||||
- `--admin`: List only admin users. Optional.
|
|
||||||
- Description: lists all users that exist
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin user list`
|
|
||||||
- `delete`:
|
|
||||||
- Options:
|
|
||||||
- `--email`: Email of the user to be deleted.
|
|
||||||
- `--username`: Username of user to be deleted.
|
|
||||||
- `--id`: ID of user to be deleted.
|
|
||||||
- One of `--id`, `--username` or `--email` is required. If more than one is provided then all have to match.
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin user delete --id 1`
|
|
||||||
- `create`:
|
|
||||||
- Options:
|
|
||||||
- `--name value`: Username. Required. As of Gitea 1.9.0, use the `--username` flag instead.
|
|
||||||
- `--username value`: Username. Required. New in Gitea 1.9.0.
|
|
||||||
- `--password value`: Password. Required.
|
|
||||||
- `--email value`: Email. Required.
|
|
||||||
- `--admin`: If provided, this makes the user an admin. Optional.
|
|
||||||
- `--access-token`: If provided, an access token will be created for the user. Optional. (default: false).
|
|
||||||
- `--must-change-password`: If provided, the created user will be required to choose a newer password after the
|
|
||||||
initial login. Optional. (default: true).
|
|
||||||
- `--random-password`: If provided, a randomly generated password will be used as the password of the created
|
|
||||||
user. The value of `--password` will be discarded. Optional.
|
|
||||||
- `--random-password-length`: If provided, it will be used to configure the length of the randomly generated
|
|
||||||
password. Optional. (default: 12)
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin user create --username myname --password asecurepassword --email me@example.com`
|
|
||||||
- `change-password`:
|
|
||||||
- Options:
|
|
||||||
- `--username value`, `-u value`: Username. Required.
|
|
||||||
- `--password value`, `-p value`: New password. Required.
|
|
||||||
- `--must-change-password`: If provided, the user is required to choose a new password after the login. Optional.
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin user change-password --username myname --password asecurepassword`
|
|
||||||
- `must-change-password`:
|
|
||||||
- Args:
|
|
||||||
- `[username...]`: Users that must change their passwords
|
|
||||||
- Options:
|
|
||||||
- `--all`, `-A`: Force a password change for all users
|
|
||||||
- `--exclude username`, `-e username`: Exclude the given user. Can be set multiple times.
|
|
||||||
- `--unset`: Revoke forced password change for the given users
|
|
||||||
- `generate-access-token`:
|
|
||||||
- Options:
|
|
||||||
- `--username value`, `-u value`: Username. Required.
|
|
||||||
- `--token-name value`, `-t value`: Token name. Required.
|
|
||||||
- `--scopes value`: Comma-separated list of scopes. Scopes follow the format `[read|write]:<block>` or `all` where `<block>` is one of the available visual groups you can see when opening the API page showing the available routes (for example `repo`).
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin user generate-access-token --username myname --token-name mytoken`
|
|
||||||
- `gitea admin user generate-access-token --help`
|
|
||||||
- `regenerate`
|
|
||||||
- Options:
|
|
||||||
- `hooks`: Regenerate Git Hooks for all repositories
|
|
||||||
- `keys`: Regenerate authorized_keys file
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin regenerate hooks`
|
|
||||||
- `gitea admin regenerate keys`
|
|
||||||
- `auth`:
|
|
||||||
- `list`:
|
|
||||||
- Description: lists all external authentication sources that exist
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin auth list`
|
|
||||||
- `delete`:
|
|
||||||
- Options:
|
|
||||||
- `--id`: ID of source to be deleted. Required.
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin auth delete --id 1`
|
|
||||||
- `add-oauth`:
|
|
||||||
- Options:
|
|
||||||
- `--name`: Application Name.
|
|
||||||
- `--provider`: OAuth2 Provider.
|
|
||||||
- `--key`: Client ID (Key).
|
|
||||||
- `--secret`: Client Secret.
|
|
||||||
- `--auto-discover-url`: OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider).
|
|
||||||
- `--use-custom-urls`: Use custom URLs for GitLab/GitHub OAuth endpoints.
|
|
||||||
- `--custom-tenant-id`: Use custom Tenant ID for OAuth endpoints.
|
|
||||||
- `--custom-auth-url`: Use a custom Authorization URL (option for GitLab/GitHub).
|
|
||||||
- `--custom-token-url`: Use a custom Token URL (option for GitLab/GitHub).
|
|
||||||
- `--custom-profile-url`: Use a custom Profile URL (option for GitLab/GitHub).
|
|
||||||
- `--custom-email-url`: Use a custom Email URL (option for GitHub).
|
|
||||||
- `--icon-url`: Custom icon URL for OAuth2 login source.
|
|
||||||
- `--skip-local-2fa`: Allow source to override local 2FA. (Optional)
|
|
||||||
- `--scopes`: Additional scopes to request for this OAuth2 source. (Optional)
|
|
||||||
- `--required-claim-name`: Claim name that has to be set to allow users to login with this source. (Optional)
|
|
||||||
- `--required-claim-value`: Claim value that has to be set to allow users to login with this source. (Optional)
|
|
||||||
- `--group-claim-name`: Claim name providing group names for this source. (Optional)
|
|
||||||
- `--admin-group`: Group Claim value for administrator users. (Optional)
|
|
||||||
- `--restricted-group`: Group Claim value for restricted users. (Optional)
|
|
||||||
- `--group-team-map`: JSON mapping between groups and org teams. (Optional)
|
|
||||||
- `--group-team-map-removal`: Activate automatic team membership removal depending on groups. (Optional)
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin auth add-oauth --name external-github --provider github --key OBTAIN_FROM_SOURCE --secret OBTAIN_FROM_SOURCE`
|
|
||||||
- `update-oauth`:
|
|
||||||
- Options:
|
|
||||||
- `--id`: ID of source to be updated. Required.
|
|
||||||
- `--name`: Application Name.
|
|
||||||
- `--provider`: OAuth2 Provider.
|
|
||||||
- `--key`: Client ID (Key).
|
|
||||||
- `--secret`: Client Secret.
|
|
||||||
- `--auto-discover-url`: OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider).
|
|
||||||
- `--use-custom-urls`: Use custom URLs for GitLab/GitHub OAuth endpoints.
|
|
||||||
- `--custom-tenant-id`: Use custom Tenant ID for OAuth endpoints.
|
|
||||||
- `--custom-auth-url`: Use a custom Authorization URL (option for GitLab/GitHub).
|
|
||||||
- `--custom-token-url`: Use a custom Token URL (option for GitLab/GitHub).
|
|
||||||
- `--custom-profile-url`: Use a custom Profile URL (option for GitLab/GitHub).
|
|
||||||
- `--custom-email-url`: Use a custom Email URL (option for GitHub).
|
|
||||||
- `--icon-url`: Custom icon URL for OAuth2 login source.
|
|
||||||
- `--skip-local-2fa`: Allow source to override local 2FA. (Optional)
|
|
||||||
- `--scopes`: Additional scopes to request for this OAuth2 source.
|
|
||||||
- `--required-claim-name`: Claim name that has to be set to allow users to login with this source. (Optional)
|
|
||||||
- `--required-claim-value`: Claim value that has to be set to allow users to login with this source. (Optional)
|
|
||||||
- `--group-claim-name`: Claim name providing group names for this source. (Optional)
|
|
||||||
- `--admin-group`: Group Claim value for administrator users. (Optional)
|
|
||||||
- `--restricted-group`: Group Claim value for restricted users. (Optional)
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin auth update-oauth --id 1 --name external-github-updated`
|
|
||||||
- `add-smtp`:
|
|
||||||
- Options:
|
|
||||||
- `--name`: Application Name. Required.
|
|
||||||
- `--auth-type`: SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5). Default to PLAIN.
|
|
||||||
- `--host`: SMTP host. Required.
|
|
||||||
- `--port`: SMTP port. Required.
|
|
||||||
- `--force-smtps`: SMTPS is always used on port 465. Set this to force SMTPS on other ports.
|
|
||||||
- `--skip-verify`: Skip TLS verify.
|
|
||||||
- `--helo-hostname`: Hostname sent with HELO. Leave blank to send current hostname.
|
|
||||||
- `--disable-helo`: Disable SMTP helo.
|
|
||||||
- `--allowed-domains`: Leave empty to allow all domains. Separate multiple domains with a comma (',').
|
|
||||||
- `--skip-local-2fa`: Skip 2FA to log on.
|
|
||||||
- `--active`: This Authentication Source is Activated.
|
|
||||||
Remarks:
|
|
||||||
`--force-smtps`, `--skip-verify`, `--disable-helo`, `--skip-loca-2fs` and `--active` options can be used in form:
|
|
||||||
- `--option`, `--option=true` to enable
|
|
||||||
- `--option=false` to disable
|
|
||||||
If those options are not specified value would not be changed in `update-smtp` or would use default `false` value in `add-smtp`
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin auth add-smtp --name ldap --host smtp.mydomain.org --port 587 --skip-verify --active`
|
|
||||||
- `update-smtp`:
|
|
||||||
- Options:
|
|
||||||
- `--id`: ID of source to be updated. Required.
|
|
||||||
- other options are shared with `add-smtp`
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin auth update-smtp --id 1 --host smtp.mydomain.org --port 587 --skip-verify=false`
|
|
||||||
- `gitea admin auth update-smtp --id 1 --active=false`
|
|
||||||
- `add-ldap`: Add new LDAP (via Bind DN) authentication source
|
|
||||||
- Options:
|
|
||||||
- `--name value`: Authentication name. Required.
|
|
||||||
- `--not-active`: Deactivate the authentication source.
|
|
||||||
- `--security-protocol value`: Security protocol name. Required.
|
|
||||||
- `--skip-tls-verify`: Disable TLS verification.
|
|
||||||
- `--host value`: The address where the LDAP server can be reached. Required.
|
|
||||||
- `--port value`: The port to use when connecting to the LDAP server. Required.
|
|
||||||
- `--user-search-base value`: The LDAP base at which user accounts will be searched for. Required.
|
|
||||||
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate. Required.
|
|
||||||
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
|
||||||
- `--restricted-filter value`: An LDAP filter specifying if a user should be given restricted status.
|
|
||||||
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
|
||||||
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
|
||||||
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
|
||||||
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address. Required.
|
|
||||||
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
|
|
||||||
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
|
|
||||||
- `--bind-dn value`: The DN to bind to the LDAP server with when searching for the user.
|
|
||||||
- `--bind-password value`: The password for the Bind DN, if any.
|
|
||||||
- `--attributes-in-bind`: Fetch attributes in bind DN context.
|
|
||||||
- `--synchronize-users`: Enable user synchronization.
|
|
||||||
- `--page-size value`: Search page size.
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin auth add-ldap --name ldap --security-protocol unencrypted --host mydomain.org --port 389 --user-search-base "ou=Users,dc=mydomain,dc=org" --user-filter "(&(objectClass=posixAccount)(|(uid=%[1]s)(mail=%[1]s)))" --email-attribute mail`
|
|
||||||
- `update-ldap`: Update existing LDAP (via Bind DN) authentication source
|
|
||||||
- Options:
|
|
||||||
- `--id value`: ID of authentication source. Required.
|
|
||||||
- `--name value`: Authentication name.
|
|
||||||
- `--not-active`: Deactivate the authentication source.
|
|
||||||
- `--security-protocol value`: Security protocol name.
|
|
||||||
- `--skip-tls-verify`: Disable TLS verification.
|
|
||||||
- `--host value`: The address where the LDAP server can be reached.
|
|
||||||
- `--port value`: The port to use when connecting to the LDAP server.
|
|
||||||
- `--user-search-base value`: The LDAP base at which user accounts will be searched for.
|
|
||||||
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate.
|
|
||||||
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
|
||||||
- `--restricted-filter value`: An LDAP filter specifying if a user should be given restricted status.
|
|
||||||
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
|
||||||
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
|
||||||
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
|
||||||
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address.
|
|
||||||
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
|
|
||||||
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
|
|
||||||
- `--bind-dn value`: The DN to bind to the LDAP server with when searching for the user.
|
|
||||||
- `--bind-password value`: The password for the Bind DN, if any.
|
|
||||||
- `--attributes-in-bind`: Fetch attributes in bind DN context.
|
|
||||||
- `--synchronize-users`: Enable user synchronization.
|
|
||||||
- `--page-size value`: Search page size.
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin auth update-ldap --id 1 --name "my ldap auth source"`
|
|
||||||
- `gitea admin auth update-ldap --id 1 --username-attribute uid --firstname-attribute givenName --surname-attribute sn`
|
|
||||||
- `add-ldap-simple`: Add new LDAP (simple auth) authentication source
|
|
||||||
- Options:
|
|
||||||
- `--name value`: Authentication name. Required.
|
|
||||||
- `--not-active`: Deactivate the authentication source.
|
|
||||||
- `--security-protocol value`: Security protocol name. Required.
|
|
||||||
- `--skip-tls-verify`: Disable TLS verification.
|
|
||||||
- `--host value`: The address where the LDAP server can be reached. Required.
|
|
||||||
- `--port value`: The port to use when connecting to the LDAP server. Required.
|
|
||||||
- `--user-search-base value`: The LDAP base at which user accounts will be searched for.
|
|
||||||
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate. Required.
|
|
||||||
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
|
||||||
- `--restricted-filter value`: An LDAP filter specifying if a user should be given restricted status.
|
|
||||||
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
|
||||||
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
|
||||||
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
|
||||||
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address. Required.
|
|
||||||
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
|
|
||||||
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
|
|
||||||
- `--user-dn value`: The user’s DN. Required.
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin auth add-ldap-simple --name ldap --security-protocol unencrypted --host mydomain.org --port 389 --user-dn "cn=%s,ou=Users,dc=mydomain,dc=org" --user-filter "(&(objectClass=posixAccount)(cn=%s))" --email-attribute mail`
|
|
||||||
- `update-ldap-simple`: Update existing LDAP (simple auth) authentication source
|
|
||||||
- Options:
|
|
||||||
- `--id value`: ID of authentication source. Required.
|
|
||||||
- `--name value`: Authentication name.
|
|
||||||
- `--not-active`: Deactivate the authentication source.
|
|
||||||
- `--security-protocol value`: Security protocol name.
|
|
||||||
- `--skip-tls-verify`: Disable TLS verification.
|
|
||||||
- `--host value`: The address where the LDAP server can be reached.
|
|
||||||
- `--port value`: The port to use when connecting to the LDAP server.
|
|
||||||
- `--user-search-base value`: The LDAP base at which user accounts will be searched for.
|
|
||||||
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate.
|
|
||||||
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
|
||||||
- `--restricted-filter value`: An LDAP filter specifying if a user should be given restricted status.
|
|
||||||
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
|
||||||
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
|
||||||
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
|
||||||
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address.
|
|
||||||
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
|
|
||||||
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
|
|
||||||
- `--user-dn value`: The user’s DN.
|
|
||||||
- Examples:
|
|
||||||
- `gitea admin auth update-ldap-simple --id 1 --name "my ldap auth source"`
|
|
||||||
- `gitea admin auth update-ldap-simple --id 1 --username-attribute uid --firstname-attribute givenName --surname-attribute sn`
|
|
||||||
|
|
||||||
### cert
|
|
||||||
|
|
||||||
Generates a self-signed SSL certificate. Outputs to `cert.pem` and `key.pem` in the current
|
|
||||||
directory and will overwrite any existing files.
|
|
||||||
|
|
||||||
- Options:
|
|
||||||
- `--host value`: Comma separated hostnames and ips which this certificate is valid for.
|
|
||||||
Wildcards are supported. Required.
|
|
||||||
- `--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: 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.
|
|
||||||
- Examples:
|
|
||||||
- `gitea cert --host git.example.com,example.com,www.example.com --ca`
|
|
||||||
|
|
||||||
### dump
|
|
||||||
|
|
||||||
Dumps all files and databases into a zip file. Outputs into a file like `gitea-dump-1482906742.zip`
|
|
||||||
in the current directory.
|
|
||||||
|
|
||||||
- Options:
|
|
||||||
- `--file name`, `-f name`: Name of the dump file with will be created. Optional. (default: gitea-dump-[timestamp].zip).
|
|
||||||
- `--tempdir path`, `-t path`: Path to the temporary directory used. Optional. (default: /tmp).
|
|
||||||
- `--skip-repository`, `-R`: Skip the repository dumping. Optional.
|
|
||||||
- `--skip-custom-dir`: Skip dumping of the custom dir. Optional.
|
|
||||||
- `--skip-lfs-data`: Skip dumping of LFS data. Optional.
|
|
||||||
- `--skip-attachment-data`: Skip dumping of attachment data. Optional.
|
|
||||||
- `--skip-package-data`: Skip dumping of package data. Optional.
|
|
||||||
- `--skip-log`: Skip dumping of log data. Optional.
|
|
||||||
- `--database`, `-d`: Specify the database SQL syntax. Optional (supported arguments: sqlite3, mysql, mssql, postgres).
|
|
||||||
- `--verbose`, `-V`: If provided, shows additional details. Optional.
|
|
||||||
- `--type`: Set the dump output format. Optional. (formats: zip, tar, tar.sz, tar.gz, tar.xz, tar.bz2, tar.br, tar.lz4, tar.zst default: zip).
|
|
||||||
- Examples:
|
|
||||||
- `gitea dump`
|
|
||||||
- `gitea dump --verbose`
|
|
||||||
|
|
||||||
### generate
|
|
||||||
|
|
||||||
Generates random values and tokens for usage in configuration file. Useful for generating values
|
|
||||||
for automatic deployments.
|
|
||||||
|
|
||||||
- Commands:
|
|
||||||
- `secret`:
|
|
||||||
- Options:
|
|
||||||
- `INTERNAL_TOKEN`: Token used for an internal API call authentication.
|
|
||||||
- `JWT_SECRET`: LFS & OAUTH2 JWT authentication secret (LFS_JWT_SECRET is aliased to this option for backwards compatibility).
|
|
||||||
- `SECRET_KEY`: Global secret key.
|
|
||||||
- Examples:
|
|
||||||
- `gitea generate secret INTERNAL_TOKEN`
|
|
||||||
- `gitea generate secret JWT_SECRET`
|
|
||||||
- `gitea generate secret SECRET_KEY`
|
|
||||||
|
|
||||||
### keys
|
|
||||||
|
|
||||||
Provides an SSHD AuthorizedKeysCommand. Needs to be configured in the sshd config file:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
...
|
|
||||||
# The value of -e and the AuthorizedKeysCommandUser should match the
|
|
||||||
# username running Gitea
|
|
||||||
AuthorizedKeysCommandUser git
|
|
||||||
AuthorizedKeysCommand /path/to/gitea keys -e git -u %u -t %t -k %k
|
|
||||||
```
|
|
||||||
|
|
||||||
The command will return the appropriate authorized_keys line for the
|
|
||||||
provided key. You should also set the value
|
|
||||||
`SSH_CREATE_AUTHORIZED_KEYS_FILE=false` in the `[server]` section of
|
|
||||||
`app.ini`.
|
|
||||||
|
|
||||||
NB: opensshd requires the Gitea program to be owned by root and not
|
|
||||||
writable by group or others. The program must be specified by an absolute
|
|
||||||
path.
|
|
||||||
NB: Gitea must be running for this command to succeed.
|
|
||||||
|
|
||||||
### migrate
|
|
||||||
|
|
||||||
Migrates the database. This command can be used to run other commands before starting the server for the first time.
|
|
||||||
This command is idempotent.
|
|
||||||
|
|
||||||
### doctor check
|
|
||||||
|
|
||||||
Diagnose and potentially fix problems with the current Gitea instance.
|
|
||||||
Several checks are run by default, but additional ones can be run:
|
|
||||||
|
|
||||||
- `gitea doctor check --list` - will list all the available checks
|
|
||||||
- `gitea doctor check --all` - will run all available checks
|
|
||||||
- `gitea doctor check --default` - will run the default checks
|
|
||||||
- `gitea doctor check --run [check(s),]...` - will run the named checks
|
|
||||||
|
|
||||||
Some problems can be automatically fixed by passing the `--fix` option.
|
|
||||||
Extra logging can be set with `--log-file=...`.
|
|
||||||
|
|
||||||
#### doctor recreate-table
|
|
||||||
|
|
||||||
Sometimes when there are migrations the old columns and default values may be left
|
|
||||||
unchanged in the database schema. This may lead to warning such as:
|
|
||||||
|
|
||||||
```
|
|
||||||
2020/08/02 11:32:29 ...rm/session_schema.go:360:Sync() [W] Table user Column keep_activity_private db default is , struct default is 0
|
|
||||||
```
|
|
||||||
|
|
||||||
You can cause Gitea to recreate these tables and copy the old data into the new table
|
|
||||||
with the defaults set appropriately by using:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea doctor recreate-table user
|
|
||||||
```
|
|
||||||
|
|
||||||
You can ask Gitea to recreate multiple tables using:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea doctor recreate-table table1 table2 ...
|
|
||||||
```
|
|
||||||
|
|
||||||
And if you would like Gitea to recreate all tables simply call:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea doctor recreate-table
|
|
||||||
```
|
|
||||||
|
|
||||||
It is highly recommended to back-up your database before running these commands.
|
|
||||||
|
|
||||||
### doctor convert
|
|
||||||
|
|
||||||
Converts a MySQL database from utf8 to utf8mb4 or a MSSQL database from varchar to nvarchar.
|
|
||||||
|
|
||||||
### manager
|
|
||||||
|
|
||||||
Manage running server operations:
|
|
||||||
|
|
||||||
- Commands:
|
|
||||||
- `shutdown`: Gracefully shutdown the running process
|
|
||||||
- `restart`: Gracefully restart the running process - (not implemented for windows servers)
|
|
||||||
- `flush-queues`: Flush queues in the running process
|
|
||||||
- Options:
|
|
||||||
- `--timeout value`: Timeout for the flushing process (default: 1m0s)
|
|
||||||
- `--non-blocking`: Set to true to not wait for flush to complete before returning
|
|
||||||
- `logging`: Adjust logging commands
|
|
||||||
- Commands:
|
|
||||||
- `pause`: Pause logging
|
|
||||||
- Notes:
|
|
||||||
- The logging level will be raised to INFO temporarily if it is below this level.
|
|
||||||
- Gitea will buffer logs up to a certain point and will drop them after that point.
|
|
||||||
- `resume`: Resume logging
|
|
||||||
- `release-and-reopen`: Cause Gitea to release and re-open files and connections used for logging (Equivalent to sending SIGUSR1 to Gitea.)
|
|
||||||
- `remove name`: Remove the named logger
|
|
||||||
- Options:
|
|
||||||
- `--group group`, `-g group`: Set the group to remove the sublogger from. (defaults to `default`)
|
|
||||||
- `add`: Add a logger
|
|
||||||
- Commands:
|
|
||||||
- `console`: Add a console logger
|
|
||||||
- Options:
|
|
||||||
- `--group value`, `-g value`: Group to add logger to - will default to "default"
|
|
||||||
- `--name value`, `-n value`: Name of the new logger - will default to mode
|
|
||||||
- `--level value`, `-l value`: Logging level for the new logger
|
|
||||||
- `--stacktrace-level value`, `-L value`: Stacktrace logging level
|
|
||||||
- `--flags value`, `-F value`: Flags for the logger
|
|
||||||
- `--expression value`, `-e value`: Matching expression for the logger
|
|
||||||
- `--prefix value`, `-p value`: Prefix for the logger
|
|
||||||
- `--color`: Use color in the logs
|
|
||||||
- `--stderr`: Output console logs to stderr - only relevant for console
|
|
||||||
- `file`: Add a file logger
|
|
||||||
- Options:
|
|
||||||
- `--group value`, `-g value`: Group to add logger to - will default to "default"
|
|
||||||
- `--name value`, `-n value`: Name of the new logger - will default to mode
|
|
||||||
- `--level value`, `-l value`: Logging level for the new logger
|
|
||||||
- `--stacktrace-level value`, `-L value`: Stacktrace logging level
|
|
||||||
- `--flags value`, `-F value`: Flags for the logger
|
|
||||||
- `--expression value`, `-e value`: Matching expression for the logger
|
|
||||||
- `--prefix value`, `-p value`: Prefix for the logger
|
|
||||||
- `--color`: Use color in the logs
|
|
||||||
- `--filename value`, `-f value`: Filename for the logger -
|
|
||||||
- `--rotate`, `-r`: Rotate logs
|
|
||||||
- `--max-size value`, `-s value`: Maximum size in bytes before rotation
|
|
||||||
- `--daily`, `-d`: Rotate logs daily
|
|
||||||
- `--max-days value`, `-D value`: Maximum number of daily logs to keep
|
|
||||||
- `--compress`, `-z`: Compress rotated logs
|
|
||||||
- `--compression-level value`, `-Z value`: Compression level to use
|
|
||||||
- `conn`: Add a network connection logger
|
|
||||||
- Options:
|
|
||||||
- `--group value`, `-g value`: Group to add logger to - will default to "default"
|
|
||||||
- `--name value`, `-n value`: Name of the new logger - will default to mode
|
|
||||||
- `--level value`, `-l value`: Logging level for the new logger
|
|
||||||
- `--stacktrace-level value`, `-L value`: Stacktrace logging level
|
|
||||||
- `--flags value`, `-F value`: Flags for the logger
|
|
||||||
- `--expression value`, `-e value`: Matching expression for the logger
|
|
||||||
- `--prefix value`, `-p value`: Prefix for the logger
|
|
||||||
- `--color`: Use color in the logs
|
|
||||||
- `--reconnect-on-message`, `-R`: Reconnect to host for every message
|
|
||||||
- `--reconnect`, `-r`: Reconnect to host when connection is dropped
|
|
||||||
- `--protocol value`, `-P value`: Set protocol to use: tcp, unix, or udp (defaults to tcp)
|
|
||||||
- `--address value`, `-a value`: Host address and port to connect to (defaults to :7020)
|
|
||||||
- `smtp`: Add an SMTP logger
|
|
||||||
- Options:
|
|
||||||
- `--group value`, `-g value`: Group to add logger to - will default to "default"
|
|
||||||
- `--name value`, `-n value`: Name of the new logger - will default to mode
|
|
||||||
- `--level value`, `-l value`: Logging level for the new logger
|
|
||||||
- `--stacktrace-level value`, `-L value`: Stacktrace logging level
|
|
||||||
- `--flags value`, `-F value`: Flags for the logger
|
|
||||||
- `--expression value`, `-e value`: Matching expression for the logger
|
|
||||||
- `--prefix value`, `-p value`: Prefix for the logger
|
|
||||||
- `--color`: Use color in the logs
|
|
||||||
- `--username value`, `-u value`: Mail server username
|
|
||||||
- `--password value`, `-P value`: Mail server password
|
|
||||||
- `--host value`, `-H value`: Mail server host (defaults to: 127.0.0.1:25)
|
|
||||||
- `--send-to value`, `-s value`: Email address(es) to send to
|
|
||||||
- `--subject value`, `-S value`: Subject header of sent emails
|
|
||||||
- `processes`: Display Gitea processes and goroutine information
|
|
||||||
- Options:
|
|
||||||
- `--flat`: Show processes as flat table rather than as tree
|
|
||||||
- `--no-system`: Do not show system processes
|
|
||||||
- `--stacktraces`: Show stacktraces for goroutines associated with processes
|
|
||||||
- `--json`: Output as json
|
|
||||||
- `--cancel PID`: Send cancel to process with PID. (Only for non-system processes.)
|
|
||||||
|
|
||||||
### dump-repo
|
|
||||||
|
|
||||||
Dump-repo dumps repository data from Git/GitHub/Gitea/GitLab:
|
|
||||||
|
|
||||||
- Options:
|
|
||||||
- `--git_service service` : Git service, it could be `git`, `github`, `gitea`, `gitlab`, If clone_addr could be recognized, this could be ignored.
|
|
||||||
- `--repo_dir dir`, `-r dir`: Repository dir path to store the data
|
|
||||||
- `--clone_addr addr`: The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL. i.e. https://github.com/lunny/tango.git
|
|
||||||
- `--auth_username lunny`: The username to visit the clone_addr
|
|
||||||
- `--auth_password <password>`: The password to visit the clone_addr
|
|
||||||
- `--auth_token <token>`: The personal token to visit the clone_addr
|
|
||||||
- `--owner_name lunny`: The data will be stored on a directory with owner name if not empty
|
|
||||||
- `--repo_name tango`: The data will be stored on a directory with repository name if not empty
|
|
||||||
- `--units <units>`: Which items will be migrated, one or more units should be separated as comma. wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.
|
|
||||||
|
|
||||||
### restore-repo
|
|
||||||
|
|
||||||
Restore-repo restore repository data from disk dir:
|
|
||||||
|
|
||||||
- Options:
|
|
||||||
- `--repo_dir dir`, `-r dir`: Repository dir path to restore from
|
|
||||||
- `--owner_name lunny`: Restore destination owner name
|
|
||||||
- `--repo_name tango`: Restore destination repository name
|
|
||||||
- `--units <units>`: Which items will be restored, one or more units should be separated as comma. wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.
|
|
||||||
|
|
||||||
### actions generate-runner-token
|
|
||||||
|
|
||||||
Generate a new token for a runner to use to register with the server
|
|
||||||
|
|
||||||
- Options:
|
|
||||||
- `--scope {owner}[/{repo}]`, `-s {owner}[/{repo}]`: To limit the scope of the runner, no scope means the runner can be used for all repos, but you can also limit it to a specific repo or owner
|
|
||||||
|
|
||||||
To register a global runner:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea actions generate-runner-token
|
|
||||||
```
|
|
||||||
|
|
||||||
To register a runner for a specific organization, in this case `org`:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea actions generate-runner-token -s org
|
|
||||||
```
|
|
||||||
|
|
||||||
To register a runner for a specific repo, in this case `username/test-repo`:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea actions generate-runner-token -s username/test-repo
|
|
||||||
```
|
|
|
@ -1,542 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "Gitea 命令行"
|
|
||||||
slug: "command-line"
|
|
||||||
sidebar_position: 1
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/command-line
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Gitea 命令行"
|
|
||||||
sidebar_position: 1
|
|
||||||
identifier: "command-line"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 命令行
|
|
||||||
|
|
||||||
## 用法
|
|
||||||
|
|
||||||
`gitea [全局选项] 命令 [命令或全局选项] [参数...]`
|
|
||||||
|
|
||||||
## 全局选项
|
|
||||||
|
|
||||||
所有全局选项均可被放置在命令级别。
|
|
||||||
|
|
||||||
- `--help`,`-h`:显示帮助文本并退出。可选。
|
|
||||||
- `--version`,`-v`:显示版本信息并退出。可选。 (示例:`Gitea version 1.1.0+218-g7b907ed built with: bindata, sqlite`)。
|
|
||||||
- `--custom-path path`,`-C path`:Gitea 自定义文件夹的路径。可选。 (默认值:`AppWorkPath`/custom 或 `$GITEA_CUSTOM`)。
|
|
||||||
- `--config path`,`-c path`:Gitea 配置文件的路径。可选。 (默认值:`custom`/conf/app.ini)。
|
|
||||||
- `--work-path path`,`-w path`:Gitea 的 `AppWorkPath`。可选。 (默认值:LOCATION_OF_GITEA_BINARY 或 `$GITEA_WORK_DIR`)
|
|
||||||
|
|
||||||
注意:默认的 custom-path、config 和 work-path 也可以在构建时更改(如果需要)。
|
|
||||||
|
|
||||||
## 命令
|
|
||||||
|
|
||||||
### web
|
|
||||||
|
|
||||||
启动服务器:
|
|
||||||
|
|
||||||
- 选项:
|
|
||||||
- `--port number`,`-p number`:端口号。可选。 (默认值:3000)。覆盖配置文件中的设置。
|
|
||||||
- `--install-port number`:运行安装页面的端口号。可选。 (默认值:3000)。覆盖配置文件中的设置。
|
|
||||||
- `--pid path`,`-P path`:Pid 文件的路径。可选。
|
|
||||||
- `--quiet`,`-q`:只在控制台上输出 Fatal 日志,用于在设置日志之前发出的日志。
|
|
||||||
- `--verbose`:在控制台上输出跟踪日志,用于在设置日志之前发出的日志。
|
|
||||||
- 示例:
|
|
||||||
- `gitea web`
|
|
||||||
- `gitea web --port 80`
|
|
||||||
- `gitea web --config /etc/gitea.ini --pid /some/custom/gitea.pid`
|
|
||||||
- 注意:
|
|
||||||
- Gitea 不应以 root 用户身份运行。要绑定到低于 1024 的端口,您可以在 Linux 上使用 setcap 命令:`sudo setcap 'cap_net_bind_service=+ep' /path/to/gitea`。每次更新 Gitea 都需要重新执行此操作。
|
|
||||||
|
|
||||||
### admin
|
|
||||||
|
|
||||||
管理员操作:
|
|
||||||
|
|
||||||
- 命令:
|
|
||||||
- `user`:
|
|
||||||
- `list`:
|
|
||||||
- 选项:
|
|
||||||
- `--admin`:仅列出管理员用户。可选。
|
|
||||||
- 描述:列出所有现有用户。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin user list`
|
|
||||||
- `delete`:
|
|
||||||
- 选项:
|
|
||||||
- `--email`:要删除的用户的电子邮件。
|
|
||||||
- `--username`:要删除的用户的用户名。
|
|
||||||
- `--id`:要删除的用户的ID。
|
|
||||||
- 必须提供 `--id`、`--username` 或 `--email` 中的一个。如果提供多个,则所有条件必须匹配。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin user delete --id 1`
|
|
||||||
- `create`:
|
|
||||||
- 选项:
|
|
||||||
- `--name value`:用户名。必填。自 Gitea 1.9.0 版本起,请改用 `--username` 标志。
|
|
||||||
- `--username value`:用户名。必填。Gitea 1.9.0 新增。
|
|
||||||
- `--password value`:密码。必填。
|
|
||||||
- `--email value`:邮箱。必填。
|
|
||||||
- `--admin`:如果提供此选项,将创建一个管理员用户。可选。
|
|
||||||
- `--access-token`:如果提供,将为用户创建访问令牌。可选。(默认值:false)。
|
|
||||||
- `--must-change-password`:如果提供,创建的用户将在初始登录后需要选择一个新密码。可选。(默认值:true)。
|
|
||||||
- `--random-password`:如果提供,将使用随机生成的密码作为创建用户的密码。`--password` 的值将被忽略。可选。
|
|
||||||
- `--random-password-length`:如果提供,将用于配置随机生成密码的长度。可选。(默认值:12)
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin user create --username myname --password asecurepassword --email me@example.com`
|
|
||||||
- `change-password`:
|
|
||||||
- 选项:
|
|
||||||
- `--username value`,`-u value`:用户名。必填。
|
|
||||||
- `--password value`,`-p value`:新密码。必填。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin user change-password --username myname --password asecurepassword`
|
|
||||||
- `must-change-password`:
|
|
||||||
- 参数:
|
|
||||||
- `[username...]`:需要更改密码的用户
|
|
||||||
- 选项:
|
|
||||||
- `--all`,`-A`:强制所有用户更改密码
|
|
||||||
- `--exclude username`,`-e username`:排除给定的用户。可以多次设置。
|
|
||||||
- `--unset`:撤销对给定用户的强制密码更改
|
|
||||||
- `regenerate`:
|
|
||||||
- 选项:
|
|
||||||
- `hooks`:重新生成所有仓库的 Git Hooks。
|
|
||||||
- `keys`:重新生成 authorized_keys 文件。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin regenerate hooks`
|
|
||||||
- `gitea admin regenerate keys`
|
|
||||||
- `auth`:
|
|
||||||
- `list`:
|
|
||||||
- 描述:列出所有存在的外部认证源。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin auth list`
|
|
||||||
- `delete`:
|
|
||||||
- 选项:
|
|
||||||
- `--id`:要删除的源的 ID。必填。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin auth delete --id 1`
|
|
||||||
- `add-oauth`:
|
|
||||||
- 选项:
|
|
||||||
- `--name`:应用程序名称。
|
|
||||||
- `--provider`:OAuth2 提供者。
|
|
||||||
- `--key`:客户端 ID(Key)。
|
|
||||||
- `--secret`:客户端密钥。
|
|
||||||
- `--auto-discover-url`:OpenID Connect 自动发现 URL(仅在使用 OpenID Connect 作为提供程序时需要)。
|
|
||||||
- `--use-custom-urls`:在 GitLab/GitHub OAuth 端点上使用自定义 URL。
|
|
||||||
- `--custom-tenant-id`:在 OAuth 端点上使用自定义租户 ID。
|
|
||||||
- `--custom-auth-url`:使用自定义授权 URL(GitLab/GitHub 的选项)。
|
|
||||||
- `--custom-token-url`:使用自定义令牌 URL(GitLab/GitHub 的选项)。
|
|
||||||
- `--custom-profile-url`:使用自定义配置文件 URL(GitLab/GitHub 的选项)。
|
|
||||||
- `--custom-email-url`:使用自定义电子邮件 URL(GitHub 的选项)。
|
|
||||||
- `--icon-url`:OAuth2 登录源的自定义图标 URL。
|
|
||||||
- `--skip-local-2fa`:允许源覆盖本地 2FA。(可选)
|
|
||||||
- `--scopes`:请求此 OAuth2 源的附加范围。(可选)
|
|
||||||
- `--required-claim-name`:必须设置的声明名称,以允许用户使用此源登录。(可选)
|
|
||||||
- `--required-claim-value`:必须设置的声明值,以允许用户使用此源登录。(可选)
|
|
||||||
- `--group-claim-name`:提供此源的组名的声明名称。(可选)
|
|
||||||
- `--admin-group`:管理员用户的组声明值。(可选)
|
|
||||||
- `--restricted-group`:受限用户的组声明值。(可选)
|
|
||||||
- `--group-team-map`:组与组织团队之间的 JSON 映射。(可选)
|
|
||||||
- `--group-team-map-removal`:根据组自动激活团队成员资格的删除。(可选)
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin auth add-oauth --name external-github --provider github --key OBTAIN_FROM_SOURCE --secret OBTAIN_FROM_SOURCE`
|
|
||||||
- `update-oauth`:
|
|
||||||
- 选项:
|
|
||||||
- `--id`:要更新的源的 ID。必填。
|
|
||||||
- `--name`:应用程序名称。
|
|
||||||
- `--provider`:OAuth2 提供者。
|
|
||||||
- `--key`:客户端 ID(Key)。
|
|
||||||
- `--secret`:客户端密钥。
|
|
||||||
- `--auto-discover-url`:OpenID Connect 自动发现 URL(仅在使用 OpenID Connect 作为提供程序时需要)。
|
|
||||||
- `--use-custom-urls`:在 GitLab/GitHub OAuth 端点上使用自定义 URL。
|
|
||||||
- `--custom-tenant-id`:在 OAuth 端点上使用自定义租户 ID。
|
|
||||||
- `--custom-auth-url`:使用自定义授权 URL(GitLab/GitHub 的选项)。
|
|
||||||
- `--custom-token-url`:使用自定义令牌 URL(GitLab/GitHub 的选项)。
|
|
||||||
- `--custom-profile-url`:使用自定义配置文件 URL(GitLab/GitHub 的选项)。
|
|
||||||
- `--custom-email-url`:使用自定义电子邮件 URL(GitHub 的选项)。
|
|
||||||
- `--icon-url`:OAuth2 登录源的自定义图标 URL。
|
|
||||||
- `--skip-local-2fa`:允许源覆盖本地 2FA。(可选)
|
|
||||||
- `--scopes`:请求此 OAuth2 源的附加范围。
|
|
||||||
- `--required-claim-name`:必须设置的声明名称,以允许用户使用此源登录。(可选)
|
|
||||||
- `--required-claim-value`:必须设置的声明值,以允许用户使用此源登录。(可选)
|
|
||||||
- `--group-claim-name`:提供此源的组名的声明名称。(可选)
|
|
||||||
- `--admin-group`:管理员用户的组声明值。(可选)
|
|
||||||
- `--restricted-group`:受限用户的组声明值。(可选)
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin auth update-oauth --id 1 --name external-github-updated`
|
|
||||||
- `add-smtp`:
|
|
||||||
- 选项:
|
|
||||||
- `--name`:应用程序名称。必填。
|
|
||||||
- `--auth-type`:SMTP 认证类型(PLAIN/LOGIN/CRAM-MD5)。默认为 PLAIN。
|
|
||||||
- `--host`:SMTP 主机。必填。
|
|
||||||
- `--port`:SMTP 端口。必填。
|
|
||||||
- `--force-smtps`:SMTPS 始终在端口 465 上使用。设置此选项以强制在其他端口上使用 SMTPS。
|
|
||||||
- `--skip-verify`:跳过 TLS 验证。
|
|
||||||
- `--helo-hostname`:发送 HELO 时使用的主机名。留空以发送当前主机名。
|
|
||||||
- `--disable-helo`:禁用 SMTP helo。
|
|
||||||
- `--allowed-domains`:留空以允许所有域。使用逗号(',')分隔多个域。
|
|
||||||
- `--skip-local-2fa`:跳过 2FA 登录。
|
|
||||||
- `--active`:启用此认证源。
|
|
||||||
备注:
|
|
||||||
`--force-smtps`、`--skip-verify`、`--disable-helo`、`--skip-local-2fs` 和 `--active` 选项可以采用以下形式使用:
|
|
||||||
- `--option`、`--option=true` 以启用选项
|
|
||||||
- `--option=false` 以禁用选项
|
|
||||||
如果未指定这些选项,则在 `update-smtp` 中不会更改值,或者在 `add-smtp` 中将使用默认的 `false` 值。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin auth add-smtp --name ldap --host smtp.mydomain.org --port 587 --skip-verify --active`
|
|
||||||
- `update-smtp`:
|
|
||||||
- 选项:
|
|
||||||
- `--id`:要更新的源的 ID。必填。
|
|
||||||
- 其他选项与 `add-smtp` 共享
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin auth update-smtp --id 1 --host smtp.mydomain.org --port 587 --skip-verify=false`
|
|
||||||
- `gitea admin auth update-smtp --id 1 --active=false`
|
|
||||||
- `add-ldap`:添加新的 LDAP(通过 Bind DN)认证源
|
|
||||||
- 选项:
|
|
||||||
- `--name value`:认证名称。必填。
|
|
||||||
- `--not-active`:停用认证源。
|
|
||||||
- `--security-protocol value`:安全协议名称。必填。
|
|
||||||
- `--skip-tls-verify`:禁用 TLS 验证。
|
|
||||||
- `--host value`:LDAP 服务器的地址。必填。
|
|
||||||
- `--port value`:连接到 LDAP 服务器时使用的端口。必填。
|
|
||||||
- `--user-search-base value`:用户帐户将在其中搜索的 LDAP 基础路径。必填。
|
|
||||||
- `--user-filter value`:声明如何查找试图进行身份验证的用户记录的 LDAP 过滤器。必填。
|
|
||||||
- `--admin-filter value`:指定是否应授予用户管理员特权的 LDAP 过滤器。
|
|
||||||
- `--restricted-filter value`:指定是否应将用户设置为受限状态的 LDAP 过滤器。
|
|
||||||
- `--username-attribute value`:用户 LDAP 记录中包含用户名的属性。
|
|
||||||
- `--firstname-attribute value`:用户 LDAP 记录中包含用户名字的属性。
|
|
||||||
- `--surname-attribute value`:用户 LDAP 记录中包含用户姓氏的属性。
|
|
||||||
- `--email-attribute value`:用户 LDAP 记录中包含用户电子邮件地址的属性。必填。
|
|
||||||
- `--public-ssh-key-attribute value`:用户 LDAP 记录中包含用户公共 SSH 密钥的属性。
|
|
||||||
- `--avatar-attribute value`:用户 LDAP 记录中包含用户头像的属性。
|
|
||||||
- `--bind-dn value`:在搜索用户时绑定到 LDAP 服务器的 DN。
|
|
||||||
- `--bind-password value`:绑定 DN 的密码(如果有)。
|
|
||||||
- `--attributes-in-bind`:在绑定 DN 上下文中获取属性。
|
|
||||||
- `--synchronize-users`:启用用户同步。
|
|
||||||
- `--page-size value`:搜索页面大小。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin auth add-ldap --name ldap --security-protocol unencrypted --host mydomain.org --port 389 --user-search-base "ou=Users,dc=mydomain,dc=org" --user-filter "(&(objectClass=posixAccount)(|(uid=%[1]s)(mail=%[1]s)))" --email-attribute mail`
|
|
||||||
- `update-ldap`:更新现有的 LDAP(通过 Bind DN)认证源
|
|
||||||
- 选项:
|
|
||||||
- `--id value`:认证源的 ID。必填。
|
|
||||||
- `--name value`:认证名称。
|
|
||||||
- `--not-active`:停用认证源。
|
|
||||||
- `--security-protocol value`:安全协议名称。
|
|
||||||
- `--skip-tls-verify`:禁用 TLS 验证。
|
|
||||||
- `--host value`:LDAP 服务器的地址。
|
|
||||||
- `--port value`:连接到 LDAP 服务器时使用的端口。
|
|
||||||
- `--user-search-base value`:用户帐户将在其中搜索的 LDAP 基础路径。
|
|
||||||
- `--user-filter value`:声明如何查找试图进行身份验证的用户记录的 LDAP 过滤器。
|
|
||||||
- `--admin-filter value`:指定是否应授予用户管理员特权的 LDAP 过滤器。
|
|
||||||
- `--restricted-filter value`:指定是否应将用户设置为受限状态的 LDAP 过滤器。
|
|
||||||
- `--username-attribute value`:用户 LDAP 记录中包含用户名的属性。
|
|
||||||
- `--firstname-attribute value`:用户 LDAP 记录中包含用户名字的属性。
|
|
||||||
- `--surname-attribute value`:用户 LDAP 记录中包含用户姓氏的属性。
|
|
||||||
- `--email-attribute value`:用户 LDAP 记录中包含用户电子邮件地址的属性。
|
|
||||||
- `--public-ssh-key-attribute value`:用户 LDAP 记录中包含用户公共 SSH 密钥的属性。
|
|
||||||
- `--avatar-attribute value`:用户 LDAP 记录中包含用户头像的属性。
|
|
||||||
- `--bind-dn value`:在搜索用户时绑定到 LDAP 服务器的 DN。
|
|
||||||
- `--bind-password value`:绑定 DN 的密码(如果有)。
|
|
||||||
- `--attributes-in-bind`:在绑定 DN 上下文中获取属性。
|
|
||||||
- `--synchronize-users`:启用用户同步。
|
|
||||||
- `--page-size value`:搜索页面大小。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin auth update-ldap --id 1 --name "my ldap auth source"`
|
|
||||||
- `gitea admin auth update-ldap --id 1 --username-attribute uid --firstname-attribute givenName --surname-attribute sn`
|
|
||||||
- `add-ldap-simple`:添加新的 LDAP(简单身份验证)认证源
|
|
||||||
- 选项:
|
|
||||||
- `--name value`:认证名称。必填。
|
|
||||||
- `--not-active`:停用认证源。
|
|
||||||
- `--security-protocol value`:安全协议名称。必填。
|
|
||||||
- `--skip-tls-verify`:禁用 TLS 验证。
|
|
||||||
- `--host value`:LDAP 服务器的地址。必填。
|
|
||||||
- `--port value`:连接到 LDAP 服务器时使用的端口。必填。
|
|
||||||
- `--user-search-base value`:用户帐户将在其中搜索的 LDAP 基础路径。
|
|
||||||
- `--user-filter value`:声明如何查找试图进行身份验证的用户记录的 LDAP 过滤器。必填。
|
|
||||||
- `--admin-filter value`:指定是否应授予用户管理员特权的 LDAP 过滤器。
|
|
||||||
- `--restricted-filter value`:指定是否应将用户设置为受限状态的 LDAP 过滤器。
|
|
||||||
- `--username-attribute value`:用户 LDAP 记录中包含用户名的属性。
|
|
||||||
- `--firstname-attribute value`:用户 LDAP 记录中包含用户名字的属性。
|
|
||||||
- `--surname-attribute value`:用户 LDAP 记录中包含用户姓氏的属性。
|
|
||||||
- `--email-attribute value`:用户 LDAP 记录中包含用户电子邮件地址的属性。必填。
|
|
||||||
- `--public-ssh-key-attribute value`:用户 LDAP 记录中包含用户公共 SSH 密钥的属性。
|
|
||||||
- `--avatar-attribute value`:用户 LDAP 记录中包含用户头像的属性。
|
|
||||||
- `--user-dn value`:用户的 DN。必填。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin auth add-ldap-simple --name ldap --security-protocol unencrypted --host mydomain.org --port 389 --user-dn "cn=%s,ou=Users,dc=mydomain,dc=org" --user-filter "(&(objectClass=posixAccount)(cn=%s))" --email-attribute mail`
|
|
||||||
- `update-ldap-simple`:更新现有的 LDAP(简单身份验证)认证源
|
|
||||||
- 选项:
|
|
||||||
- `--id value`:认证源的 ID。必填。
|
|
||||||
- `--name value`:认证名称。
|
|
||||||
- `--not-active`:停用认证源。
|
|
||||||
- `--security-protocol value`:安全协议名称。
|
|
||||||
- `--skip-tls-verify`:禁用 TLS 验证。
|
|
||||||
- `--host value`:LDAP 服务器的地址。
|
|
||||||
- `--port value`:连接到 LDAP 服务器时使用的端口。
|
|
||||||
- `--user-search-base value`:用户帐户将在其中搜索的 LDAP 基础路径。
|
|
||||||
- `--user-filter value`:声明如何查找试图进行身份验证的用户记录的 LDAP 过滤器。
|
|
||||||
- `--admin-filter value`:指定是否应授予用户管理员特权的 LDAP 过滤器。
|
|
||||||
- `--restricted-filter value`:指定是否应将用户设置为受限状态的 LDAP 过滤器。
|
|
||||||
- `--username-attribute value`:用户 LDAP 记录中包含用户名的属性。
|
|
||||||
- `--firstname-attribute value`:用户 LDAP 记录中包含用户名字的属性。
|
|
||||||
- `--surname-attribute value`:用户 LDAP 记录中包含用户姓氏的属性。
|
|
||||||
- `--email-attribute value`:用户 LDAP 记录中包含用户电子邮件地址的属性。
|
|
||||||
- `--public-ssh-key-attribute value`:用户 LDAP 记录中包含用户公共 SSH 密钥的属性。
|
|
||||||
- `--avatar-attribute value`:用户 LDAP 记录中包含用户头像的属性。
|
|
||||||
- `--user-dn value`:用户的 DN。
|
|
||||||
- 示例:
|
|
||||||
- `gitea admin auth update-ldap-simple --id 1 --name "my ldap auth source"`
|
|
||||||
- `gitea admin auth update-ldap-simple --id 1 --username-attribute uid --firstname-attribute givenName --surname-attribute sn`
|
|
||||||
|
|
||||||
### cert
|
|
||||||
|
|
||||||
生成自签名的SSL证书。将输出到当前目录下的`cert.pem`和`key.pem`文件中,并且会覆盖任何现有文件。
|
|
||||||
|
|
||||||
- 选项:
|
|
||||||
- `--host value`:逗号分隔的主机名和IP地址列表,此证书适用于这些主机。支持使用通配符。必填。
|
|
||||||
- `--ecdsa-curve value`:用于生成密钥的ECDSA曲线。可选。有效选项为P224、P256、P384、P521。
|
|
||||||
- `--rsa-bits value`:要生成的RSA密钥的大小。可选。如果设置了--ecdsa-curve,则忽略此选项。(默认值:3072)。
|
|
||||||
- `--start-date value`:证书的创建日期。可选。(格式:`Jan 1 15:04:05 2011`)。
|
|
||||||
- `--duration value`:证书有效期。可选。(默认值:8760h0m0s)
|
|
||||||
- `--ca`:如果提供此选项,则证书将生成自己的证书颁发机构。可选。
|
|
||||||
- 示例:
|
|
||||||
- `gitea cert --host git.example.com,example.com,www.example.com --ca`
|
|
||||||
|
|
||||||
### dump
|
|
||||||
|
|
||||||
将所有文件和数据库导出到一个zip文件中。输出文件将保存在当前目录下,类似于`gitea-dump-1482906742.zip`。
|
|
||||||
|
|
||||||
- 选项:
|
|
||||||
- `--file name`,`-f name`:指定要创建的导出文件的名称。可选。(默认值:gitea-dump-[timestamp].zip)。
|
|
||||||
- `--tempdir path`,`-t path`:指定临时目录的路径。可选。(默认值:/tmp)。
|
|
||||||
- `--skip-repository`,`-R`:跳过仓库的导出。可选。
|
|
||||||
- `--skip-custom-dir`:跳过自定义目录的导出。可选。
|
|
||||||
- `--skip-lfs-data`:跳过LFS数据的导出。可选。
|
|
||||||
- `--skip-attachment-data`:跳过附件数据的导出。可选。
|
|
||||||
- `--skip-package-data`:跳过包数据的导出。可选。
|
|
||||||
- `--skip-log`:跳过日志数据的导出。可选。
|
|
||||||
- `--database`,`-d`:指定数据库的SQL语法。可选。
|
|
||||||
- `--verbose`,`-V`:如果提供此选项,显示附加详细信息。可选。
|
|
||||||
- `--type`:设置导出的格式。可选。(默认值:zip)
|
|
||||||
- 示例:
|
|
||||||
- `gitea dump`
|
|
||||||
- `gitea dump --verbose`
|
|
||||||
|
|
||||||
### generate
|
|
||||||
|
|
||||||
用于在配置文件中生成随机值和令牌。对于自动部署时生成值非常有用。
|
|
||||||
|
|
||||||
- 命令:
|
|
||||||
- `secret`:
|
|
||||||
- 选项:
|
|
||||||
- `INTERNAL_TOKEN`: 用于内部 API 调用身份验证的令牌。
|
|
||||||
- `JWT_SECRET`: 用于 LFS 和 OAUTH2 JWT 身份验证的密钥(LFS_JWT_SECRET 是此选项的别名,用于向后兼容)。
|
|
||||||
- `SECRET_KEY`: 全局密钥。
|
|
||||||
- 示例:
|
|
||||||
- `gitea generate secret INTERNAL_TOKEN`
|
|
||||||
- `gitea generate secret JWT_SECRET`
|
|
||||||
- `gitea generate secret SECRET_KEY`
|
|
||||||
|
|
||||||
### keys
|
|
||||||
|
|
||||||
提供一个 SSHD AuthorizedKeysCommand。需要在 sshd 配置文件中进行配置:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
...
|
|
||||||
# -e 的值和 AuthorizedKeysCommandUser 应与运行 Gitea 的用户名匹配
|
|
||||||
AuthorizedKeysCommandUser git
|
|
||||||
AuthorizedKeysCommand /path/to/gitea keys -e git -u %u -t %t -k %k
|
|
||||||
```
|
|
||||||
|
|
||||||
该命令将返回适用于提供的密钥的合适 authorized_keys 行。您还应在 `app.ini` 的 `[server]` 部分设置值 `SSH_CREATE_AUTHORIZED_KEYS_FILE=false`。
|
|
||||||
|
|
||||||
注意: opensshd 要求 Gitea 程序由 root 拥有,并且不可由组或其他人写入。程序必须使用绝对路径指定。
|
|
||||||
注意: Gitea 必须在运行此命令时处于运行状态才能成功。
|
|
||||||
|
|
||||||
### migrate
|
|
||||||
|
|
||||||
迁移数据库。该命令可用于在首次启动服务器之前运行其他命令。此命令是幂等的。
|
|
||||||
|
|
||||||
### doctor check
|
|
||||||
|
|
||||||
对 Gitea 实例进行诊断,可以修复一些可修复的问题。
|
|
||||||
默认只运行部分检查,额外的检查可以参考:
|
|
||||||
|
|
||||||
- `gitea doctor check --list` - 列出所有可用的检查
|
|
||||||
- `gitea doctor check --all` - 运行所有可用的检查
|
|
||||||
- `gitea doctor check --default` - 运行默认的检查
|
|
||||||
- `gitea doctor check --run [check(s),]...` - 运行指定的名字的检查
|
|
||||||
|
|
||||||
有些问题可以通过设置 `--fix` 选项进行自动修复。
|
|
||||||
额外的日志可以通过 `--log-file=...` 进行设置。
|
|
||||||
|
|
||||||
#### doctor recreate-table
|
|
||||||
|
|
||||||
有时,在迁移时,旧的列和默认值可能会在数据库模式中保持不变。这可能会导致警告,如下所示:
|
|
||||||
|
|
||||||
```
|
|
||||||
2020/08/02 11:32:29 ...rm/session_schema.go:360:Sync() [W] Table user Column keep_activity_private db default is , struct default is 0
|
|
||||||
```
|
|
||||||
|
|
||||||
您可以通过以下方式让 Gitea 重新创建这些表,并将旧数据复制到新表中,并适当设置默认值:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea doctor recreate-table user
|
|
||||||
```
|
|
||||||
|
|
||||||
您可以使用以下方式让 Gitea 重新创建多个表:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea doctor recreate-table table1 table2 ...
|
|
||||||
```
|
|
||||||
|
|
||||||
如果您希望 Gitea 重新创建所有表,请直接调用:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea doctor recreate-table
|
|
||||||
```
|
|
||||||
|
|
||||||
强烈建议在运行这些命令之前备份您的数据库。
|
|
||||||
|
|
||||||
### doctor convert
|
|
||||||
|
|
||||||
将现有的 MySQL 数据库从 utf8 转换为 utf8mb4,或者把 MSSQL 数据库从 varchar 转换为 nvarchar。
|
|
||||||
|
|
||||||
### manager
|
|
||||||
|
|
||||||
管理运行中的服务器操作:
|
|
||||||
|
|
||||||
- 命令:
|
|
||||||
- `shutdown`: 优雅地关闭运行中的进程
|
|
||||||
- `restart`: 优雅地重新启动运行中的进程(对于Windows服务器尚未实现)
|
|
||||||
- `flush-queues`: 刷新运行中的进程中的队列
|
|
||||||
- 选项:
|
|
||||||
- `--timeout value`: 刷新过程的超时时间(默认值: 1m0s)
|
|
||||||
- `--non-blocking`: 设置为true,以在返回之前不等待刷新完成
|
|
||||||
- `logging`: 调整日志命令
|
|
||||||
- 命令:
|
|
||||||
- `pause`: 暂停日志记录
|
|
||||||
- 注意:
|
|
||||||
- 如果日志级别低于此级别,日志级别将被临时提升为INFO。
|
|
||||||
- Gitea将在一定程度上缓冲日志,并在超过该点后丢弃日志。
|
|
||||||
- `resume`: 恢复日志记录
|
|
||||||
- `release-and-reopen`: 使Gitea释放和重新打开用于日志记录的文件和连接(相当于向Gitea发送SIGUSR1信号)。
|
|
||||||
- `remove name`: 删除指定的日志记录器
|
|
||||||
- 选项:
|
|
||||||
- `--group group`, `-g group`: 从中删除子记录器的组(默认为`default`)
|
|
||||||
- `add`: 添加日志记录器
|
|
||||||
- 命令:
|
|
||||||
- `console`: 添加控制台日志记录器
|
|
||||||
- 选项:
|
|
||||||
- `--group value`, `-g value`: 要添加日志记录器的组 - 默认为"default"
|
|
||||||
- `--name value`, `-n value`: 新日志记录器的名称 - 默认为模式
|
|
||||||
- `--level value`, `-l value`: 新日志记录器的日志级别
|
|
||||||
- `--stacktrace-level value`, `-L value`: 堆栈跟踪日志级别
|
|
||||||
- `--flags value`, `-F value`: 日志记录器的标志
|
|
||||||
- `--expression value`, `-e value`: 日志记录器的匹配表达式
|
|
||||||
- `--prefix value`, `-p value`: 日志记录器的前缀
|
|
||||||
- `--color`: 在日志中使用颜色
|
|
||||||
- `--stderr`: 将控制台日志输出到stderr - 仅适用于控制台
|
|
||||||
- `file`: 添加文件日志记录器
|
|
||||||
- 选项:
|
|
||||||
- `--group value`, `-g value`: 要添加日志记录器的组 - 默认为"default"
|
|
||||||
- `--name value`, `-n value`: 新日志记录器的名称 - 默认为模式
|
|
||||||
- `--level value`, `-l value`: 新日志记录器的日志级别
|
|
||||||
- `--stacktrace-level value`, `-L value`: 堆栈跟踪日志级别
|
|
||||||
- `--flags value`, `-F value`: 日志记录器的标志
|
|
||||||
- `--expression value`, `-e value`: 日志记录器的匹配表达式
|
|
||||||
- `--prefix value`, `-p value`: 日志记录器的前缀
|
|
||||||
- `--color`: 在日志中使用颜色
|
|
||||||
- `--filename value`, `-f value`: 日志记录器的文件名
|
|
||||||
- `--rotate`, `-r`: 轮转日志
|
|
||||||
- `--max-size value`, `-s value`: 在轮转之前的最大大小(以字节为单位)
|
|
||||||
- `--daily`, `-d`: 每天轮转日志
|
|
||||||
- `--max-days value`, `-D value`: 保留的每日日志的最大数量
|
|
||||||
- `--compress`, `-z`: 压缩轮转的日志
|
|
||||||
- `--compression-level value`, `-Z value`: 使用的压缩级别
|
|
||||||
- `conn`: 添加网络连接日志记录器
|
|
||||||
- 选项:
|
|
||||||
- `--group value`, `-g value`: 要添加日志记录器的组 - 默认为"default"
|
|
||||||
- `--name value`, `-n value`: 新日志记录器的名称 - 默认为模式
|
|
||||||
- `--level value`, `-l value`: 新日志记录器的日志级别
|
|
||||||
- `--stacktrace-level value`, `-L value`: 堆栈跟踪日志级别
|
|
||||||
- `--flags value`, `-F value`: 日志记录器的标志
|
|
||||||
- `--expression value`, `-e value`: 日志记录器的匹配表达式
|
|
||||||
- `--prefix value`, `-p value`: 日志记录器的前缀
|
|
||||||
- `--color`: 在日志中使用颜色
|
|
||||||
- `--reconnect-on-message`, `-R`: 对于每个消息重新连接主机
|
|
||||||
- `--reconnect`, `-r`: 连接中断时重新连接主机
|
|
||||||
- `--protocol value`, `-P value`: 设置要使用的协议:tcp、unix或udp(默认为tcp)
|
|
||||||
- `--address value`, `-a value`: 要连接到的主机地址和端口(默认为:7020)
|
|
||||||
- `smtp`: 添加SMTP日志记录器
|
|
||||||
- 选项:
|
|
||||||
- `--group value`, `-g value`: 要添加日志记录器的组 - 默认为"default"
|
|
||||||
- `--name value`, `-n value`: 新日志记录器的名称 - 默认为模式
|
|
||||||
- `--level value`, `-l value`: 新日志记录器的日志级别
|
|
||||||
- `--stacktrace-level value`, `-L value`: 堆栈跟踪日志级别
|
|
||||||
- `--flags value`, `-F value`: 日志记录器的标志
|
|
||||||
- `--expression value`, `-e value`: 日志记录器的匹配表达式
|
|
||||||
- `--prefix value`, `-p value`: 日志记录器的前缀
|
|
||||||
- `--color`: 在日志中使用颜色
|
|
||||||
- `--username value`, `-u value`: 邮件服务器用户名
|
|
||||||
- `--password value`, `-P value`: 邮件服务器密码
|
|
||||||
- `--host value`, `-H value`: 邮件服务器主机(默认为: 127.0.0.1:25)
|
|
||||||
- `--send-to value`, `-s value`: 要发送到的电子邮件地址
|
|
||||||
- `--subject value`, `-S value`: 发送电子邮件的主题标题
|
|
||||||
- `processes`: 显示 Gitea 进程和 Goroutine 信息
|
|
||||||
- 选项:
|
|
||||||
- `--flat`: 以平面表格形式显示进程,而不是树形结构
|
|
||||||
- `--no-system`: 不显示系统进程
|
|
||||||
- `--stacktraces`: 显示与进程关联的 Goroutine 的堆栈跟踪
|
|
||||||
- `--json`: 输出为 JSON 格式
|
|
||||||
- `--cancel PID`: 向具有 PID 的进程发送取消命令(仅适用于非系统进程)
|
|
||||||
|
|
||||||
### dump-repo
|
|
||||||
|
|
||||||
`dump-repo` 从 Git/GitHub/Gitea/GitLab 中转储存储库数据:
|
|
||||||
|
|
||||||
- 选项:
|
|
||||||
- `--git_service service`:Git 服务,可以是 `git`、`github`、`gitea`、`gitlab`。如果 `clone_addr` 可以被识别,则可以忽略此选项。
|
|
||||||
- `--repo_dir dir`,`-r dir`:存储数据的存储库目录路径。
|
|
||||||
- `--clone_addr addr`:将被克隆的 URL,目前可以是 git/github/gitea/gitlab 的 http/https URL。例如:https://github.com/lunny/tango.git
|
|
||||||
- `--auth_username lunny`:访问 `clone_addr` 的用户名。
|
|
||||||
- `--auth_password <password>`:访问 `clone_addr` 的密码。
|
|
||||||
- `--auth_token <token>`:访问 `clone_addr` 的个人令牌。
|
|
||||||
- `--owner_name lunny`:如果非空,数据将存储在具有所有者名称的目录中。
|
|
||||||
- `--repo_name tango`:如果非空,数据将存储在具有存储库名称的目录中。
|
|
||||||
- `--units <units>`:要迁移的项目,一个或多个项目应以逗号分隔。允许的项目有 wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments。如果为空,则表示所有项目。
|
|
||||||
|
|
||||||
### restore-repo
|
|
||||||
|
|
||||||
`restore-repo` 从磁盘目录中还原存储库数据:
|
|
||||||
|
|
||||||
- 选项:
|
|
||||||
- `--repo_dir dir`,`-r dir`:还原数据的存储库目录路径。
|
|
||||||
- `--owner_name lunny`:还原目标所有者名称。
|
|
||||||
- `--repo_name tango`:还原目标存储库名称。
|
|
||||||
- `--units <units>`:要还原的项目,一个或多个项目应以逗号分隔。允许的项目有 wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments。如果为空,则表示所有项目。
|
|
||||||
|
|
||||||
### actions generate-runner-token
|
|
||||||
|
|
||||||
生成一个供 Runner 使用的新令牌,用于向服务器注册。
|
|
||||||
|
|
||||||
- 选项:
|
|
||||||
- `--scope {owner}[/{repo}]`,`-s {owner}[/{repo}]`:限制 Runner 的范围,没有范围表示该 Runner 可用于所有仓库,但你也可以将其限制为特定的仓库或所有者。
|
|
||||||
|
|
||||||
要注册全局 Runner:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea actions generate-runner-token
|
|
||||||
```
|
|
||||||
|
|
||||||
要注册特定组织的 Runner,例如 `org`:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea actions generate-runner-token -s org
|
|
||||||
```
|
|
||||||
|
|
||||||
要注册特定仓库的 Runner,例如 `username/test-repo`:
|
|
||||||
|
|
||||||
```
|
|
||||||
gitea actions generate-runner-token -s username/test-repo
|
|
||||||
```
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,403 +0,0 @@
|
||||||
---
|
|
||||||
date: "2017-04-15T14:56:00+02:00"
|
|
||||||
title: "Customizing Gitea"
|
|
||||||
slug: "customizing-gitea"
|
|
||||||
sidebar_position: 100
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/customizing-gitea
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Customizing Gitea"
|
|
||||||
identifier: "customizing-gitea"
|
|
||||||
sidebar_position: 100
|
|
||||||
---
|
|
||||||
|
|
||||||
# Customizing Gitea
|
|
||||||
|
|
||||||
Customizing Gitea is typically done using the `CustomPath` folder - by default this is
|
|
||||||
the `custom` folder from the working directory (WorkPath), but may be different if your build has
|
|
||||||
set this differently. This is the central place to override configuration settings,
|
|
||||||
templates, etc. You can check the `CustomPath` using `gitea help`. You can also find
|
|
||||||
the path on the _Configuration_ tab in the _Site Administration_ page. You can override
|
|
||||||
the `CustomPath` by setting either the `GITEA_CUSTOM` environment variable or by
|
|
||||||
using the `--custom-path` option on the `gitea` binary. (The option will override the
|
|
||||||
environment variable.)
|
|
||||||
|
|
||||||
If Gitea is deployed from binary, all default paths will be relative to the Gitea
|
|
||||||
binary. If installed from a distribution, these paths will likely be modified to
|
|
||||||
the Linux Filesystem Standard. Gitea will attempt to create required folders, including
|
|
||||||
`custom/`. Distributions may provide a symlink for `custom` using `/etc/gitea/`.
|
|
||||||
|
|
||||||
Application settings can be found in file `CustomConf` which is by default,
|
|
||||||
`$GITEA_CUSTOM/conf/app.ini` but may be different if your build has set this differently.
|
|
||||||
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](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`
|
|
||||||
environment variable; this can be used to override the default path to something else.
|
|
||||||
`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](administration/environment-variables.md)
|
|
||||||
|
|
||||||
**Note:** Gitea must perform a full restart to see configuration changes.
|
|
||||||
|
|
||||||
## Serving custom public files
|
|
||||||
|
|
||||||
To make Gitea serve custom public files (like pages and images), use the folder
|
|
||||||
`$GITEA_CUSTOM/public/` as the webroot. Symbolic links will be followed.
|
|
||||||
At the moment, only the following files are served:
|
|
||||||
|
|
||||||
- `public/robots.txt`
|
|
||||||
- files in the `public/.well-known/` folder
|
|
||||||
- files in the `public/assets/` folder
|
|
||||||
|
|
||||||
For example, a file `image.png` stored in `$GITEA_CUSTOM/public/assets/`, can be accessed with
|
|
||||||
the url `http://gitea.domain.tld/assets/image.png`.
|
|
||||||
|
|
||||||
## Changing the logo
|
|
||||||
|
|
||||||
To build a custom logo and/or favicon clone the Gitea source repository, replace `assets/logo.svg` and/or `assets/favicon.svg` and run
|
|
||||||
`make generate-images`. `assets/favicon.svg` is used for the favicon only. This will update below output files which you can then place in `$GITEA_CUSTOM/public/assets/img` on your server:
|
|
||||||
|
|
||||||
- `public/assets/img/logo.svg` - Used for site icon, app icon
|
|
||||||
- `public/assets/img/logo.png` - Used for Open Graph
|
|
||||||
- `public/assets/img/avatar_default.png` - Used as the default avatar image
|
|
||||||
- `public/assets/img/apple-touch-icon.png` - Used on iOS devices for bookmarks
|
|
||||||
- `public/assets/img/favicon.svg` - Used for favicon
|
|
||||||
- `public/assets/img/favicon.png` - Used as fallback for browsers that don't support SVG favicons
|
|
||||||
|
|
||||||
In case the source image is not in vector format, you can attempt to convert a raster image using tools like [this](https://www.aconvert.com/image/png-to-svg/).
|
|
||||||
|
|
||||||
## Customizing Gitea pages and resources
|
|
||||||
|
|
||||||
Gitea's executable contains all the resources required to run: templates, images, style-sheets
|
|
||||||
and translations. Any of them can be overridden by placing a replacement in a matching path
|
|
||||||
inside the `custom` directory. For example, to replace the default `.gitignore` provided
|
|
||||||
for C++ repositories, we want to replace `options/gitignore/C++`. To do this, a replacement
|
|
||||||
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://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).
|
|
||||||
|
|
||||||
Be aware that any statement contained inside `{{` and `}}` are Gitea's template syntax and
|
|
||||||
shouldn't be touched without fully understanding these components.
|
|
||||||
|
|
||||||
### Customizing startpage / homepage
|
|
||||||
|
|
||||||
Copy [`home.tmpl`](https://github.com/go-gitea/gitea/blob/main/templates/home.tmpl) for your version of Gitea from `templates` to `$GITEA_CUSTOM/templates`.
|
|
||||||
Edit as you wish.
|
|
||||||
Dont forget to restart your Gitea to apply the changes.
|
|
||||||
|
|
||||||
### Adding links and tabs
|
|
||||||
|
|
||||||
If all you want is to add extra links to the top navigation bar or footer, or extra tabs to the repository view, you can put them in `extra_links.tmpl` (links added to the navbar), `extra_links_footer.tmpl` (links added to the left side of footer), and `extra_tabs.tmpl` inside your `$GITEA_CUSTOM/templates/custom/` directory.
|
|
||||||
|
|
||||||
For instance, let's say you are in Germany and must add the famously legally-required "Impressum"/about page, listing who is responsible for the site's content:
|
|
||||||
just place it under your "$GITEA_CUSTOM/public/assets/" directory (for instance `$GITEA_CUSTOM/public/assets/impressum.html`) and put a link to it in either `$GITEA_CUSTOM/templates/custom/extra_links.tmpl` or `$GITEA_CUSTOM/templates/custom/extra_links_footer.tmpl`.
|
|
||||||
|
|
||||||
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](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
|
|
||||||
`templates/repo/header.tmpl`
|
|
||||||
([source in GitHub](https://github.com/go-gitea/gitea/blob/main/templates/repo/header.tmpl))
|
|
||||||
|
|
||||||
### Other additions to the page
|
|
||||||
|
|
||||||
Apart from `extra_links.tmpl` and `extra_tabs.tmpl`, there are other useful templates you can put in your `$GITEA_CUSTOM/templates/custom/` directory:
|
|
||||||
|
|
||||||
- `header.tmpl`, just before the end of the `<head>` tag where you can add custom CSS files for instance.
|
|
||||||
- `body_outer_pre.tmpl`, right after the start of `<body>`.
|
|
||||||
- `body_inner_pre.tmpl`, before the top navigation bar, but already inside the main container `<div class="full height">`.
|
|
||||||
- `body_inner_post.tmpl`, before the end of the main container.
|
|
||||||
- `body_outer_post.tmpl`, before the bottom `<footer>` element.
|
|
||||||
- `footer.tmpl`, right before the end of the `<body>` tag, a good place for additional JavaScript.
|
|
||||||
|
|
||||||
### Using Gitea variables
|
|
||||||
|
|
||||||
It's possible to use various Gitea variables in your custom templates.
|
|
||||||
|
|
||||||
First, _temporarily_ enable development mode: in your `app.ini` change from `RUN_MODE = prod` to `RUN_MODE = dev`. Then add `{{ $ | DumpVar }}` to any of your templates, restart Gitea and refresh that page; that will dump all available variables.
|
|
||||||
|
|
||||||
Find the data that you need, and use the corresponding variable; for example, if you need the name of the repository then you'd use `{{.Repository.Name}}`.
|
|
||||||
|
|
||||||
If you need to transform that data somehow, and aren't familiar with Go, an easy workaround is to add the data to the DOM and add a small JavaScript script block to manipulate the data.
|
|
||||||
|
|
||||||
### Example: PlantUML
|
|
||||||
|
|
||||||
You can add [PlantUML](https://plantuml.com/) support to Gitea's markdown by using a PlantUML server.
|
|
||||||
The data is encoded and sent to the PlantUML server which generates the picture. There is an online
|
|
||||||
demo server at http://www.plantuml.com/plantuml, but if you (or your users) have sensitive data you
|
|
||||||
can set up your own [PlantUML server](https://plantuml.com/server) instead. To set up PlantUML rendering,
|
|
||||||
copy JavaScript files from https://gitea.com/davidsvantesson/plantuml-code-highlight and put them in your
|
|
||||||
`$GITEA_CUSTOM/public/assets/` folder. Then add the following to `custom/footer.tmpl`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<script>
|
|
||||||
$(async () => {
|
|
||||||
if (!$('.language-plantuml').length) return;
|
|
||||||
await Promise.all([
|
|
||||||
$.getScript('https://your-gitea-server.com/assets/deflate.js'),
|
|
||||||
$.getScript('https://your-gitea-server.com/assets/encode.js'),
|
|
||||||
$.getScript('https://your-gitea-server.com/assets/plantuml_codeblock_parse.js'),
|
|
||||||
]);
|
|
||||||
// Replace call with address to your plantuml server
|
|
||||||
parsePlantumlCodeBlocks("https://www.plantuml.com/plantuml");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
You can then add blocks like the following to your markdown:
|
|
||||||
|
|
||||||
```plantuml
|
|
||||||
Alice -> Bob: Authentication Request
|
|
||||||
Bob --> Alice: Authentication Response
|
|
||||||
|
|
||||||
Alice -> Bob: Another authentication Request
|
|
||||||
Alice <-- Bob: Another authentication Response
|
|
||||||
```
|
|
||||||
|
|
||||||
The script will detect tags with `class="language-plantuml"`, but you can change this by providing a second argument to `parsePlantumlCodeBlocks`.
|
|
||||||
|
|
||||||
### Example: STL Preview
|
|
||||||
|
|
||||||
You can display STL file directly in Gitea by adding:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<script>
|
|
||||||
function lS(src) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
let s = document.createElement("script");
|
|
||||||
s.src = src;
|
|
||||||
s.addEventListener("load", () => {
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
document.body.appendChild(s);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($('.view-raw>a[href$=".stl" i]').length) {
|
|
||||||
$("body").append(
|
|
||||||
'<link href="/assets/Madeleine.js/src/css/Madeleine.css" rel="stylesheet">'
|
|
||||||
);
|
|
||||||
Promise.all([
|
|
||||||
lS("/assets/Madeleine.js/src/lib/stats.js"),
|
|
||||||
lS("/assets/Madeleine.js/src/lib/detector.js"),
|
|
||||||
lS("/assets/Madeleine.js/src/lib/three.min.js"),
|
|
||||||
lS("/assets/Madeleine.js/src/Madeleine.js"),
|
|
||||||
]).then(function () {
|
|
||||||
$(".view-raw")
|
|
||||||
.attr("id", "view-raw")
|
|
||||||
.attr("style", "padding: 0;margin-bottom: -10px;");
|
|
||||||
new Madeleine({
|
|
||||||
target: "view-raw",
|
|
||||||
data: $('.view-raw>a[href$=".stl" i]').attr("href"),
|
|
||||||
path: "/assets/Madeleine.js/src",
|
|
||||||
});
|
|
||||||
$('.view-raw>a[href$=".stl"]').remove();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
to the file `templates/custom/footer.tmpl`
|
|
||||||
|
|
||||||
You also need to download the content of the library [Madeleine.js](https://github.com/beige90/Madeleine.js) and place it under `$GITEA_CUSTOM/public/assets/` folder.
|
|
||||||
|
|
||||||
You should end-up with a folder structure similar to:
|
|
||||||
|
|
||||||
```
|
|
||||||
$GITEA_CUSTOM/templates
|
|
||||||
-- custom
|
|
||||||
`-- footer.tmpl
|
|
||||||
|
|
||||||
$GITEA_CUSTOM/public/assets/
|
|
||||||
-- Madeleine.js
|
|
||||||
|-- LICENSE
|
|
||||||
|-- README.md
|
|
||||||
|-- css
|
|
||||||
| |-- pygment_trac.css
|
|
||||||
| `-- stylesheet.css
|
|
||||||
|-- examples
|
|
||||||
| |-- ajax.html
|
|
||||||
| |-- index.html
|
|
||||||
| `-- upload.html
|
|
||||||
|-- images
|
|
||||||
| |-- bg_hr.png
|
|
||||||
| |-- blacktocat.png
|
|
||||||
| |-- icon_download.png
|
|
||||||
| `-- sprite_download.png
|
|
||||||
|-- models
|
|
||||||
| |-- dino2.stl
|
|
||||||
| |-- ducati.stl
|
|
||||||
| |-- gallardo.stl
|
|
||||||
| |-- lamp.stl
|
|
||||||
| |-- octocat.stl
|
|
||||||
| |-- skull.stl
|
|
||||||
| `-- treefrog.stl
|
|
||||||
`-- src
|
|
||||||
|-- Madeleine.js
|
|
||||||
|-- css
|
|
||||||
| `-- Madeleine.css
|
|
||||||
|-- icons
|
|
||||||
| |-- logo.png
|
|
||||||
| |-- madeleine.eot
|
|
||||||
| |-- madeleine.svg
|
|
||||||
| |-- madeleine.ttf
|
|
||||||
| `-- madeleine.woff
|
|
||||||
`-- lib
|
|
||||||
|-- MadeleineConverter.js
|
|
||||||
|-- MadeleineLoader.js
|
|
||||||
|-- detector.js
|
|
||||||
|-- stats.js
|
|
||||||
`-- three.min.js
|
|
||||||
```
|
|
||||||
|
|
||||||
Then restart Gitea and open a STL file on your Gitea instance.
|
|
||||||
|
|
||||||
## Customizing Gitea mails
|
|
||||||
|
|
||||||
The `$GITEA_CUSTOM/templates/mail` folder allows changing the body of every mail of Gitea.
|
|
||||||
Templates to override can be found in the
|
|
||||||
[`templates/mail`](https://github.com/go-gitea/gitea/tree/main/templates/mail)
|
|
||||||
directory of Gitea source.
|
|
||||||
Override by making a copy of the file under `$GITEA_CUSTOM/templates/mail` using a
|
|
||||||
full path structure matching source.
|
|
||||||
|
|
||||||
Any statement contained inside `{{` and `}}` are Gitea's template
|
|
||||||
syntax and shouldn't be touched without fully understanding these components.
|
|
||||||
|
|
||||||
## Adding Analytics to Gitea
|
|
||||||
|
|
||||||
Google Analytics, Matomo (previously Piwik), and other analytics services can be added to Gitea. To add the tracking code, refer to the `Other additions to the page` section of this document, and add the JavaScript to the `$GITEA_CUSTOM/templates/custom/header.tmpl` file.
|
|
||||||
|
|
||||||
## Customizing gitignores, labels, licenses, locales, and readmes.
|
|
||||||
|
|
||||||
Place custom files in corresponding sub-folder under `custom/options`.
|
|
||||||
|
|
||||||
**NOTE:** The files should not have a file extension, e.g. `Labels` rather than `Labels.txt`
|
|
||||||
|
|
||||||
### gitignores
|
|
||||||
|
|
||||||
To add custom .gitignore, add a file with existing [.gitignore rules](https://git-scm.com/docs/gitignore) in it to `$GITEA_CUSTOM/options/gitignore`
|
|
||||||
|
|
||||||
## Customizing the git configuration
|
|
||||||
|
|
||||||
Starting with Gitea 1.20, you can customize the git configuration via the `git.config` section.
|
|
||||||
|
|
||||||
### Enabling signed git pushes
|
|
||||||
|
|
||||||
To enable signed git pushes, set these two options:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[git.config]
|
|
||||||
receive.advertisePushOptions = true
|
|
||||||
receive.certNonceSeed = <randomstring>
|
|
||||||
```
|
|
||||||
|
|
||||||
`certNonceSeed` should be set to a random string and be kept secret.
|
|
||||||
|
|
||||||
### Labels
|
|
||||||
|
|
||||||
Starting with Gitea 1.19, you can add a file that follows the [YAML label format](https://github.com/go-gitea/gitea/blob/main/options/label/Advanced.yaml) to `$GITEA_CUSTOM/options/label`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
labels:
|
|
||||||
- name: "foo/bar" # name of the label that will appear in the dropdown
|
|
||||||
exclusive: true # whether to use the exclusive namespace for scoped labels. scoped delimiter is /
|
|
||||||
color: aabbcc # hex colour coding
|
|
||||||
description: Some label # long description of label intent
|
|
||||||
```
|
|
||||||
|
|
||||||
The [legacy file format](https://github.com/go-gitea/gitea/blob/main/options/label/Default) can still be used following the format below, however we strongly recommend using the newer YAML format instead.
|
|
||||||
|
|
||||||
`#hex-color label name ; label description`
|
|
||||||
|
|
||||||
For more information, see the [labels documentation](usage/labels.md).
|
|
||||||
|
|
||||||
### Licenses
|
|
||||||
|
|
||||||
To add a custom license, add a file with the license text to `$GITEA_CUSTOM/options/license`
|
|
||||||
|
|
||||||
### Locales
|
|
||||||
|
|
||||||
Locales are managed via our [Crowdin](https://crowdin.com/project/gitea).
|
|
||||||
You can override a locale by placing an altered locale file in `$GITEA_CUSTOM/options/locale`.
|
|
||||||
Gitea's default locale files can be found in the [`options/locale`](https://github.com/go-gitea/gitea/tree/main/options/locale) source folder and these should be used as examples for your changes.
|
|
||||||
|
|
||||||
To add a completely new locale, as well as placing the file in the above location, you will need to add the new lang and name to the `[i18n]` section in your `app.ini`. Keep in mind that Gitea will use those settings as **overrides**, so if you want to keep the other languages as well you will need to copy/paste the default values and add your own to them.
|
|
||||||
|
|
||||||
```
|
|
||||||
[i18n]
|
|
||||||
LANGS = en-US,foo-BAR
|
|
||||||
NAMES = English,FooBar
|
|
||||||
```
|
|
||||||
|
|
||||||
The first locale will be used as the default if user browser's language doesn't match any locale in the list.
|
|
||||||
|
|
||||||
Locales may change between versions, so keeping track of your customized locales is highly encouraged.
|
|
||||||
|
|
||||||
### Readmes
|
|
||||||
|
|
||||||
To add a custom Readme, add a markdown formatted file (without an `.md` extension) to `$GITEA_CUSTOM/options/readme`
|
|
||||||
|
|
||||||
**NOTE:** readme templates support **variable expansion**.
|
|
||||||
currently there are `{Name}` (name of repository), `{Description}`, `{CloneURL.SSH}`, `{CloneURL.HTTPS}` and `{OwnerName}`
|
|
||||||
|
|
||||||
### Reactions
|
|
||||||
|
|
||||||
To change reaction emoji's you can set allowed reactions at app.ini
|
|
||||||
|
|
||||||
```
|
|
||||||
[ui]
|
|
||||||
REACTIONS = +1, -1, laugh, confused, heart, hooray, eyes
|
|
||||||
```
|
|
||||||
|
|
||||||
A full list of supported emoji's is at [emoji list](https://gitea.com/gitea/gitea.com/issues/8)
|
|
||||||
|
|
||||||
## Customizing the look of Gitea
|
|
||||||
|
|
||||||
The built-in themes are `gitea-light`, `gitea-dark`, and `gitea-auto` (which automatically adapts to OS settings).
|
|
||||||
|
|
||||||
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](administration/config-cheat-sheet.md#ui-ui) section of `app.ini`.
|
|
||||||
|
|
||||||
To make a custom theme available to all users:
|
|
||||||
|
|
||||||
1. Add a CSS file to `$GITEA_CUSTOM/public/assets/css/theme-<theme-name>.css`.
|
|
||||||
The value of `$GITEA_CUSTOM` of your instance can be queried by calling `gitea help` and looking up the value of "CustomPath".
|
|
||||||
2. Add `<theme-name>` to the comma-separated list of setting `THEMES` in `app.ini`
|
|
||||||
|
|
||||||
Community themes are listed in [gitea/awesome-gitea#themes](https://gitea.com/gitea/awesome-gitea#themes).
|
|
||||||
|
|
||||||
The default theme sources can be found [here](https://github.com/go-gitea/gitea/blob/main/web_src/css/themes).
|
|
||||||
|
|
||||||
If your custom theme is considered a dark theme, set the global css variable `--is-dark-theme` to `true`.
|
|
||||||
This allows Gitea to adjust the Monaco code editor's theme accordingly.
|
|
||||||
|
|
||||||
## Customizing fonts
|
|
||||||
|
|
||||||
Fonts can be customized using CSS variables:
|
|
||||||
|
|
||||||
```css
|
|
||||||
:root {
|
|
||||||
--fonts-proportional: /* custom proportional fonts */ !important;
|
|
||||||
--fonts-monospace: /* custom monospace fonts */ !important;
|
|
||||||
--fonts-emoji: /* custom emoji fonts */ !important;
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,91 +0,0 @@
|
||||||
---
|
|
||||||
date: "2017-04-15T14:56:00+02:00"
|
|
||||||
title: "自定义 Gitea 配置"
|
|
||||||
slug: "customizing-gitea"
|
|
||||||
sidebar_position: 100
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/customizing-gitea
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "自定义 Gitea 配置"
|
|
||||||
sidebar_position: 100
|
|
||||||
identifier: "customizing-gitea"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 自定义 Gitea 配置
|
|
||||||
|
|
||||||
Gitea 引用 `custom` 目录中的自定义配置文件来覆盖配置、模板等默认配置。
|
|
||||||
|
|
||||||
如果从二进制部署 Gitea ,则所有默认路径都将相对于该 gitea 二进制文件;如果从发行版安装,则可能会将这些路径修改为Linux文件系统标准。Gitea
|
|
||||||
将会自动创建包括 `custom/` 在内的必要应用目录,应用本身的配置存放在
|
|
||||||
`custom/conf/app.ini` 当中。在发行版中可能会以 `/etc/gitea/` 的形式为 `custom` 设置一个符号链接,查看配置详情请移步:
|
|
||||||
|
|
||||||
- [快速备忘单](administration/config-cheat-sheet.md)
|
|
||||||
- [完整配置清单](https://github.com/go-gitea/gitea/blob/main/custom/conf/app.example.ini)
|
|
||||||
|
|
||||||
如果您在 binary 同目录下无法找到 `custom` 文件夹,请检查您的 `GITEA_CUSTOM`
|
|
||||||
环境变量配置, 因为它可能被配置到了其他地方(可能被一些启动脚本设置指定了目录)。
|
|
||||||
|
|
||||||
- [环境变量清单](administration/environment-variables.md)
|
|
||||||
|
|
||||||
**注:** 必须完全重启 Gitea 以使配置生效。
|
|
||||||
|
|
||||||
## 使用自定义 /robots.txt
|
|
||||||
|
|
||||||
将 [想要展示的内容](http://www.robotstxt.org/) 存放在 `custom` 目录中的
|
|
||||||
`robots.txt` 文件来让 Gitea 使用自定义的`/robots.txt` (默认:空 404)。
|
|
||||||
|
|
||||||
## 使用自定义的公共文件
|
|
||||||
|
|
||||||
将自定义的公共文件(比如页面和图片)作为 webroot 放在 `custom/public/` 中来让 Gitea 提供这些自定义内容(符号链接将被追踪)。
|
|
||||||
|
|
||||||
举例说明:`image.png` 存放在 `custom/public/assets/`中,那么它可以通过链接 http://gitea.domain.tld/assets/image.png 访问。
|
|
||||||
|
|
||||||
## 修改默认头像
|
|
||||||
|
|
||||||
替换以下目录中的 png 图片: `custom/public/assets/img/avatar\_default.png`
|
|
||||||
|
|
||||||
## 自定义 Gitea 页面
|
|
||||||
|
|
||||||
您可以改变 Gitea `custom/templates` 的每个单页面。您可以在 Gitea 源码的 `templates` 目录中找到用于覆盖的模板文件,应用将根据
|
|
||||||
`custom/templates` 目录下的路径结构进行匹配和覆盖。
|
|
||||||
|
|
||||||
包含在 `{{` 和 `}}` 中的任何语句都是 Gitea 的模板语法,如果您不完全理解这些组件,不建议您对它们进行修改。
|
|
||||||
|
|
||||||
### 添加链接和页签
|
|
||||||
|
|
||||||
如果您只是想添加额外的链接到顶部导航栏或额外的选项卡到存储库视图,您可以将它们放在您 `custom/templates/custom/` 目录下的 `extra_links.tmpl` 和 `extra_tabs.tmpl` 文件中。
|
|
||||||
|
|
||||||
举例说明:假设您需要在网站放置一个静态的“关于”页面,您只需将该页面放在您的
|
|
||||||
"custom/public/"目录下(比如 `custom/public/impressum.html`)并且将它与 `custom/templates/custom/extra_links.tmpl` 链接起来即可。
|
|
||||||
|
|
||||||
这个链接应当使用一个名为“item”的 class 来匹配当前样式,您可以使用 `{{AppSubUrl}}` 来获取 base URL:
|
|
||||||
`<a class="item" href="{{AppSubUrl}}/assets/impressum.html">Impressum</a>`
|
|
||||||
|
|
||||||
同理,您可以将页签添加到 `extra_tabs.tmpl` 中,使用同样的方式来添加页签。它的具体样式需要与
|
|
||||||
`templates/repo/header.tmpl` 中已有的其他选项卡的样式匹配
|
|
||||||
([source in GitHub](https://github.com/go-gitea/gitea/blob/main/templates/repo/header.tmpl))
|
|
||||||
|
|
||||||
### 页面的其他新增内容
|
|
||||||
|
|
||||||
除了 `extra_links.tmpl` 和 `extra_tabs.tmpl`,您可以在您的 `custom/templates/custom/` 目录中存放一些其他有用的模板,例如:
|
|
||||||
|
|
||||||
- `header.tmpl`,在 `<head>` 标记结束之前的模板,例如添加自定义CSS文件
|
|
||||||
- `body_outer_pre.tmpl`,在 `<body>` 标记开始处的模板
|
|
||||||
- `body_inner_pre.tmpl`,在顶部导航栏之前,但在主 container 内部的模板,例如添加一个 `<div class="full height">`
|
|
||||||
- `body_inner_post.tmpl`,在主 container 结束处的模板
|
|
||||||
- `body_outer_post.tmpl`,在底部 `<footer>` 元素之前.
|
|
||||||
- `footer.tmpl`,在 `<body>` 标签结束处的模板,可以在这里填写一些附加的 Javascript 脚本。
|
|
||||||
|
|
||||||
## 自定义 gitignores,labels, licenses, locales 以及 readmes
|
|
||||||
|
|
||||||
将自定义文件放在 `custom/options` 下相应子的文件夹中即可
|
|
||||||
|
|
||||||
## 更改 Gitea 外观
|
|
||||||
|
|
||||||
内置主题是“gitea-light”、“gitea-dark”和“gitea-auto”(自动适应操作系统设置)。
|
|
||||||
|
|
||||||
默认主题可以通过 `app.ini` 的 [ui](administration/config-cheat-sheet.md#ui-ui) 部分中的 `DEFAULT_THEME` 进行更改。
|
|
|
@ -1,86 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-10-15T10:10:00+05:00"
|
|
||||||
title: "Email setup"
|
|
||||||
slug: "email-setup"
|
|
||||||
sidebar_position: 12
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/email-setup
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Email setup"
|
|
||||||
sidebar_position: 12
|
|
||||||
identifier: "email-setup"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Email setup
|
|
||||||
|
|
||||||
Gitea has mailer functionality for sending transactional emails (such as registration confirmation). It can be configured to either use Sendmail (or compatible MTAs like Postfix and msmtp) or directly use SMTP server.
|
|
||||||
|
|
||||||
## Using Sendmail
|
|
||||||
|
|
||||||
Use `sendmail` command as mailer.
|
|
||||||
|
|
||||||
Note: For use in the official Gitea Docker image, please configure with the SMTP version (see the following section).
|
|
||||||
|
|
||||||
Note: For Internet-facing sites consult documentation of your MTA for instructions to send emails over TLS. Also set up SPF, DMARC, and DKIM DNS records to make emails sent be accepted as legitimate by various email providers.
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[mailer]
|
|
||||||
ENABLED = true
|
|
||||||
FROM = gitea@mydomain.com
|
|
||||||
PROTOCOL = sendmail
|
|
||||||
SENDMAIL_PATH = /usr/sbin/sendmail
|
|
||||||
SENDMAIL_ARGS = "--" ; most "sendmail" programs take options, "--" will prevent an email address being interpreted as an option.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using SMTP
|
|
||||||
|
|
||||||
Directly use SMTP server as relay. This option is useful if you don't want to set up MTA on your instance but you have an account at email provider.
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[mailer]
|
|
||||||
ENABLED = true
|
|
||||||
FROM = gitea@mydomain.com
|
|
||||||
PROTOCOL = smtps
|
|
||||||
SMTP_ADDR = mail.mydomain.com
|
|
||||||
SMTP_PORT = 587
|
|
||||||
USER = gitea@mydomain.com
|
|
||||||
PASSWD = `password`
|
|
||||||
```
|
|
||||||
|
|
||||||
Restart Gitea for the configuration changes to take effect.
|
|
||||||
|
|
||||||
To send a test email to validate the settings, go to Gitea > Site Administration > Configuration > SMTP Mailer Configuration.
|
|
||||||
|
|
||||||
For the full list of options check the [Config Cheat Sheet](administration/config-cheat-sheet.md)
|
|
||||||
|
|
||||||
Please note: authentication is only supported when the SMTP server communication is encrypted with TLS or `HOST=localhost`. TLS encryption can be through:
|
|
||||||
|
|
||||||
- STARTTLS (also known as Opportunistic TLS) via port 587. Initial connection is done over cleartext, but then be upgraded over TLS if the server supports it.
|
|
||||||
- SMTPS connection (SMTP over TLS) via the default port 465. Connection to the server use TLS from the beginning.
|
|
||||||
- Forced SMTPS connection with `PROTOCOL=smtps`. (These are both known as Implicit TLS.)
|
|
||||||
This is due to protections imposed by the Go internal libraries against STRIPTLS attacks.
|
|
||||||
|
|
||||||
Note that Implicit TLS is recommended by [RFC8314](https://tools.ietf.org/html/rfc8314#section-3) since 2018.
|
|
||||||
|
|
||||||
### Gmail
|
|
||||||
|
|
||||||
The following configuration should work with GMail's SMTP server:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[mailer]
|
|
||||||
ENABLED = true
|
|
||||||
HOST = smtp.gmail.com:465 ; Remove this line for Gitea >= 1.18.0
|
|
||||||
SMTP_ADDR = smtp.gmail.com
|
|
||||||
SMTP_PORT = 465
|
|
||||||
FROM = example.user@gmail.com
|
|
||||||
USER = example.user
|
|
||||||
PASSWD = `***`
|
|
||||||
PROTOCOL = smtps
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that you'll need to create and use an [App password](https://support.google.com/accounts/answer/185833?hl=en) by enabling 2FA on your Google
|
|
||||||
account. You won't be able to use your Google account password directly.
|
|
|
@ -1,85 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "Email 设置"
|
|
||||||
slug: "email-setup"
|
|
||||||
sidebar_position: 12
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/email-setup
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Email 设置"
|
|
||||||
sidebar_position: 12
|
|
||||||
identifier: "email-setup"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Email 设置
|
|
||||||
|
|
||||||
Gitea 具有邮件功能,用于发送事务性邮件(例如注册确认邮件)。它可以配置为使用 Sendmail(或兼容的 MTA,例如 Postfix 和 msmtp)或直接使用 SMTP 服务器。
|
|
||||||
|
|
||||||
## 使用 Sendmail
|
|
||||||
|
|
||||||
使用 `sendmail` 命令作为邮件传输代理(mailer)。
|
|
||||||
|
|
||||||
注意:对于在官方Gitea Docker镜像中使用,请使用SMTP版本进行配置(请参考下一节)。
|
|
||||||
|
|
||||||
注意:对于面向互联网的网站,请查阅您的 MTA 文档以了解通过TLS发送邮件的说明。同时设置 SPF、DMARC 和 DKIM DNS 记录,以使发送的邮件被各个电子邮件提供商接受为合法邮件。
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[mailer]
|
|
||||||
ENABLED = true
|
|
||||||
FROM = gitea@mydomain.com
|
|
||||||
PROTOCOL = sendmail
|
|
||||||
SENDMAIL_PATH = /usr/sbin/sendmail
|
|
||||||
SENDMAIL_ARGS = "--" ; 大多数 "sendmail" 程序都接受选项,使用 "--" 将防止电子邮件地址被解释为选项。
|
|
||||||
```
|
|
||||||
|
|
||||||
## 使用 SMTP
|
|
||||||
|
|
||||||
直接使用 SMTP 服务器作为中继。如果您不想在实例上设置 MTA,但在电子邮件提供商那里有一个帐户,这个选项非常有用。
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[mailer]
|
|
||||||
ENABLED = true
|
|
||||||
FROM = gitea@mydomain.com
|
|
||||||
PROTOCOL = smtps
|
|
||||||
SMTP_ADDR = mail.mydomain.com
|
|
||||||
SMTP_PORT = 587
|
|
||||||
USER = gitea@mydomain.com
|
|
||||||
PASSWD = `password`
|
|
||||||
```
|
|
||||||
|
|
||||||
重启 Gitea 以使配置更改生效。
|
|
||||||
|
|
||||||
要发送测试邮件以验证设置,请转到 Gitea > 站点管理 > 配置 > SMTP 邮件配置。
|
|
||||||
|
|
||||||
有关所有选项的完整列表,请查看[配置速查表](administration/config-cheat-sheet.md)。
|
|
||||||
|
|
||||||
请注意:只有在使用 TLS 或 `HOST=localhost` 加密 SMTP 服务器通信时才支持身份验证。TLS 加密可以通过以下方式进行:
|
|
||||||
|
|
||||||
- 通过端口 587 的 STARTTLS(也称为 Opportunistic TLS)。初始连接是明文的,但如果服务器支持,则可以升级为 TLS。
|
|
||||||
- 通过默认端口 465 的 SMTPS 连接。连接到服务器从一开始就使用 TLS。
|
|
||||||
- 使用 `PROTOCOL=smtps` 进行强制的 SMTPS 连接。(这两种方式都被称为 Implicit TLS)
|
|
||||||
这是由于 Go 内部库对 STRIPTLS 攻击的保护机制。
|
|
||||||
|
|
||||||
请注意,自2018年起,[RFC8314](https://tools.ietf.org/html/rfc8314#section-3) 推荐使用 Implicit TLS。
|
|
||||||
|
|
||||||
### Gmail
|
|
||||||
|
|
||||||
以下配置应该适用于 Gmail 的 SMTP 服务器:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[mailer]
|
|
||||||
ENABLED = true
|
|
||||||
HOST = smtp.gmail.com:465 ; 对于 Gitea >= 1.18.0,删除此行
|
|
||||||
SMTP_ADDR = smtp.gmail.com
|
|
||||||
SMTP_PORT = 465
|
|
||||||
FROM = example.user@gmail.com
|
|
||||||
USER = example.user
|
|
||||||
PASSWD = `***`
|
|
||||||
PROTOCOL = smtps
|
|
||||||
```
|
|
||||||
|
|
||||||
请注意,您需要创建并使用一个 [应用密码](https://support.google.com/accounts/answer/185833?hl=en) 并在您的 Google 帐户上启用 2FA。您将无法直接使用您的 Google 帐户密码。
|
|
|
@ -1,59 +0,0 @@
|
||||||
---
|
|
||||||
date: "2017-04-08T11:34:00+02:00"
|
|
||||||
title: "Environment variables"
|
|
||||||
slug: "environment-variables"
|
|
||||||
sidebar_position: 10
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/environment-variables
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Environment variables"
|
|
||||||
sidebar_position: 10
|
|
||||||
identifier: "environment-variables"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Environment variables
|
|
||||||
|
|
||||||
This is an inventory of Gitea environment variables. They change Gitea behaviour.
|
|
||||||
|
|
||||||
Initialize them before Gitea command to be effective, for example:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
GITEA_CUSTOM=/home/gitea/custom ./gitea web
|
|
||||||
```
|
|
||||||
|
|
||||||
## From Go language
|
|
||||||
|
|
||||||
As Gitea is written in Go, it uses some variables that influence the behaviour of Go's runtime, such as:
|
|
||||||
|
|
||||||
- `GOMEMLIMIT`
|
|
||||||
- `GOGC`
|
|
||||||
- `GOMAXPROCS`
|
|
||||||
- `GODEBUG`
|
|
||||||
|
|
||||||
For documentation about each of the variables available, refer to the
|
|
||||||
[official Go documentation on runtime environment variables](https://pkg.go.dev/runtime#hdr-Environment_Variables).
|
|
||||||
|
|
||||||
## Gitea files
|
|
||||||
|
|
||||||
- `GITEA_WORK_DIR`: Absolute path of working directory.
|
|
||||||
- `GITEA_CUSTOM`: Gitea uses `WorkPath`/custom folder by default. Use this variable to change _custom_ directory.
|
|
||||||
|
|
||||||
## Operating system specifics
|
|
||||||
|
|
||||||
- `USER`: System user that Gitea will run as. Used for some repository access strings.
|
|
||||||
- `USERNAME`: if no `USER` found, Gitea will use `USERNAME`
|
|
||||||
- `HOME`: User home directory path. The `USERPROFILE` environment variable is used in Windows.
|
|
||||||
|
|
||||||
### Only on Windows
|
|
||||||
|
|
||||||
- `USERPROFILE`: User home directory path. If empty, uses `HOMEDRIVE` + `HOMEPATH`
|
|
||||||
- `HOMEDRIVE`: Main drive path used to access the home directory (C:)
|
|
||||||
- `HOMEPATH`: Home relative path in the given home drive path
|
|
||||||
|
|
||||||
## Miscellaneous
|
|
||||||
|
|
||||||
- `SKIP_MINWINSVC`: If set to 1, do not run as a service on Windows.
|
|
|
@ -1,57 +0,0 @@
|
||||||
---
|
|
||||||
date: "2017-04-08T11:34:00+02:00"
|
|
||||||
title: "环境变量清单"
|
|
||||||
slug: "environment-variables"
|
|
||||||
sidebar_position: 10
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/environment-variables
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "环境变量清单"
|
|
||||||
sidebar_position: 10
|
|
||||||
identifier: "environment-variables"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 环境变量清单
|
|
||||||
|
|
||||||
这里是用来控制 Gitea 行为表现的的环境变量清单,您需要在执行如下 Gitea 启动命令前设置它们来确保配置生效:
|
|
||||||
|
|
||||||
```
|
|
||||||
GITEA_CUSTOM=/home/gitea/custom ./gitea web
|
|
||||||
```
|
|
||||||
|
|
||||||
## Go 的配置
|
|
||||||
|
|
||||||
因为 Gitea 使用 Go 语言编写,因此它使用了一些相关的 Go 的配置参数:
|
|
||||||
|
|
||||||
* `GOOS`
|
|
||||||
* `GOARCH`
|
|
||||||
* [`GOPATH`](https://go.dev/cmd/go/#hdr-GOPATH_environment_variable)
|
|
||||||
|
|
||||||
您可以在[官方文档](https://go.dev/cmd/go/#hdr-Environment_variables)中查阅这些配置参数的详细信息。
|
|
||||||
|
|
||||||
## Gitea 的文件目录
|
|
||||||
|
|
||||||
* `GITEA_WORK_DIR`:工作目录的绝对路径
|
|
||||||
* `GITEA_CUSTOM`:默认情况下 Gitea 使用默认目录 `GITEA_WORK_DIR`/custom,您可以使用这个参数来配置 *custom* 目录
|
|
||||||
* `GOGS_WORK_DIR`: 已废弃,请使用 `GITEA_WORK_DIR` 替代
|
|
||||||
* `GOGS_CUSTOM`: 已废弃,请使用 `GITEA_CUSTOM` 替代
|
|
||||||
|
|
||||||
## 操作系统配置
|
|
||||||
|
|
||||||
* `USER`:Gitea 运行时使用的系统用户,它将作为一些 repository 的访问地址的一部分
|
|
||||||
* `USERNAME`: 如果没有配置 `USER`, Gitea 将使用 `USERNAME`
|
|
||||||
* `HOME`: 用户的 home 目录,在 Windows 中会使用 `USERPROFILE` 环境变量
|
|
||||||
|
|
||||||
### 仅限于 Windows 的配置
|
|
||||||
|
|
||||||
* `USERPROFILE`: 用户的主目录,如果未配置则会使用 `HOMEDRIVE` + `HOMEPATH`
|
|
||||||
* `HOMEDRIVE`: 用于访问 home 目录的主驱动器路径(C盘)
|
|
||||||
* `HOMEPATH`:在指定主驱动器下的 home 目录相对路径
|
|
||||||
|
|
||||||
## Miscellaneous
|
|
||||||
|
|
||||||
* `SKIP_MINWINSVC`:如果设置为 1,在 Windows 上不会以 service 的形式运行。
|
|
|
@ -1,194 +0,0 @@
|
||||||
---
|
|
||||||
date: "2018-11-23:00:00+02:00"
|
|
||||||
title: "External renderers"
|
|
||||||
slug: "external-renderers"
|
|
||||||
sidebar_position: 60
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/external-renderers
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "External renderers"
|
|
||||||
sidebar_position: 60
|
|
||||||
identifier: "external-renderers"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Custom files rendering configuration
|
|
||||||
|
|
||||||
Gitea supports custom file renderings (i.e., Jupyter notebooks, asciidoc, etc.) through external binaries,
|
|
||||||
it is just a matter of:
|
|
||||||
|
|
||||||
- installing external binaries
|
|
||||||
- add some configuration to your `app.ini` file
|
|
||||||
- restart your Gitea instance
|
|
||||||
|
|
||||||
This supports rendering of whole files. If you want to render code blocks in markdown you would need to do something with javascript. See some examples on the [Customizing Gitea](administration/customizing-gitea.md) page.
|
|
||||||
|
|
||||||
## Installing external binaries
|
|
||||||
|
|
||||||
In order to get file rendering through external binaries, their associated packages must be installed.
|
|
||||||
If you're using a Docker image, your `Dockerfile` should contain something along this lines:
|
|
||||||
|
|
||||||
```docker
|
|
||||||
FROM gitea/gitea:@version@
|
|
||||||
[...]
|
|
||||||
|
|
||||||
COPY custom/app.ini /data/gitea/conf/app.ini
|
|
||||||
[...]
|
|
||||||
|
|
||||||
RUN apk --no-cache add asciidoctor freetype freetype-dev gcc g++ libpng libffi-dev py-pip python3-dev py3-pip py3-pyzmq
|
|
||||||
# install any other package you need for your external renderers
|
|
||||||
|
|
||||||
RUN pip3 install --upgrade pip
|
|
||||||
RUN pip3 install -U setuptools
|
|
||||||
RUN pip3 install jupyter docutils
|
|
||||||
# add above any other python package you may need to install
|
|
||||||
```
|
|
||||||
|
|
||||||
## `app.ini` file configuration
|
|
||||||
|
|
||||||
add one `[markup.XXXXX]` section per external renderer on your custom `app.ini`:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[markup.asciidoc]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .adoc,.asciidoc
|
|
||||||
RENDER_COMMAND = "asciidoctor -s -a showtitle --out-file=- -"
|
|
||||||
; Input is not a standard input but a file
|
|
||||||
IS_INPUT_FILE = false
|
|
||||||
|
|
||||||
[markup.jupyter]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .ipynb
|
|
||||||
RENDER_COMMAND = "jupyter nbconvert --stdin --stdout --to html --template basic"
|
|
||||||
IS_INPUT_FILE = false
|
|
||||||
|
|
||||||
[markup.restructuredtext]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .rst
|
|
||||||
RENDER_COMMAND = "timeout 30s pandoc +RTS -M512M -RTS -f rst"
|
|
||||||
IS_INPUT_FILE = false
|
|
||||||
```
|
|
||||||
|
|
||||||
If your external markup relies on additional classes and attributes on the generated HTML elements, you might need to enable custom sanitizer policies. Gitea uses the [`bluemonday`](https://godoc.org/github.com/microcosm-cc/bluemonday) package as our HTML sanitizer. The example below could be used to support server-side [KaTeX](https://katex.org/) rendering output from [`pandoc`](https://pandoc.org/).
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[markup.sanitizer.TeX]
|
|
||||||
; Pandoc renders TeX segments as <span>s with the "math" class, optionally
|
|
||||||
; with "inline" or "display" classes depending on context.
|
|
||||||
; - note this is different from the built-in math support in our markdown parser which uses <code>
|
|
||||||
ELEMENT = span
|
|
||||||
ALLOW_ATTR = class
|
|
||||||
REGEXP = ^\s*((math(\s+|$)|inline(\s+|$)|display(\s+|$)))+
|
|
||||||
|
|
||||||
[markup.markdown]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .md,.markdown
|
|
||||||
RENDER_COMMAND = pandoc -f markdown -t html --katex
|
|
||||||
```
|
|
||||||
|
|
||||||
You must define `ELEMENT` and `ALLOW_ATTR` in each section.
|
|
||||||
|
|
||||||
To define multiple entries, add a unique alphanumeric suffix (e.g., `[markup.sanitizer.1]` and `[markup.sanitizer.something]`).
|
|
||||||
|
|
||||||
To apply a sanitisation rules only for a specify external renderer they must use the renderer name, e.g. `[markup.sanitizer.asciidoc.rule-1]`, `[markup.sanitizer.<renderer>.rule-1]`.
|
|
||||||
|
|
||||||
**Note**: If the rule is defined above the renderer ini section or the name does not match a renderer it is applied to every renderer.
|
|
||||||
|
|
||||||
Once your configuration changes have been made, restart Gitea to have changes take effect.
|
|
||||||
|
|
||||||
**Note**: Prior to Gitea 1.12 there was a single `markup.sanitiser` section with keys that were redefined for multiple rules, however,
|
|
||||||
there were significant problems with this method of configuration necessitating configuration through multiple sections.
|
|
||||||
|
|
||||||
### Example: HTML
|
|
||||||
|
|
||||||
Render HTML files directly:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[markup.html]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .html,.htm
|
|
||||||
RENDER_COMMAND = cat
|
|
||||||
; Input is not a standard input but a file
|
|
||||||
IS_INPUT_FILE = true
|
|
||||||
|
|
||||||
[markup.sanitizer.html.1]
|
|
||||||
ELEMENT = div
|
|
||||||
ALLOW_ATTR = class
|
|
||||||
|
|
||||||
[markup.sanitizer.html.2]
|
|
||||||
ELEMENT = a
|
|
||||||
ALLOW_ATTR = class
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example: Office DOCX
|
|
||||||
|
|
||||||
Display Office DOCX files with [`pandoc`](https://pandoc.org/):
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[markup.docx]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .docx
|
|
||||||
RENDER_COMMAND = "pandoc --from docx --to html --self-contained --template /path/to/basic.html"
|
|
||||||
|
|
||||||
[markup.sanitizer.docx.img]
|
|
||||||
ALLOW_DATA_URI_IMAGES = true
|
|
||||||
```
|
|
||||||
|
|
||||||
The template file has the following content:
|
|
||||||
|
|
||||||
```
|
|
||||||
$body$
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example: Jupyter Notebook
|
|
||||||
|
|
||||||
Display Jupyter Notebook files with [`nbconvert`](https://github.com/jupyter/nbconvert):
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[markup.jupyter]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .ipynb
|
|
||||||
RENDER_COMMAND = "jupyter-nbconvert --stdin --stdout --to html --template basic"
|
|
||||||
|
|
||||||
[markup.sanitizer.jupyter.img]
|
|
||||||
ALLOW_DATA_URI_IMAGES = true
|
|
||||||
```
|
|
||||||
|
|
||||||
## Customizing CSS
|
|
||||||
|
|
||||||
The external renderer is specified in the .ini in the format `[markup.XXXXX]` and the HTML supplied by your external renderer will be wrapped in a `<div>` with classes `markup` and `XXXXX`. The `markup` class provides out of the box styling (as does `markdown` if `XXXXX` is `markdown`). Otherwise you can use these classes to specifically target the contents of your rendered HTML.
|
|
||||||
|
|
||||||
And so you could write some CSS:
|
|
||||||
|
|
||||||
```css
|
|
||||||
.markup.XXXXX html {
|
|
||||||
font-size: 100%;
|
|
||||||
overflow-y: scroll;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
-ms-text-size-adjust: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markup.XXXXX body {
|
|
||||||
color: #444;
|
|
||||||
font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1.7;
|
|
||||||
padding: 1em;
|
|
||||||
margin: auto;
|
|
||||||
max-width: 42em;
|
|
||||||
background: #fefefe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markup.XXXXX p {
|
|
||||||
color: orangered;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Add your stylesheet to your custom directory e.g `custom/public/assets/css/my-style-XXXXX.css` and import it using a custom header file `custom/templates/custom/header.tmpl`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="{{AppSubUrl}}/assets/css/my-style-XXXXX.css" />
|
|
||||||
```
|
|
|
@ -1,203 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "外部渲染器"
|
|
||||||
slug: "external-renderers"
|
|
||||||
sidebar_position: 60
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/external-renderers
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "外部渲染器"
|
|
||||||
sidebar_position: 60
|
|
||||||
identifier: "external-renderers"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 自定义文件渲染配置
|
|
||||||
|
|
||||||
Gitea 通过外部二进制文件支持自定义文件渲染(例如 Jupyter notebooks、asciidoc 等),只需要进行以下步骤:
|
|
||||||
|
|
||||||
- 安装外部二进制文件
|
|
||||||
- 在您的 `app.ini` 文件中添加一些配置
|
|
||||||
- 重新启动 Gitea 实例
|
|
||||||
|
|
||||||
此功能支持整个文件的渲染。如果您想要在 Markdown 中渲染代码块,您需要使用 JavaScript 进行一些操作。请参阅 [自定义 Gitea 配置](administration/customizing-gitea.md) 页面上的一些示例。
|
|
||||||
|
|
||||||
## 安装外部二进制文件
|
|
||||||
|
|
||||||
为了通过外部二进制文件进行文件渲染,必须安装它们的关联软件包。
|
|
||||||
如果您正在使用 Docker 镜像,则您的 `Dockerfile` 应该包含以下内容:
|
|
||||||
|
|
||||||
```docker
|
|
||||||
FROM gitea/gitea:@version@
|
|
||||||
[...]
|
|
||||||
|
|
||||||
COPY custom/app.ini /data/gitea/conf/app.ini
|
|
||||||
[...]
|
|
||||||
|
|
||||||
RUN apk --no-cache add asciidoctor freetype freetype-dev gcc g++ libpng libffi-dev py-pip python3-dev py3-pip py3-pyzmq
|
|
||||||
# 安装其他您需要的外部渲染器的软件包
|
|
||||||
|
|
||||||
RUN pip3 install --upgrade pip
|
|
||||||
RUN pip3 install -U setuptools
|
|
||||||
RUN pip3 install jupyter docutils
|
|
||||||
# 在上面添加您需要安装的任何其他 Python 软件包
|
|
||||||
```
|
|
||||||
|
|
||||||
## `app.ini` 文件配置
|
|
||||||
|
|
||||||
在您的自定义 `app.ini` 文件中为每个外部渲染器添加一个 `[markup.XXXXX]` 部分:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[markup.asciidoc]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .adoc,.asciidoc
|
|
||||||
RENDER_COMMAND = "asciidoctor -s -a showtitle --out-file=- -"
|
|
||||||
; 输入不是标准输入而是文件
|
|
||||||
IS_INPUT_FILE = false
|
|
||||||
|
|
||||||
[markup.jupyter]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .ipynb
|
|
||||||
RENDER_COMMAND = "jupyter nbconvert --stdin --stdout --to html --template basic"
|
|
||||||
IS_INPUT_FILE = false
|
|
||||||
|
|
||||||
[markup.restructuredtext]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .rst
|
|
||||||
RENDER_COMMAND = "timeout 30s pandoc +RTS -M512M -RTS -f rst"
|
|
||||||
IS_INPUT_FILE = false
|
|
||||||
```
|
|
||||||
|
|
||||||
如果您的外部标记语言依赖于在生成的 HTML 元素上的额外类和属性,您可能需要启用自定义的清理策略。Gitea 使用 [`bluemonday`](https://godoc.org/github.com/microcosm-cc/bluemonday) 包作为我们的 HTML 清理器。下面的示例可以用于支持从 [`pandoc`](https://pandoc.org/) 输出的服务器端 [KaTeX](https://katex.org/) 渲染结果。
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[markup.sanitizer.TeX]
|
|
||||||
; Pandoc 渲染 TeX 段落为带有 "math" 类的 <span> 元素,根据上下文可能还带有 "inline" 或 "display" 类。
|
|
||||||
; - 请注意,这与我们的 Markdown 解析器中内置的数学支持不同,后者使用 <code> 元素。
|
|
||||||
ELEMENT = span
|
|
||||||
ALLOW_ATTR = class
|
|
||||||
REGEXP = ^\s*((math(\s+|$)|inline(\s+|$)|display(\s+|$)))+
|
|
||||||
|
|
||||||
[markup.markdown]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .md,.markdown
|
|
||||||
RENDER_COMMAND = pandoc -f markdown -t html --katex
|
|
||||||
```
|
|
||||||
|
|
||||||
您必须在每个部分中定义 `ELEMENT` 和 `ALLOW_ATTR`。
|
|
||||||
|
|
||||||
要定义多个条目,请添加唯一的字母数字后缀(例如,`[markup.sanitizer.1]` 和 `[markup.sanitizer.something]`)。
|
|
||||||
|
|
||||||
要仅为特定的外部渲染器应用清理规则,它们必须使用渲染器名称,例如 `[markup.sanitizer.asciidoc.rule-1]`、`[markup.sanitizer.<renderer>.rule-1]`。
|
|
||||||
|
|
||||||
**注意**:如果规则在渲染器 ini 部分之前定义,或者名称与渲染器不匹配,它将应用于所有渲染器。
|
|
||||||
|
|
||||||
完成配置更改后,请重新启动 Gitea 以使更改生效。
|
|
||||||
|
|
||||||
**注意**:在 Gitea 1.12 之前,存在一个名为 `markup.sanitiser` 的单个部分,其中的键被重新定义为多个规则,但是,这种配置方法存在重大问题,需要通过多个部分进行配置。
|
|
||||||
|
|
||||||
### 示例:HTML
|
|
||||||
|
|
||||||
直接渲染 HTML 文件:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[markup.html]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .html,.htm
|
|
||||||
RENDER_COMMAND = cat
|
|
||||||
; 输入不是标准输入,而是文件
|
|
||||||
IS_INPUT_FILE = true
|
|
||||||
|
|
||||||
[markup.sanitizer.html.1]
|
|
||||||
ELEMENT = div
|
|
||||||
ALLOW_ATTR = class
|
|
||||||
|
|
||||||
[markup.sanitizer.html.2]
|
|
||||||
ELEMENT = a
|
|
||||||
ALLOW_ATTR = class
|
|
||||||
```
|
|
||||||
|
|
||||||
请注意:此示例中的配置将允许渲染 HTML 文件,并使用 `cat` 命令将文件内容输出为 HTML。此外,配置中的两个清理规则将允许 `<div>` 和 `<a>` 元素使用 `class` 属性。
|
|
||||||
|
|
||||||
在进行配置更改后,请重新启动 Gitea 以使更改生效。
|
|
||||||
|
|
||||||
### 示例:Office DOCX
|
|
||||||
|
|
||||||
使用 [`pandoc`](https://pandoc.org/) 显示 Office DOCX 文件:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[markup.docx]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .docx
|
|
||||||
RENDER_COMMAND = "pandoc --from docx --to html --self-contained --template /path/to/basic.html"
|
|
||||||
|
|
||||||
[markup.sanitizer.docx.img]
|
|
||||||
ALLOW_DATA_URI_IMAGES = true
|
|
||||||
```
|
|
||||||
|
|
||||||
在此示例中,配置将允许显示 Office DOCX 文件,并使用 `pandoc` 命令将文件转换为 HTML 格式。同时,清理规则中的 `ALLOW_DATA_URI_IMAGES` 设置为 `true`,允许使用 Data URI 格式的图片。
|
|
||||||
|
|
||||||
模板文件的内容如下:
|
|
||||||
|
|
||||||
```
|
|
||||||
$body$
|
|
||||||
```
|
|
||||||
|
|
||||||
### 示例:Jupyter Notebook
|
|
||||||
|
|
||||||
使用 [`nbconvert`](https://github.com/jupyter/nbconvert) 显示 Jupyter Notebook 文件:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[markup.jupyter]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .ipynb
|
|
||||||
RENDER_COMMAND = "jupyter-nbconvert --stdin --stdout --to html --template basic"
|
|
||||||
|
|
||||||
[markup.sanitizer.jupyter.img]
|
|
||||||
ALLOW_DATA_URI_IMAGES = true
|
|
||||||
```
|
|
||||||
|
|
||||||
在此示例中,配置将允许显示 Jupyter Notebook 文件,并使用 `nbconvert` 命令将文件转换为 HTML 格式。同样,清理规则中的 `ALLOW_DATA_URI_IMAGES` 设置为 `true`,允许使用 Data URI 格式的图片。
|
|
||||||
|
|
||||||
在进行配置更改后,请重新启动 Gitea 以使更改生效。
|
|
||||||
|
|
||||||
## 自定义 CSS
|
|
||||||
|
|
||||||
在 `.ini` 文件中,可以使用 `[markup.XXXXX]` 的格式指定外部渲染器,并且由外部渲染器生成的 HTML 将被包装在一个带有 `markup` 和 `XXXXX` 类的 `<div>` 中。`markup` 类提供了预定义的样式(如果 `XXXXX` 是 `markdown`,则使用 `markdown` 类)。否则,您可以使用这些类来针对渲染的 HTML 内容进行定制样式。
|
|
||||||
|
|
||||||
因此,您可以编写一些 CSS 样式:
|
|
||||||
|
|
||||||
```css
|
|
||||||
.markup.XXXXX html {
|
|
||||||
font-size: 100%;
|
|
||||||
overflow-y: scroll;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
-ms-text-size-adjust: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markup.XXXXX body {
|
|
||||||
color: #444;
|
|
||||||
font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1.7;
|
|
||||||
padding: 1em;
|
|
||||||
margin: auto;
|
|
||||||
max-width: 42em;
|
|
||||||
background: #fefefe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markup.XXXXX p {
|
|
||||||
color: orangered;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
将您的样式表添加到自定义目录中,例如 `custom/public/assets/css/my-style-XXXXX.css`,并使用自定义的头文件 `custom/templates/custom/header.tmpl` 进行导入:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="{{AppSubUrl}}/assets/css/my-style-XXXXX.css" />
|
|
||||||
```
|
|
||||||
|
|
||||||
通过以上步骤,您可以将自定义的 CSS 样式应用到特定的外部渲染器,使其具有所需的样式效果。
|
|
|
@ -1,127 +0,0 @@
|
||||||
---
|
|
||||||
date: "2018-05-11T11:00:00+02:00"
|
|
||||||
title: "Fail2ban Setup "
|
|
||||||
slug: "fail2ban-setup"
|
|
||||||
sidebar_position: 16
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/fail2ban-setup
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Fail2ban setup"
|
|
||||||
sidebar_position: 16
|
|
||||||
identifier: "fail2ban-setup"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Fail2ban setup to block users after failed login attempts
|
|
||||||
|
|
||||||
**Remember that fail2ban is powerful and can cause lots of issues if you do it incorrectly, so make
|
|
||||||
sure to test this before relying on it so you don't lock yourself out.**
|
|
||||||
|
|
||||||
Gitea returns an HTTP 200 for bad logins in the web logs, but if you have logging options on in
|
|
||||||
`app.ini`, then you should be able to go off of `log/gitea.log`, which gives you something like this
|
|
||||||
on a bad authentication from the web or CLI using SSH or HTTP respectively:
|
|
||||||
|
|
||||||
```log
|
|
||||||
2018/04/26 18:15:54 [I] Failed authentication attempt for user from xxx.xxx.xxx.xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
```log
|
|
||||||
2020/10/15 16:05:09 modules/ssh/ssh.go:143:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.)
|
|
||||||
|
|
||||||
```log
|
|
||||||
2020/10/15 16:05:09 modules/ssh/ssh.go:155:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.)
|
|
||||||
|
|
||||||
```log
|
|
||||||
2020/10/15 16:05:09 modules/ssh/ssh.go:198:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.)
|
|
||||||
|
|
||||||
```log
|
|
||||||
2020/10/15 16:05:09 modules/ssh/ssh.go:213:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.)
|
|
||||||
|
|
||||||
```log
|
|
||||||
2020/10/15 16:05:09 modules/ssh/ssh.go:227:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.)
|
|
||||||
|
|
||||||
```log
|
|
||||||
2020/10/15 16:05:09 modules/ssh/ssh.go:249:sshConnectionFailed() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
(From 1.15 this new message will available and doesn't have any of the false positive results that above messages from publicKeyHandler do. This will only be logged if the user has completely failed authentication.)
|
|
||||||
|
|
||||||
```log
|
|
||||||
2020/10/15 16:08:44 ...s/context/context.go:204:HandleText() [E] invalid credentials from xxx.xxx.xxx.xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
Add our filter in `/etc/fail2ban/filter.d/gitea.conf`:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
# gitea.conf
|
|
||||||
[Definition]
|
|
||||||
failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
|
|
||||||
ignoreregex =
|
|
||||||
```
|
|
||||||
|
|
||||||
Add our jail in `/etc/fail2ban/jail.d/gitea.conf`:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[gitea]
|
|
||||||
enabled = true
|
|
||||||
filter = gitea
|
|
||||||
logpath = /var/lib/gitea/log/gitea.log
|
|
||||||
maxretry = 10
|
|
||||||
findtime = 3600
|
|
||||||
bantime = 900
|
|
||||||
action = iptables-allports
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're using Docker, you'll also need to add an additional jail to handle the **FORWARD**
|
|
||||||
chain in **iptables**. Configure it in `/etc/fail2ban/jail.d/gitea-docker.conf`:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[gitea-docker]
|
|
||||||
enabled = true
|
|
||||||
filter = gitea
|
|
||||||
logpath = /var/lib/gitea/log/gitea.log
|
|
||||||
maxretry = 10
|
|
||||||
findtime = 3600
|
|
||||||
bantime = 900
|
|
||||||
action = iptables-allports[chain="FORWARD"]
|
|
||||||
```
|
|
||||||
|
|
||||||
Then simply run `service fail2ban restart` to apply your changes. You can check to see if
|
|
||||||
fail2ban has accepted your configuration using `service fail2ban status`.
|
|
||||||
|
|
||||||
Make sure and read up on fail2ban and configure it to your needs, this bans someone
|
|
||||||
for **15 minutes** (from all ports) when they fail authentication 10 times in an hour.
|
|
||||||
|
|
||||||
If you run Gitea behind a reverse proxy with Nginx (for example with Docker), you need to add
|
|
||||||
this to your Nginx configuration so that IPs don't show up as 127.0.0.1:
|
|
||||||
|
|
||||||
```
|
|
||||||
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](administration/config-cheat-sheet.md#security-security) for more information).
|
|
||||||
|
|
||||||
```
|
|
||||||
REVERSE_PROXY_LIMIT = 1
|
|
||||||
REVERSE_PROXY_TRUSTED_PROXIES = 127.0.0.1/8 ; 172.17.0.0/16 for the docker default network
|
|
||||||
```
|
|
|
@ -1,94 +0,0 @@
|
||||||
---
|
|
||||||
date: "2022-08-01T00:00:00+00:00"
|
|
||||||
title: "设置 Fail2ban"
|
|
||||||
slug: "fail2ban-setup"
|
|
||||||
sidebar_position: 16
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/fail2ban-setup
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "设置 Fail2ban"
|
|
||||||
sidebar_position: 16
|
|
||||||
identifier: "fail2ban-setup"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 使用 Fail2ban 阻止攻击者的暴力登录
|
|
||||||
|
|
||||||
**Fail2ban 检查客户端登录日志,将多次登录失败的客户端识别为攻击者并在一段时间内阻止其访问服务。如果你的实例是公开的,这一点尤其重要。请管理员仔细设置 fail2ban,错误的配置将导致防火墙阻止你访问自己的服务器。**
|
|
||||||
|
|
||||||
Gitea 会在日志文件 `log/gitea.log` 中记录登录失败的 CLI、SSH 或 HTTP 客户端 IP 地址,而你需要将 Gitea 的日志输出模式从默认的 `console` 更改为 `file`。这表示将日志输出到文件,使得 fail2ban 可以定期扫描日志内容。
|
|
||||||
|
|
||||||
当用户的身份验证失败时,日志中会记录此类信息:
|
|
||||||
|
|
||||||
```log
|
|
||||||
2018/04/26 18:15:54 [I] Failed authentication attempt for user from xxx.xxx.xxx.xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
```log
|
|
||||||
2020/10/15 16:08:44 [E] invalid credentials from xxx.xxx.xxx.xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
## 设置 Fail2ban
|
|
||||||
|
|
||||||
添加日志过滤器规则到配置文件 `/etc/fail2ban/filter.d/gitea.conf`:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[Definition]
|
|
||||||
failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
|
|
||||||
ignoreregex =
|
|
||||||
```
|
|
||||||
|
|
||||||
添加监狱规则到配置文件 `/etc/fail2ban/jail.d/gitea.conf`:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[gitea]
|
|
||||||
enabled = true
|
|
||||||
filter = gitea
|
|
||||||
logpath = /var/lib/gitea/log/gitea.log
|
|
||||||
maxretry = 10
|
|
||||||
findtime = 3600
|
|
||||||
bantime = 900
|
|
||||||
action = iptables-allports
|
|
||||||
```
|
|
||||||
|
|
||||||
如果你的 Gitea 实例运行在 Docker 容器中,并且直接将容器端口暴露到外部网络,
|
|
||||||
你还需要添加 `chain="FORWARD"` 到监狱规则配置文件 `/etc/fail2ban/jail.d/gitea-docker.conf`
|
|
||||||
以适应 Docker 的网络转发规则。但如果你在容器的宿主机上使用 Nginx 反向代理连接到 Gitea 则无需这样配置。
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[gitea-docker]
|
|
||||||
enabled = true
|
|
||||||
filter = gitea
|
|
||||||
logpath = /var/lib/gitea/log/gitea.log
|
|
||||||
maxretry = 10
|
|
||||||
findtime = 3600
|
|
||||||
bantime = 900
|
|
||||||
action = iptables-allports[chain="FORWARD"]
|
|
||||||
```
|
|
||||||
|
|
||||||
最后,运行 `systemctl restart fail2ban` 即可应用更改。现在,你可以使用 `systemctl status fail2ban` 检查 fail2ban 运行状态。
|
|
||||||
|
|
||||||
上述规则规定客户端在 1 小时内,如果登录失败的次数达到 10 次,则通过 iptables 锁定该客户端 IP 地址 15 分钟。
|
|
||||||
|
|
||||||
## 设置反向代理
|
|
||||||
|
|
||||||
如果你使用 Nginx 反向代理到 Gitea 实例,你还需要设置 Nginx 的 HTTP 头部值 `X-Real-IP` 将真实的客户端 IP 地址传递给 Gitea。否则 Gitea 程序会将客户端地址错误解析为反向代理服务器的地址,例如回环地址 `127.0.0.1`。
|
|
||||||
|
|
||||||
```
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
```
|
|
||||||
|
|
||||||
额外注意,在 Gitea 的配置文件 `app.ini` 中存在下列默认值:
|
|
||||||
|
|
||||||
```
|
|
||||||
REVERSE_PROXY_LIMIT = 1
|
|
||||||
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](administration/config-cheat-sheet.md#security-security))
|
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-10-06T08:00:00+05:00"
|
|
||||||
title: "Git LFS setup"
|
|
||||||
slug: "git-lfs-setup"
|
|
||||||
sidebar_position: 12
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/git-lfs-setup
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Git LFS setup"
|
|
||||||
sidebar_position: 12
|
|
||||||
identifier: "git-lfs-setup"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Git Large File Storage setup
|
|
||||||
|
|
||||||
To use Gitea's built-in LFS support, you must update the `app.ini` file:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[server]
|
|
||||||
; Enables git-lfs support. true or false, default is false.
|
|
||||||
LFS_START_SERVER = true
|
|
||||||
|
|
||||||
[lfs]
|
|
||||||
; Where your lfs files reside, default is data/lfs.
|
|
||||||
PATH = /home/gitea/data/lfs
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note**: LFS server support needs at least Git v2.1.2 installed on the server
|
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "Git LFS 设置"
|
|
||||||
slug: "git-lfs-setup"
|
|
||||||
sidebar_position: 12
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/git-lfs-setup
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Git LFS 设置"
|
|
||||||
sidebar_position: 12
|
|
||||||
identifier: "git-lfs-setup"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 配置 Git 大文件存储(Large File Storage,LFS)
|
|
||||||
|
|
||||||
要使用 Gitea 内置的 LFS 支持,您需要更新 `app.ini` 文件:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[server]
|
|
||||||
; 启用 git-lfs 支持。true 或 false,默认为 false。
|
|
||||||
LFS_START_SERVER = true
|
|
||||||
|
|
||||||
[lfs]
|
|
||||||
; 存放 LFS 文件的路径,默认为 data/lfs。
|
|
||||||
PATH = /home/gitea/data/lfs
|
|
||||||
```
|
|
||||||
|
|
||||||
**注意**:LFS 服务器支持需要服务器上安装 Git v2.1.2 以上版本。
|
|
|
@ -1,100 +0,0 @@
|
||||||
---
|
|
||||||
date: "2018-06-02T11:00:00+02:00"
|
|
||||||
title: "HTTPS setup"
|
|
||||||
slug: "https-setup"
|
|
||||||
sidebar_position: 12
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/https-setup
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "HTTPS setup"
|
|
||||||
sidebar_position: 12
|
|
||||||
identifier: "https-setup"
|
|
||||||
---
|
|
||||||
|
|
||||||
# HTTPS setup to encrypt connections to Gitea
|
|
||||||
|
|
||||||
## Using the built-in server
|
|
||||||
|
|
||||||
Before you enable HTTPS, make sure that you have valid SSL/TLS certificates.
|
|
||||||
You could use self-generated certificates for evaluation and testing. Please run `gitea cert --host [HOST]` to generate a self signed certificate.
|
|
||||||
|
|
||||||
If you are using Apache or nginx on the server, it's recommended to check the [reverse proxy guide](administration/reverse-proxies.md).
|
|
||||||
|
|
||||||
To use Gitea's built-in HTTPS support, you must change your `app.ini` file:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[server]
|
|
||||||
PROTOCOL = https
|
|
||||||
ROOT_URL = https://git.example.com:3000/
|
|
||||||
HTTP_PORT = 3000
|
|
||||||
CERT_FILE = cert.pem
|
|
||||||
KEY_FILE = key.pem
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that if your certificate is signed by a third party certificate authority (i.e. not self-signed), then cert.pem should contain the certificate chain. The server certificate must be the first entry in cert.pem, followed by the intermediaries in order (if any). The root certificate does not have to be included because the connecting client must already have it in order to estalbish the trust relationship.
|
|
||||||
To learn more about the config values, please checkout the [Config Cheat Sheet](administration/config-cheat-sheet.md#server-server).
|
|
||||||
|
|
||||||
For the `CERT_FILE` or `KEY_FILE` field, the file path is relative to the `GITEA_CUSTOM` environment variable when it is a relative path. It can be an absolute path as well.
|
|
||||||
|
|
||||||
### Setting up HTTP redirection
|
|
||||||
|
|
||||||
The Gitea server is only able to listen to one port; to redirect HTTP requests to the HTTPS port, you will need to enable the HTTP redirection service:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[server]
|
|
||||||
REDIRECT_OTHER_PORT = true
|
|
||||||
; Port the redirection service should listen on
|
|
||||||
PORT_TO_REDIRECT = 3080
|
|
||||||
```
|
|
||||||
|
|
||||||
If you are using Docker, make sure that this port is configured in your `docker-compose.yml` file.
|
|
||||||
|
|
||||||
## Using ACME (Default: Let's Encrypt)
|
|
||||||
|
|
||||||
[ACME](https://tools.ietf.org/html/rfc8555) is a Certificate Authority standard protocol that allows you to automatically request and renew SSL/TLS certificates. [Let's Encrypt](https://letsencrypt.org/) is a free publicly trusted Certificate Authority server using this standard. Only `HTTP-01` and `TLS-ALPN-01` challenges are implemented. In order for ACME challenges to pass and verify your domain ownership, external traffic to the gitea domain on port `80` (`HTTP-01`) or port `443` (`TLS-ALPN-01`) has to be served by the gitea instance. Setting up [HTTP redirection](#setting-up-http-redirection) and port-forwards might be needed for external traffic to route correctly. Normal traffic to port `80` will otherwise be automatically redirected to HTTPS. **You must consent** to the ACME provider's terms of service (default Let's Encrypt's [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf)).
|
|
||||||
|
|
||||||
Minimum setup using the default Let's Encrypt:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[server]
|
|
||||||
PROTOCOL=https
|
|
||||||
DOMAIN=git.example.com
|
|
||||||
ENABLE_ACME=true
|
|
||||||
ACME_ACCEPTTOS=true
|
|
||||||
ACME_DIRECTORY=https
|
|
||||||
;; Email can be omitted here and provided manually at first run, after which it is cached
|
|
||||||
ACME_EMAIL=email@example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
Minimum setup using a [smallstep CA](https://github.com/smallstep/certificates), refer to [their tutorial](https://smallstep.com/docs/tutorials/acme-challenge) for more information.
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[server]
|
|
||||||
PROTOCOL=https
|
|
||||||
DOMAIN=git.example.com
|
|
||||||
ENABLE_ACME=true
|
|
||||||
ACME_ACCEPTTOS=true
|
|
||||||
ACME_URL=https://ca.example.com/acme/acme/directory
|
|
||||||
;; Can be omitted if using the system's trust is preferred
|
|
||||||
;ACME_CA_ROOT=/path/to/root_ca.crt
|
|
||||||
ACME_DIRECTORY=https
|
|
||||||
ACME_EMAIL=email@example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
To learn more about the config values, please checkout the [Config Cheat Sheet](administration/config-cheat-sheet.md#server-server).
|
|
||||||
|
|
||||||
## Using a reverse proxy
|
|
||||||
|
|
||||||
Setup up your reverse proxy as shown in the [reverse proxy guide](administration/reverse-proxies.md).
|
|
||||||
|
|
||||||
After that, enable HTTPS by following one of these guides:
|
|
||||||
|
|
||||||
- [nginx](https://nginx.org/en/docs/http/configuring_https_servers.html)
|
|
||||||
- [apache2/httpd](https://httpd.apache.org/docs/2.4/ssl/ssl_howto.html)
|
|
||||||
- [caddy](https://caddyserver.com/docs/tls)
|
|
||||||
|
|
||||||
Note: Enabling HTTPS only at the proxy level is referred as [TLS Termination Proxy](https://en.wikipedia.org/wiki/TLS_termination_proxy). The proxy server accepts incoming TLS connections, decrypts the contents, and passes the now unencrypted contents to Gitea. This is normally fine as long as both the proxy and Gitea instances are either on the same machine, or on different machines within private network (with the proxy is exposed to outside network). If your Gitea instance is separated from your proxy over a public network, or if you want full end-to-end encryption, you can also [enable HTTPS support directly in Gitea using built-in server](#using-the-built-in-server) and forward the connections over HTTPS instead.
|
|
|
@ -1,97 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-04-09T11:00:00+02:00"
|
|
||||||
title: "HTTPS配置"
|
|
||||||
slug: "https-setup"
|
|
||||||
sidebar_position: 12
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "HTTPS setup"
|
|
||||||
sidebar_position: 12
|
|
||||||
identifier: "https-setup"
|
|
||||||
---
|
|
||||||
|
|
||||||
# HTTPS setup to encrypt connections to Gitea
|
|
||||||
|
|
||||||
## 使用内置服务器
|
|
||||||
|
|
||||||
在启用HTTPS之前,确保您拥有有效的SSL/TLS证书。
|
|
||||||
建议在测试和评估情况下使用自签名证书,请运行 `gitea cert --host [HOST]` 以生成自签名证书
|
|
||||||
|
|
||||||
如果您在服务器上使用阿帕奇(Apache)或Nginx,建议参考 [反向代理指南](administration/reverse-proxies.md)。
|
|
||||||
|
|
||||||
要使用Gitea内置HTTPS支持,您必须编辑`app.ini`文件。
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[server]
|
|
||||||
PROTOCOL = https
|
|
||||||
ROOT_URL = https://git.example.com:3000/
|
|
||||||
HTTP_PORT = 3000
|
|
||||||
CERT_FILE = cert.pem
|
|
||||||
KEY_FILE = key.pem
|
|
||||||
```
|
|
||||||
|
|
||||||
请注意,如果您的证书由第三方证书颁发机构签名(即不是自签名的),则 cert.pem 应包含证书链。服务器证书必须是 cert.pem 中的第一个条目,后跟中介(如果有)。不必包含根证书,因为连接客户端必须已经拥有根证书才能建立信任关系。要了解有关配置值的更多信息,请查看 [配置备忘单](administration/config-cheat-sheet#server-server)。
|
|
||||||
|
|
||||||
对于“CERT_FILE”或“KEY_FILE”字段,当文件路径是相对路径时,文件路径相对于“GITEA_CUSTOM”环境变量。它也可以是绝对路径。
|
|
||||||
|
|
||||||
### 设置HTTP重定向
|
|
||||||
|
|
||||||
Gitea服务器仅支持监听一个端口;要重定向HTTP请求致HTTPS端口,您需要启用HTTP重定向服务:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[server]
|
|
||||||
REDIRECT_OTHER_PORT = true
|
|
||||||
; Port the redirection service should listen on
|
|
||||||
PORT_TO_REDIRECT = 3080
|
|
||||||
```
|
|
||||||
|
|
||||||
如果您使用Docker,确保端口已配置在 `docker-compose.yml` 文件
|
|
||||||
|
|
||||||
## 使用 ACME (默认: Let's Encrypt)
|
|
||||||
|
|
||||||
[ACME](https://tools.ietf.org/html/rfc8555) 是一种证书颁发机构标准协议,允许您自动请求和续订 SSL/TLS 证书。[Let`s Encrypt](https://letsencrypt.org/) 是使用此标准的免费公开信任的证书颁发机构服务器。仅实施“HTTP-01”和“TLS-ALPN-01”挑战。为了使 ACME 质询通过并验证您的域所有权,“80”端口(“HTTP-01”)或“443”端口(“TLS-ALPN-01”)上 gitea 域的外部流量必须由 gitea 实例提供服务。可能需要设置 [HTTP 重定向](#设置http重定向) 和端口转发才能正确路由外部流量。否则,到端口“80”的正常流量将自动重定向到 HTTPS。**您必须同意**ACME提供商的服务条款(默认为Let's Encrypt的 [服务条款](https://letsencrypt.org/documents/LE-SA-v1.2-2017年11月15日.pdf)。
|
|
||||||
|
|
||||||
使用默认 Let's Encrypt 的最小配置如下:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[server]
|
|
||||||
PROTOCOL=https
|
|
||||||
DOMAIN=git.example.com
|
|
||||||
ENABLE_ACME=true
|
|
||||||
ACME_ACCEPTTOS=true
|
|
||||||
ACME_DIRECTORY=https
|
|
||||||
;; Email can be omitted here and provided manually at first run, after which it is cached
|
|
||||||
ACME_EMAIL=email@example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
小型配置请使用 [smallstep CA](https://github.com/smallstep/certificates), 点击 [教程](https://smallstep.com/docs/tutorials/acme-challenge) 了解更多信息。
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[server]
|
|
||||||
PROTOCOL=https
|
|
||||||
DOMAIN=git.example.com
|
|
||||||
ENABLE_ACME=true
|
|
||||||
ACME_ACCEPTTOS=true
|
|
||||||
ACME_URL=https://ca.example.com/acme/acme/directory
|
|
||||||
;; Can be omitted if using the system's trust is preferred
|
|
||||||
;ACME_CA_ROOT=/path/to/root_ca.crt
|
|
||||||
ACME_DIRECTORY=https
|
|
||||||
ACME_EMAIL=email@example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
要了解关于配置, 请访问 [配置备忘单](administration/config-cheat-sheet.md#server-server)获取更多信息
|
|
||||||
|
|
||||||
## 使用反向代理服务器
|
|
||||||
|
|
||||||
按照 [reverse proxy guide](administration/reverse-proxies.md) 的规则设置你的反向代理服务器
|
|
||||||
|
|
||||||
然后,按照下面的向导启用 HTTPS:
|
|
||||||
|
|
||||||
- [nginx](https://nginx.org/en/docs/http/configuring_https_servers.html)
|
|
||||||
- [apache2/httpd](https://httpd.apache.org/docs/2.4/ssl/ssl_howto.html)
|
|
||||||
- [caddy](https://caddyserver.com/docs/tls)
|
|
||||||
|
|
||||||
注意:仅在代理层启用 HTTPS 被称为 [TLS 终止代理](https://en.wikipedia.org/wiki/TLS_termination_proxy)。代理服务器接受传入的 TLS 连接,解密内容,然后将现在未加密的内容传递给 Gitea。只要代理和 Gitea 实例在同一台计算机上或在私有网络中的不同计算机上(代理暴露给外部网络),这通常是可以接受的。如果您的 Gitea 实例与代理隔离在公共网络上,或者如果您想要全端到端的加密,您还可以直接在 Gitea 中 [启用内置服务器的 HTTPS 支持](#使用内置服务器),并将连接转发到 HTTPS 上。
|
|
|
@ -1,294 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-04-02T17:06:00+01:00"
|
|
||||||
title: "Logging Configuration"
|
|
||||||
slug: "logging-config"
|
|
||||||
sidebar_position: 40
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/logging-configuration
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Logging Configuration"
|
|
||||||
sidebar_position: 40
|
|
||||||
identifier: "logging-config"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Logging Configuration
|
|
||||||
|
|
||||||
The logging configuration of Gitea mainly consists of 3 types of components:
|
|
||||||
|
|
||||||
- The `[log]` section for general configuration
|
|
||||||
- `[log.<mode-name>]` sections for the configuration of different log writers to output logs, aka: "writer mode", the mode name is also used as "writer name".
|
|
||||||
- The `[log]` section can also contain sub-logger configurations following the key schema `logger.<logger-name>.<CONFIG-KEY>`
|
|
||||||
|
|
||||||
There is a fully functional log output by default, so it is not necessary to define one.
|
|
||||||
|
|
||||||
## Collecting Logs for Help
|
|
||||||
|
|
||||||
To collect logs for help and issue report, see [Support Options](help/support.md).
|
|
||||||
|
|
||||||
## The `[log]` section
|
|
||||||
|
|
||||||
Configuration of logging facilities in Gitea happen in the `[log]` section and its subsections.
|
|
||||||
|
|
||||||
In the top level `[log]` section the following configurations can be placed:
|
|
||||||
|
|
||||||
- `ROOT_PATH`: (Default: **%(GITEA_WORK_DIR)/log**): Base path for log files
|
|
||||||
- `MODE`: (Default: **console**) List of log outputs to use for the Default logger.
|
|
||||||
- `LEVEL`: (Default: **Info**) Least severe log events to persist, case-insensitive. Possible values are: `Trace`, `Debug`, `Info`, `Warn`, `Error`, `Fatal`.
|
|
||||||
- `STACKTRACE_LEVEL`: (Default: **None**) For this and more severe events the stacktrace will be printed upon getting logged.
|
|
||||||
|
|
||||||
And it can contain the following sub-loggers:
|
|
||||||
|
|
||||||
- `logger.router.MODE`: (Default: **,**): List of log outputs to use for the Router logger.
|
|
||||||
- `logger.access.MODE`: (Default: **_empty_**) List of log outputs to use for the Access logger. By default, the access logger is disabled.
|
|
||||||
- `logger.xorm.MODE`: (Default: **,**) List of log outputs to use for the XORM logger.
|
|
||||||
|
|
||||||
Setting a comma (`,`) to sub-logger's mode means making it use the default global `MODE`.
|
|
||||||
|
|
||||||
## Quick samples
|
|
||||||
|
|
||||||
### Default (empty) Configuration
|
|
||||||
|
|
||||||
The empty configuration is equivalent to default:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[log]
|
|
||||||
ROOT_PATH = %(GITEA_WORK_DIR)/log
|
|
||||||
MODE = console
|
|
||||||
LEVEL = Info
|
|
||||||
STACKTRACE_LEVEL = None
|
|
||||||
logger.router.MODE = ,
|
|
||||||
logger.xorm.MODE = ,
|
|
||||||
logger.access.MODE =
|
|
||||||
|
|
||||||
; this is the config options of "console" mode (used by MODE=console above)
|
|
||||||
[log.console]
|
|
||||||
MODE = console
|
|
||||||
FLAGS = stdflags
|
|
||||||
PREFIX =
|
|
||||||
COLORIZE = true
|
|
||||||
```
|
|
||||||
|
|
||||||
This is equivalent to sending all logs to the console, with default Golang log being sent to the console log too.
|
|
||||||
|
|
||||||
This is only a sample, and it is the default, do not need to write it into your configuration file.
|
|
||||||
|
|
||||||
### Disable Router logs and record some access logs to file
|
|
||||||
|
|
||||||
The Router logger is disabled, the access logs (>=Warn) goes into `access.log`:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[log]
|
|
||||||
logger.router.MODE =
|
|
||||||
logger.access.MODE = access-file
|
|
||||||
|
|
||||||
[log.access-file]
|
|
||||||
MODE = file
|
|
||||||
LEVEL = Warn
|
|
||||||
FILE_NAME = access.log
|
|
||||||
```
|
|
||||||
|
|
||||||
### Set different log levels for different modes
|
|
||||||
|
|
||||||
Default logs (>=Warn) goes into `gitea.log`, while Error logs goes into `file-error.log`:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[log]
|
|
||||||
LEVEL = Warn
|
|
||||||
MODE = file, file-error
|
|
||||||
|
|
||||||
; by default, the "file" mode will record logs to %(log.ROOT_PATH)/gitea.log, so we don't need to set it
|
|
||||||
; [log.file]
|
|
||||||
; by default, the MODE (actually it's the output writer of this logger) is taken from the section name, so we don't need to set it either
|
|
||||||
; MODE = file
|
|
||||||
|
|
||||||
[log.file-error]
|
|
||||||
MODE = file
|
|
||||||
LEVEL = Error
|
|
||||||
FILE_NAME = file-error.log
|
|
||||||
```
|
|
||||||
|
|
||||||
## Log outputs (mode and writer)
|
|
||||||
|
|
||||||
Gitea provides the following log output writers:
|
|
||||||
|
|
||||||
- `console` - Log to `stdout` (or `stderr` if it is set in the config)
|
|
||||||
- `file` - Log to a file
|
|
||||||
- `conn` - Log to a socket (network or unix)
|
|
||||||
|
|
||||||
### Common configuration
|
|
||||||
|
|
||||||
Certain configuration is common to all modes of log output:
|
|
||||||
|
|
||||||
- `MODE` is the mode of the log output writer. It will default to the mode name in the ini section. Thus `[log.console]` will default to `MODE = console`.
|
|
||||||
- `LEVEL` is the lowest level that this output will log.
|
|
||||||
- `STACKTRACE_LEVEL` is the lowest level that this output will print a stacktrace.
|
|
||||||
- `COLORIZE` will default to `true` for `console` as described, otherwise it will default to `false`.
|
|
||||||
|
|
||||||
#### `EXPRESSION`
|
|
||||||
|
|
||||||
`EXPRESSION` represents a regular expression that log events must match to be logged by the output writer.
|
|
||||||
Either the log message, (with colors removed), must match or the `longfilename:linenumber:functionname` must match.
|
|
||||||
NB: the whole message or string doesn't need to completely match.
|
|
||||||
|
|
||||||
Please note this expression will be run in the writer's goroutine but not the logging event goroutine.
|
|
||||||
|
|
||||||
#### `FLAGS`
|
|
||||||
|
|
||||||
`FLAGS` represents the preceding logging context information that is
|
|
||||||
printed before each message. It is a comma-separated string set. The order of values does not matter.
|
|
||||||
|
|
||||||
It defaults to `stdflags` (= `date,time,medfile,shortfuncname,levelinitial`)
|
|
||||||
|
|
||||||
Possible values are:
|
|
||||||
|
|
||||||
- `none` or `,` - No flags.
|
|
||||||
- `date` - the date in the local time zone: `2009/01/23`.
|
|
||||||
- `time` - the time in the local time zone: `01:23:23`.
|
|
||||||
- `microseconds` - microsecond resolution: `01:23:23.123123`. Assumes time.
|
|
||||||
- `longfile` - full file name and line number: `/a/b/c/d.go:23`.
|
|
||||||
- `shortfile` - final file name element and line number: `d.go:23`.
|
|
||||||
- `funcname` - function name of the caller: `runtime.Caller()`.
|
|
||||||
- `shortfuncname` - last part of the function name. Overrides `funcname`.
|
|
||||||
- `utc` - if date or time is set, use UTC rather than the local time zone.
|
|
||||||
- `levelinitial` - initial character of the provided level in brackets eg. `[I]` for info.
|
|
||||||
- `level` - level in brackets `[INFO]`.
|
|
||||||
- `gopid` - the Goroutine-PID of the context.
|
|
||||||
- `medfile` - last 20 characters of the filename - equivalent to `shortfile,longfile`.
|
|
||||||
- `stdflags` - equivalent to `date,time,medfile,shortfuncname,levelinitial`.
|
|
||||||
|
|
||||||
### Console mode
|
|
||||||
|
|
||||||
In this mode the logger will forward log messages to the stdout and
|
|
||||||
stderr streams attached to the Gitea process.
|
|
||||||
|
|
||||||
For loggers in console mode, `COLORIZE` will default to `true` if not
|
|
||||||
on windows, or the Windows terminal can be set into ANSI mode or is a
|
|
||||||
cygwin or Msys pipe.
|
|
||||||
|
|
||||||
Settings:
|
|
||||||
|
|
||||||
- `STDERR`: **false**: Whether the logger should print to `stderr` instead of `stdout`.
|
|
||||||
|
|
||||||
### File mode
|
|
||||||
|
|
||||||
In this mode the logger will save log messages to a file.
|
|
||||||
|
|
||||||
Settings:
|
|
||||||
|
|
||||||
- `FILE_NAME`: The file to write the log events to, relative to `ROOT_PATH`, Default to `%(ROOT_PATH)/gitea.log`. Exception: access log will default to `%(ROOT_PATH)/access.log`.
|
|
||||||
- `MAX_SIZE_SHIFT`: **28**: Maximum size shift of a single file. 28 represents 256Mb. For details see below.
|
|
||||||
- `LOG_ROTATE` **true**: Whether to rotate the log files. TODO: if false, will it delete instead on daily rotate, or do nothing?.
|
|
||||||
- `DAILY_ROTATE`: **true**: Whether to rotate logs daily.
|
|
||||||
- `MAX_DAYS`: **7**: Delete rotated log files after this number of days.
|
|
||||||
- `COMPRESS`: **true**: Whether to compress old log files by default with gzip.
|
|
||||||
- `COMPRESSION_LEVEL`: **-1**: Compression level. For details see below.
|
|
||||||
|
|
||||||
`MAX_SIZE_SHIFT` defines the maximum size of a file by left shifting 1 the given number of times (`1 << x`).
|
|
||||||
The exact behavior at the time of v1.17.3 can be seen [here](https://github.com/go-gitea/gitea/blob/v1.17.3/modules/setting/log.go#L185).
|
|
||||||
|
|
||||||
The useful values of `COMPRESSION_LEVEL` are from 1 to (and including) 9, where higher numbers mean better compression.
|
|
||||||
Beware that better compression might come with higher resource usage.
|
|
||||||
Must be preceded with a `-` sign.
|
|
||||||
|
|
||||||
### Conn mode
|
|
||||||
|
|
||||||
In this mode the logger will send log messages over a network socket.
|
|
||||||
|
|
||||||
Settings:
|
|
||||||
|
|
||||||
- `ADDR`: **:7020**: Sets the address to connect to.
|
|
||||||
- `PROTOCOL`: **tcp**: Set the protocol, either "tcp", "unix" or "udp".
|
|
||||||
- `RECONNECT`: **false**: Try to reconnect when connection is lost.
|
|
||||||
- `RECONNECT_ON_MSG`: **false**: Reconnect host for every single message.
|
|
||||||
|
|
||||||
### The "Router" logger
|
|
||||||
|
|
||||||
The Router logger logs the following message types when Gitea's route handlers work:
|
|
||||||
|
|
||||||
- `started` messages will be logged at TRACE level
|
|
||||||
- `polling`/`completed` routers will be logged at INFO. Exception: "/assets" static resource requests are also logged at TRACE.
|
|
||||||
- `slow` routers will be logged at WARN
|
|
||||||
- `failed` routers will be logged at WARN
|
|
||||||
|
|
||||||
### The "XORM" logger
|
|
||||||
|
|
||||||
To make XORM outputs SQL logs, the `LOG_SQL` in `[database]` section should also be set to `true`.
|
|
||||||
|
|
||||||
### The "Access" logger
|
|
||||||
|
|
||||||
The Access logger is a new logger since Gitea 1.9. It provides a NCSA
|
|
||||||
Common Log compliant log format. It's highly configurable but caution
|
|
||||||
should be taken when changing its template. The main benefit of this
|
|
||||||
logger is that Gitea can now log accesses in a standard log format so
|
|
||||||
standard tools may be used.
|
|
||||||
|
|
||||||
You can enable this logger using `logger.access.MODE = ...`.
|
|
||||||
|
|
||||||
If desired the format of the Access logger can be changed by changing
|
|
||||||
the value of the `ACCESS_LOG_TEMPLATE`.
|
|
||||||
|
|
||||||
Please note, the access logger will log at `INFO` level, setting the
|
|
||||||
`LEVEL` of this logger to `WARN` or above will result in no access logs.
|
|
||||||
|
|
||||||
#### The ACCESS_LOG_TEMPLATE
|
|
||||||
|
|
||||||
This value represents a go template. Its default value is
|
|
||||||
|
|
||||||
```tmpl
|
|
||||||
{{.Ctx.RemoteHost}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}" "{{.Ctx.Req.UserAgent}}"`
|
|
||||||
```
|
|
||||||
|
|
||||||
The template is passed following options:
|
|
||||||
|
|
||||||
- `Ctx` is the `context.Context`
|
|
||||||
- `Identity` is the `SignedUserName` or `"-"` if the user is not logged in
|
|
||||||
- `Start` is the start time of the request
|
|
||||||
- `ResponseWriter` is the `http.ResponseWriter`
|
|
||||||
|
|
||||||
Caution must be taken when changing this template as it runs outside of
|
|
||||||
the standard panic recovery trap. The template should also be as simple
|
|
||||||
as it runs for every request.
|
|
||||||
|
|
||||||
## Releasing-and-Reopening, Pausing and Resuming logging
|
|
||||||
|
|
||||||
If you are running on Unix you may wish to release-and-reopen logs in order to use `logrotate` or other tools.
|
|
||||||
It is possible force Gitea to release and reopen it's logging files and connections by sending `SIGUSR1` to the
|
|
||||||
running process, or running `gitea manager logging release-and-reopen`.
|
|
||||||
|
|
||||||
Alternatively, you may wish to pause and resume logging - this can be accomplished through the use of the
|
|
||||||
`gitea manager logging pause` and `gitea manager logging resume` commands. Please note that whilst logging
|
|
||||||
is paused log events below INFO level will not be stored and only a limited number of events will be stored.
|
|
||||||
Logging may block, albeit temporarily, slowing Gitea considerably whilst paused - therefore it is
|
|
||||||
recommended that pausing only done for a very short period of time.
|
|
||||||
|
|
||||||
## Adding and removing logging whilst Gitea is running
|
|
||||||
|
|
||||||
It is possible to add and remove logging whilst Gitea is running using the `gitea manager logging add` and `remove` subcommands.
|
|
||||||
This functionality can only adjust running log systems and cannot be used to start the access or router loggers if they
|
|
||||||
were not already initialized. If you wish to start these systems you are advised to adjust the app.ini and (gracefully) restart
|
|
||||||
the Gitea service.
|
|
||||||
|
|
||||||
The main intention of these commands is to easily add a temporary logger to investigate problems on running systems where a restart
|
|
||||||
may cause the issue to disappear.
|
|
||||||
|
|
||||||
## Using `logrotate` instead of built-in log rotation
|
|
||||||
|
|
||||||
Gitea includes built-in log rotation, which should be enough for most deployments. However, if you instead want to use the `logrotate` utility:
|
|
||||||
|
|
||||||
- Disable built-in log rotation by setting `LOG_ROTATE` to `false` in your `app.ini`.
|
|
||||||
- Install `logrotate`.
|
|
||||||
- Configure `logrotate` to match your deployment requirements, see `man 8 logrotate` for configuration syntax details.
|
|
||||||
In the `postrotate/endscript` block send Gitea a `USR1` signal via `kill -USR1` or `kill -10` to the `gitea` process itself,
|
|
||||||
or run `gitea manager logging release-and-reopen` (with the appropriate environment).
|
|
||||||
Ensure that your configurations apply to all files emitted by Gitea loggers as described in the above sections.
|
|
||||||
- Always do `logrotate /etc/logrotate.conf --debug` to test your configurations.
|
|
||||||
- If you are using docker and are running from outside the container you can use
|
|
||||||
`docker exec -u $OS_USER $CONTAINER_NAME sh -c 'gitea manager logging release-and-reopen'`
|
|
||||||
or `docker exec $CONTAINER_NAME sh -c '/bin/s6-svc -1 /etc/s6/gitea/'` or send `USR1` directly to the Gitea process itself.
|
|
||||||
|
|
||||||
The next `logrotate` jobs will include your configurations, so no restart is needed.
|
|
||||||
You can also immediately reload `logrotate` with `logrotate /etc/logrotate.conf --force`.
|
|
|
@ -1,272 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "日志配置"
|
|
||||||
slug: "logging-config"
|
|
||||||
sidebar_position: 40
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/logging-configuration
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "日志配置"
|
|
||||||
sidebar_position: 40
|
|
||||||
identifier: "logging-config"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 日志配置
|
|
||||||
|
|
||||||
Gitea 的日志配置主要由以下三种类型的组件组成:
|
|
||||||
|
|
||||||
- `[log]` 部分用于一般配置
|
|
||||||
- `[log.<mode-name>]` 部分用于配置不同的日志输出方式,也称为 "writer mode",模式名称同时也作为 "writer name"
|
|
||||||
- `[log]` 部分还可以包含遵循 `logger.<logger-name>.<CONFIG-KEY>` 模式的子日志记录器的配置
|
|
||||||
|
|
||||||
默认情况下,已经有一个完全功能的日志输出,因此不需要重新定义。
|
|
||||||
|
|
||||||
## 收集日志以获取帮助
|
|
||||||
|
|
||||||
要收集日志以获取帮助和报告问题,请参阅 [需要帮助](help/support.md)。
|
|
||||||
|
|
||||||
## `[log]` 部分
|
|
||||||
|
|
||||||
在 Gitea 中,日志设施的配置在 `[log]` 部分及其子部分。
|
|
||||||
|
|
||||||
在顶层的 `[log]` 部分,可以放置以下配置项:
|
|
||||||
|
|
||||||
- `ROOT_PATH`:(默认值:**%(GITEA_WORK_DIR)/log**):日志文件的基本路径。
|
|
||||||
- `MODE`:(默认值:**console**):要用于默认日志记录器的日志输出列表。
|
|
||||||
- `LEVEL`:(默认值:**Info**):要持久化的最严重的日志事件,不区分大小写。可能的值为:`Trace`、`Debug`、`Info`、`Warn`、`Error`、`Fatal`。
|
|
||||||
- `STACKTRACE_LEVEL`:(默认值:**None**):对于此类及更严重的事件,将在记录时打印堆栈跟踪。
|
|
||||||
|
|
||||||
它还可以包含以下子日志记录器:
|
|
||||||
|
|
||||||
- `logger.router.MODE`:(默认值:**,**):用于路由器日志记录器的日志输出列表。
|
|
||||||
- `logger.access.MODE`:(默认值:**_empty_**):用于访问日志记录器的日志输出列表。默认情况下,访问日志记录器被禁用。
|
|
||||||
- `logger.xorm.MODE`:(默认值:**,**):用于 XORM 日志记录器的日志输出列表。
|
|
||||||
|
|
||||||
将子日志记录器的模式设置为逗号(`,`)表示使用默认的全局 `MODE`。
|
|
||||||
|
|
||||||
## 快速示例
|
|
||||||
|
|
||||||
### 默认(空)配置
|
|
||||||
|
|
||||||
空配置等同于默认配置:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[log]
|
|
||||||
ROOT_PATH = %(GITEA_WORK_DIR)/log
|
|
||||||
MODE = console
|
|
||||||
LEVEL = Info
|
|
||||||
STACKTRACE_LEVEL = None
|
|
||||||
logger.router.MODE = ,
|
|
||||||
logger.xorm.MODE = ,
|
|
||||||
logger.access.MODE =
|
|
||||||
|
|
||||||
; 这是“控制台”模式的配置选项(由上面的 MODE=console 使用)
|
|
||||||
[log.console]
|
|
||||||
MODE = console
|
|
||||||
FLAGS = stdflags
|
|
||||||
PREFIX =
|
|
||||||
COLORIZE = true
|
|
||||||
```
|
|
||||||
|
|
||||||
这等同于将所有日志发送到控制台,并将默认的 Golang 日志也发送到控制台日志中。
|
|
||||||
|
|
||||||
这只是一个示例,默认情况下不需要将其写入配置文件中。
|
|
||||||
|
|
||||||
### 禁用路由日志并将一些访问日志记录到文件中
|
|
||||||
|
|
||||||
禁用路由日志,将访问日志(>=Warn)记录到 `access.log` 中:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[log]
|
|
||||||
logger.router.MODE =
|
|
||||||
logger.access.MODE = access-file
|
|
||||||
|
|
||||||
[log.access-file]
|
|
||||||
MODE = file
|
|
||||||
LEVEL = Warn
|
|
||||||
FILE_NAME = access.log
|
|
||||||
```
|
|
||||||
|
|
||||||
### 为不同的模式设置不同的日志级别
|
|
||||||
|
|
||||||
将默认日志(>=Warn)记录到 `gitea.log` 中,将错误日志记录到 `file-error.log` 中:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[log]
|
|
||||||
LEVEL = Warn
|
|
||||||
MODE = file, file-error
|
|
||||||
|
|
||||||
; 默认情况下,"file" 模式会将日志记录到 %(log.ROOT_PATH)/gitea.log,因此我们不需要设置它
|
|
||||||
; [log.file]
|
|
||||||
|
|
||||||
[log.file-error]
|
|
||||||
LEVEL = Error
|
|
||||||
FILE_NAME = file-error.log
|
|
||||||
```
|
|
||||||
|
|
||||||
## 日志输出(模式和写入器)
|
|
||||||
|
|
||||||
Gitea 提供以下日志写入器:
|
|
||||||
|
|
||||||
- `console` - 输出日志到 `stdout`(或 `stderr`,如果已在配置中设置)
|
|
||||||
- `file` - 输出日志到文件
|
|
||||||
- `conn` - 输出日志到套接字(网络或 Unix 套接字)
|
|
||||||
|
|
||||||
### 公共配置
|
|
||||||
|
|
||||||
某些配置适用于所有日志输出模式:
|
|
||||||
|
|
||||||
- `MODE` 是日志输出写入器的模式。它将默认为 ini 部分的模式名称。因此,`[log.console]` 将默认为 `MODE = console`。
|
|
||||||
- `LEVEL` 是此输出将记录的最低日志级别。
|
|
||||||
- `STACKTRACE_LEVEL` 是此输出将打印堆栈跟踪的最低日志级别。
|
|
||||||
- `COLORIZE` 对于 `console`,默认为 `true`,否则默认为 `false`。
|
|
||||||
|
|
||||||
#### `EXPRESSION`
|
|
||||||
|
|
||||||
`EXPRESSION` 表示日志事件必须匹配才能被输出写入器记录的正则表达式。
|
|
||||||
日志消息(去除颜色)或 `longfilename:linenumber:functionname` 必须匹配其中之一。
|
|
||||||
注意:整个消息或字符串不需要完全匹配。
|
|
||||||
|
|
||||||
请注意,此表达式将在写入器的 goroutine 中运行,而不是在日志事件的 goroutine 中运行。
|
|
||||||
|
|
||||||
#### `FLAGS`
|
|
||||||
|
|
||||||
`FLAGS` 表示在每条消息之前打印的前置日志上下文信息。
|
|
||||||
它是一个逗号分隔的字符串集。值的顺序无关紧要。
|
|
||||||
|
|
||||||
默认值为 `stdflags`(= `date,time,medfile,shortfuncname,levelinitial`)。
|
|
||||||
|
|
||||||
可能的值为:
|
|
||||||
|
|
||||||
- `none` 或 `,` - 无标志。
|
|
||||||
- `date` - 当地时区的日期:`2009/01/23`。
|
|
||||||
- `time` - 当地时区的时间:`01:23:23`。
|
|
||||||
- `microseconds` - 微秒精度:`01:23:23.123123`。假定有时间。
|
|
||||||
- `longfile` - 完整的文件名和行号:`/a/b/c/d.go:23`。
|
|
||||||
- `shortfile` - 文件名的最后一个部分和行号:`d.go:23`。
|
|
||||||
- `funcname` - 调用者的函数名:`runtime.Caller()`。
|
|
||||||
- `shortfuncname` - 函数名的最后一部分。覆盖 `funcname`。
|
|
||||||
- `utc` - 如果设置了日期或时间,则使用 UTC 而不是本地时区。
|
|
||||||
- `levelinitial` - 提供的级别的初始字符,放在方括号内,例如 `[I]` 表示 info。
|
|
||||||
- `level` - 在方括号内的级别,例如 `[INFO]`。
|
|
||||||
- `gopid` - 上下文的 Goroutine-PID。
|
|
||||||
- `medfile` - 文件名的最后 20 个字符 - 相当于 `shortfile,longfile`。
|
|
||||||
- `stdflags` - 相当于 `date,time,medfile,shortfuncname,levelinitial`。
|
|
||||||
|
|
||||||
### Console 模式
|
|
||||||
|
|
||||||
在此模式下,日志记录器将将日志消息转发到 Gitea 进程附加的 stdout 和 stderr 流。
|
|
||||||
|
|
||||||
对于 console 模式的日志记录器,如果不在 Windows 上,或者 Windows 终端可以设置为 ANSI 模式,或者是 cygwin 或 Msys 管道,则 `COLORIZE` 默认为 `true`。
|
|
||||||
|
|
||||||
设置:
|
|
||||||
|
|
||||||
- `STDERR`:**false**:日志记录器是否应将日志打印到 `stderr` 而不是 `stdout`。
|
|
||||||
|
|
||||||
### File 模式
|
|
||||||
|
|
||||||
在此模式下,日志记录器将将日志消息保存到文件中。
|
|
||||||
|
|
||||||
设置:
|
|
||||||
|
|
||||||
- `FILE_NAME`:要将日志事件写入的文件,相对于 `ROOT_PATH`,默认为 `%(ROOT_PATH)/gitea.log`。异常情况:访问日志默认为 `%(ROOT_PATH)/access.log`。
|
|
||||||
- `MAX_SIZE_SHIFT`:**28**:单个文件的最大大小位移。28 表示 256Mb。详细信息见下文。
|
|
||||||
- `LOG_ROTATE` **true**:是否轮转日志文件。
|
|
||||||
- `DAILY_ROTATE`:**true**:是否每天旋转日志。
|
|
||||||
- `MAX_DAYS`:**7**:在此天数之后删除旋转的日志文件。
|
|
||||||
- `COMPRESS`:**true**:默认情况下是否使用 gzip 压缩旧的日志文件。
|
|
||||||
- `COMPRESSION_LEVEL`:**-1**:压缩级别。详细信息见下文。
|
|
||||||
|
|
||||||
`MAX_SIZE_SHIFT` 通过将给定次数左移 1 (`1 << x`) 来定义文件的最大大小。
|
|
||||||
在 v1.17.3 版本时的确切行为可以在[这里](https://github.com/go-gitea/gitea/blob/v1.17.3/modules/setting/log.go#L185)中查看。
|
|
||||||
|
|
||||||
`COMPRESSION_LEVEL` 的有用值范围从 1 到(包括)9,其中较高的数字表示更好的压缩。
|
|
||||||
请注意,更好的压缩可能会带来更高的资源使用。
|
|
||||||
必须在前面加上 `-` 符号。
|
|
||||||
|
|
||||||
### Conn 模式
|
|
||||||
|
|
||||||
在此模式下,日志记录器将通过网络套接字发送日志消息。
|
|
||||||
|
|
||||||
设置:
|
|
||||||
|
|
||||||
- `ADDR`:**:7020**:设置要连接的地址。
|
|
||||||
- `PROTOCOL`:**tcp**:设置协议,可以是 "tcp"、"unix" 或 "udp"。
|
|
||||||
- `RECONNECT`:**false**:在连接丢失时尝试重新连接。
|
|
||||||
- `RECONNECT_ON_MSG`:**false**:为每条消息重新连接主机。
|
|
||||||
|
|
||||||
### "Router" 日志记录器
|
|
||||||
|
|
||||||
当 Gitea 的路由处理程序工作时,Router 日志记录器记录以下消息类型:
|
|
||||||
|
|
||||||
- `started` 消息将以 TRACE 级别记录
|
|
||||||
- `polling`/`completed` 路由将以 INFO 级别记录。异常情况:"/assets" 静态资源请求也会以 TRACE 级别记录。
|
|
||||||
- `slow` 路由将以 WARN 级别记录
|
|
||||||
- `failed` 路由将以 WARN 级别记录
|
|
||||||
|
|
||||||
### "XORM" 日志记录器
|
|
||||||
|
|
||||||
为了使 XORM 输出 SQL 日志,还应将 `[database]` 部分中的 `LOG_SQL` 设置为 `true`。
|
|
||||||
|
|
||||||
### "Access" 日志记录器
|
|
||||||
|
|
||||||
"Access" 日志记录器是自 Gitea 1.9 版本以来的新日志记录器。它提供了符合 NCSA Common Log 标准的日志格式。虽然它具有高度可配置性,但在更改其模板时应谨慎。此日志记录器的主要好处是,Gitea 现在可以使用标准日志格式记录访问日志,因此可以使用标准工具进行分析。
|
|
||||||
|
|
||||||
您可以通过使用 `logger.access.MODE = ...` 来启用此日志记录器。
|
|
||||||
|
|
||||||
如果需要,可以通过更改 `ACCESS_LOG_TEMPLATE` 的值来更改 "Access" 日志记录器的格式。
|
|
||||||
|
|
||||||
请注意,访问日志记录器将以 `INFO` 级别记录,将此日志记录器的 `LEVEL` 设置为 `WARN` 或更高级别将导致不记录访问日志。
|
|
||||||
|
|
||||||
#### ACCESS_LOG_TEMPLATE
|
|
||||||
|
|
||||||
此值表示一个 Go 模板。其默认值为
|
|
||||||
|
|
||||||
```tmpl
|
|
||||||
{{.Ctx.RemoteHost}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}" "{{.Ctx.Req.UserAgent}}"`
|
|
||||||
```
|
|
||||||
|
|
||||||
模板接收以下选项:
|
|
||||||
|
|
||||||
- `Ctx` 是 `context.Context`
|
|
||||||
- `Identity` 是 `SignedUserName`,如果用户未登录,则为 "-"
|
|
||||||
- `Start` 是请求的开始时间
|
|
||||||
- `ResponseWriter` 是 `http.ResponseWriter`
|
|
||||||
|
|
||||||
更改此模板时必须小心,因为它在标准的 panic 恢复陷阱之外运行。此模板应该尽可能简单,因为它会为每个请求运行一次。
|
|
||||||
|
|
||||||
## 释放和重新打开、暂停和恢复日志记录
|
|
||||||
|
|
||||||
如果您在 Unix 上运行,您可能希望释放和重新打开日志以使用 `logrotate` 或其他工具。
|
|
||||||
可以通过向运行中的进程发送 `SIGUSR1` 信号或运行 `gitea manager logging release-and-reopen` 命令来强制 Gitea 释放并重新打开其日志文件和连接。
|
|
||||||
|
|
||||||
或者,您可能希望暂停和恢复日志记录 - 可以通过使用 `gitea manager logging pause` 和 `gitea manager logging resume` 命令来实现。请注意,当日志记录暂停时,低于 INFO 级别的日志事件将不会存储,并且只会存储有限数量的事件。在暂停时,日志记录可能会阻塞,尽管是暂时性的,但会大大减慢 Gitea 的运行速度,因此建议仅暂停很短的时间。
|
|
||||||
|
|
||||||
### 在 Gitea 运行时添加和删除日志记录
|
|
||||||
|
|
||||||
可以使用 `gitea manager logging add` 和 `remove` 子命令在 Gitea 运行时添加和删除日志记录。
|
|
||||||
此功能只能调整正在运行的日志系统,不能用于启动未初始化的访问或路由日志记录器。如果您希望启动这些系统,建议调整 app.ini 并(优雅地)重新启动 Gitea 服务。
|
|
||||||
|
|
||||||
这些命令的主要目的是在运行中的系统上轻松添加临时日志记录器,以便调查问题,因为重新启动可能会导致问题消失。
|
|
||||||
|
|
||||||
## 使用 `logrotate` 而不是内置的日志轮转
|
|
||||||
|
|
||||||
Gitea 包含内置的日志轮转功能,对于大多数部署来说应该已经足够了。但是,如果您想使用 `logrotate` 工具:
|
|
||||||
|
|
||||||
- 在 `app.ini` 中将 `LOG_ROTATE` 设置为 `false`,禁用内置的日志轮转。
|
|
||||||
- 安装 `logrotate`。
|
|
||||||
- 根据部署要求配置 `logrotate`,有关配置语法细节,请参阅 `man 8 logrotate`。
|
|
||||||
在 `postrotate/endscript` 块中通过 `kill -USR1` 或 `kill -10` 向 `gitea` 进程本身发送 `USR1` 信号,
|
|
||||||
或者运行 `gitea manager logging release-and-reopen`(使用适当的环境设置)。
|
|
||||||
确保配置适用于由 Gitea 日志记录器生成的所有文件,如上述部分所述。
|
|
||||||
- 始终使用 `logrotate /etc/logrotate.conf --debug` 来测试您的配置。
|
|
||||||
- 如果您正在使用 Docker 并从容器外部运行,您可以使用
|
|
||||||
`docker exec -u $OS_USER $CONTAINER_NAME sh -c 'gitea manager logging release-and-reopen'`
|
|
||||||
或 `docker exec $CONTAINER_NAME sh -c '/bin/s6-svc -1 /etc/s6/gitea/'`,或直接向 Gitea 进程本身发送 `USR1` 信号。
|
|
||||||
|
|
||||||
下一个 `logrotate` 作业将包括您的配置,因此不需要重新启动。
|
|
||||||
您还可以立即使用 `logrotate /etc/logrotate.conf --force` 重新加载 `logrotate`。
|
|
|
@ -1,278 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-10-23T17:00:00-03:00"
|
|
||||||
title: "Mail templates"
|
|
||||||
slug: "mail-templates"
|
|
||||||
sidebar_position: 45
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/mail-templates
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Mail templates"
|
|
||||||
sidebar_position: 45
|
|
||||||
identifier: "mail-templates"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 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](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.
|
|
||||||
|
|
||||||
## Mail notifications supporting templates
|
|
||||||
|
|
||||||
Currently, the following notification events make use of templates:
|
|
||||||
|
|
||||||
| Action name | Usage |
|
|
||||||
| ----------- | ------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| `new` | A new issue or pull request was created. |
|
|
||||||
| `comment` | A new comment was created in an existing issue or pull request. |
|
|
||||||
| `close` | An issue or pull request was closed. |
|
|
||||||
| `reopen` | An issue or pull request was reopened. |
|
|
||||||
| `review` | The head comment of a review in a pull request. |
|
|
||||||
| `approve` | The head comment of a approving review for a pull request. |
|
|
||||||
| `reject` | The head comment of a review requesting changes for a pull request. |
|
|
||||||
| `code` | A single comment on the code of a pull request. |
|
|
||||||
| `assigned` | User was assigned to an issue or pull request. |
|
|
||||||
| `default` | Any action not included in the above categories, or when the corresponding category template is not present. |
|
|
||||||
|
|
||||||
The path for the template of a particular message type is:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
custom/templates/mail/{action type}/{action name}.tmpl
|
|
||||||
```
|
|
||||||
|
|
||||||
Where `{action type}` is one of `issue` or `pull` (for pull requests), and `{action name}` is one of the names listed above.
|
|
||||||
|
|
||||||
For example, the specific template for a mail regarding a comment in a pull request is:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
custom/templates/mail/pull/comment.tmpl
|
|
||||||
```
|
|
||||||
|
|
||||||
However, creating templates for each and every action type/name combination is not required.
|
|
||||||
A fallback system is used to choose the appropriate template for an event. The _first existing_
|
|
||||||
template on this list is used:
|
|
||||||
|
|
||||||
- The specific template for the desired **action type** and **action name**.
|
|
||||||
- The template for action type `issue` and the desired **action name**.
|
|
||||||
- The template for the desired **action type**, action name `default`.
|
|
||||||
- The template for action type `issue`, action name `default`.
|
|
||||||
|
|
||||||
The only mandatory template is action type `issue`, action name `default`, which is already embedded in Gitea
|
|
||||||
unless it's overridden by the user in the `custom` directory.
|
|
||||||
|
|
||||||
## Template syntax
|
|
||||||
|
|
||||||
Mail templates are UTF-8 encoded text files that need to follow one of the following formats:
|
|
||||||
|
|
||||||
```
|
|
||||||
Text and macros for the subject line
|
|
||||||
------------
|
|
||||||
Text and macros for the mail body
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```
|
|
||||||
Text and macros for the mail body
|
|
||||||
```
|
|
||||||
|
|
||||||
Specifying a _subject_ section is optional (and therefore also the dash line separator). When used, the separator between
|
|
||||||
_subject_ and _mail body_ templates requires at least three dashes; no other characters are allowed in the separator line.
|
|
||||||
|
|
||||||
_Subject_ and _mail body_ are parsed by [Golang's template engine](https://go.dev/pkg/text/template/) and
|
|
||||||
are provided with a _metadata context_ assembled for each notification. The context contains the following elements:
|
|
||||||
|
|
||||||
| Name | Type | Available | Usage |
|
|
||||||
| ------------------ | ---------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| `.FallbackSubject` | string | Always | A default subject line. See Below. |
|
|
||||||
| `.Subject` | string | Only in body | The _subject_, once resolved. |
|
|
||||||
| `.Body` | string | Always | The message of the issue, pull request or comment, parsed from Markdown into HTML and sanitized. Do not confuse with the _mail body_. |
|
|
||||||
| `.Link` | string | Always | The address of the originating issue, pull request or comment. |
|
|
||||||
| `.Issue` | models.Issue | Always | The issue (or pull request) originating the notification. To get data specific to a pull request (e.g. `HasMerged`), `.Issue.PullRequest` can be used, but care should be taken as this field will be `nil` if the issue is _not_ a pull request. |
|
|
||||||
| `.Comment` | models.Comment | If applicable | If the notification is from a comment added to an issue or pull request, this will contain the information about the comment. |
|
|
||||||
| `.IsPull` | bool | Always | `true` if the mail notification is associated with a pull request (i.e. `.Issue.PullRequest` is not `nil`). |
|
|
||||||
| `.Repo` | string | Always | Name of the repository, including owner name (e.g. `mike/stuff`) |
|
|
||||||
| `.User` | models.User | Always | Owner of the repository from which the event originated. To get the user name (e.g. `mike`),`.User.Name` can be used. |
|
|
||||||
| `.Doer` | models.User | Always | User that executed the action triggering the notification event. To get the user name (e.g. `rhonda`), `.Doer.Name` can be used. |
|
|
||||||
| `.IsMention` | bool | Always | `true` if this notification was only generated because the user was mentioned in the comment, while not being subscribed to the source. It will be `false` if the recipient was subscribed to the issue or repository. |
|
|
||||||
| `.SubjectPrefix` | string | Always | `Re: ` if the notification is about other than issue or pull request creation; otherwise an empty string. |
|
|
||||||
| `.ActionType` | string | Always | `"issue"` or `"pull"`. Will correspond to the actual _action type_ independently of which template was selected. |
|
|
||||||
| `.ActionName` | string | Always | It will be one of the action types described above (`new`, `comment`, etc.), and will correspond to the actual _action name_ independently of which template was selected. |
|
|
||||||
| `.ReviewComments` | []models.Comment | Always | List of code comments in a review. The comment text will be in `.RenderedContent` and the referenced code will be in `.Patch`. |
|
|
||||||
|
|
||||||
All names are case sensitive.
|
|
||||||
|
|
||||||
### The _subject_ part of the template
|
|
||||||
|
|
||||||
The template engine used for the mail _subject_ is golang's [`text/template`](https://go.dev/pkg/text/template/).
|
|
||||||
Please refer to the linked documentation for details about its syntax.
|
|
||||||
|
|
||||||
The _subject_ is built using the following steps:
|
|
||||||
|
|
||||||
- A template is selected according to the type of notification and to what templates are present.
|
|
||||||
- The template is parsed and resolved (e.g. `{{.Issue.Index}}` is converted to the number of the issue
|
|
||||||
or pull request).
|
|
||||||
- All space-like characters (e.g. `TAB`, `LF`, etc.) are converted to normal spaces.
|
|
||||||
- All leading, trailing and redundant spaces are removed.
|
|
||||||
- The string is truncated to its first 256 runes (characters).
|
|
||||||
|
|
||||||
If the end result is an empty string, **or** no subject template was available (i.e. the selected template
|
|
||||||
did not include a subject part), Gitea's **internal default** will be used.
|
|
||||||
|
|
||||||
The internal default (fallback) subject is the equivalent of:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
{{.SubjectPrefix}}[{{.Repo}}] {{.Issue.Title}} (#{{.Issue.Index}})
|
|
||||||
```
|
|
||||||
|
|
||||||
For example: `Re: [mike/stuff] New color palette (#38)`
|
|
||||||
|
|
||||||
Gitea's default subject can also be found in the template _metadata_ as `.FallbackSubject` from any of
|
|
||||||
the two templates, even if a valid subject template is present.
|
|
||||||
|
|
||||||
### The _mail body_ part of the template
|
|
||||||
|
|
||||||
The template engine used for the _mail body_ is golang's [`html/template`](https://go.dev/pkg/html/template/).
|
|
||||||
Please refer to the linked documentation for details about its syntax.
|
|
||||||
|
|
||||||
The _mail body_ is parsed after the mail subject, so there is an additional _metadata_ field which is
|
|
||||||
the actual rendered subject, after all considerations.
|
|
||||||
|
|
||||||
The expected result is HTML (including structural elements like`<html>`, `<body>`, etc.). Styling
|
|
||||||
through `<style>` blocks, `class` and `style` attributes is possible. However, `html/template`
|
|
||||||
does some [automatic escaping](https://go.dev/pkg/html/template/#hdr-Contexts) that should be considered.
|
|
||||||
|
|
||||||
Attachments (such as images or external style sheets) are not supported. However, other templates can
|
|
||||||
be referenced too, for example to provide the contents of a `<style>` element in a centralized fashion.
|
|
||||||
The external template must be placed under `custom/mail` and referenced relative to that directory.
|
|
||||||
For example, `custom/mail/styles/base.tmpl` can be included using `{{template styles/base}}`.
|
|
||||||
|
|
||||||
The mail is sent with `Content-Type: multipart/alternative`, so the body is sent in both HTML
|
|
||||||
and text formats. The latter is obtained by stripping the HTML markup.
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
How a mail is rendered is directly dependent on the capabilities of the mail application. Many mail
|
|
||||||
clients don't even support HTML, so they show the text version included in the generated mail.
|
|
||||||
|
|
||||||
If the template fails to render, it will be noticed only at the moment the mail is sent.
|
|
||||||
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](administration/logging-config.md) for error messages in case of trouble.
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
`custom/templates/mail/issue/default.tmpl`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
[{{.Repo}}] @{{.Doer.Name}}
|
|
||||||
{{if eq .ActionName "new"}}
|
|
||||||
created
|
|
||||||
{{else if eq .ActionName "comment"}}
|
|
||||||
commented on
|
|
||||||
{{else if eq .ActionName "close"}}
|
|
||||||
closed
|
|
||||||
{{else if eq .ActionName "reopen"}}
|
|
||||||
reopened
|
|
||||||
{{else}}
|
|
||||||
updated
|
|
||||||
{{end}}
|
|
||||||
{{if eq .ActionType "issue"}}
|
|
||||||
issue
|
|
||||||
{{else}}
|
|
||||||
pull request
|
|
||||||
{{end}}
|
|
||||||
#{{.Issue.Index}}: {{.Issue.Title}}
|
|
||||||
------------
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
||||||
<title>{{.Subject}}</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
{{if .IsMention}}
|
|
||||||
<p>
|
|
||||||
You are receiving this because @{{.Doer.Name}} mentioned you.
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
<p>
|
|
||||||
<p>
|
|
||||||
<a href="{{AppUrl}}/{{.Doer.LowerName}}">@{{.Doer.Name}}</a>
|
|
||||||
{{if not (eq .Doer.FullName "")}}
|
|
||||||
({{.Doer.FullName}})
|
|
||||||
{{end}}
|
|
||||||
{{if eq .ActionName "new"}}
|
|
||||||
created
|
|
||||||
{{else if eq .ActionName "close"}}
|
|
||||||
closed
|
|
||||||
{{else if eq .ActionName "reopen"}}
|
|
||||||
reopened
|
|
||||||
{{else}}
|
|
||||||
updated
|
|
||||||
{{end}}
|
|
||||||
<a href="{{.Link}}">{{.Repo}}#{{.Issue.Index}}</a>.
|
|
||||||
</p>
|
|
||||||
{{if not (eq .Body "")}}
|
|
||||||
<h3>Message content:</h3>
|
|
||||||
<hr>
|
|
||||||
{{.Body | Str2html}}
|
|
||||||
{{end}}
|
|
||||||
</p>
|
|
||||||
<hr>
|
|
||||||
<p>
|
|
||||||
<a href="{{.Link}}">View it on Gitea</a>.
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
This template produces something along these lines:
|
|
||||||
|
|
||||||
### Subject
|
|
||||||
|
|
||||||
> [mike/stuff] @rhonda commented on pull request #38: New color palette
|
|
||||||
|
|
||||||
### Mail body
|
|
||||||
|
|
||||||
> [@rhonda](#) (Rhonda Myers) updated [mike/stuff#38](#).
|
|
||||||
>
|
|
||||||
> #### Message content:
|
|
||||||
>
|
|
||||||
> \_********************************\_********************************
|
|
||||||
>
|
|
||||||
> Mike, I think we should tone down the blues a little.
|
|
||||||
> \_********************************\_********************************
|
|
||||||
>
|
|
||||||
> [View it on Gitea](#).
|
|
||||||
|
|
||||||
## Advanced
|
|
||||||
|
|
||||||
The template system contains several functions that can be used to further process and format
|
|
||||||
the messages. Here's a list of some of them:
|
|
||||||
|
|
||||||
| Name | Parameters | Available | Usage |
|
|
||||||
| ---------------- | ----------- | --------- | --------------------------------------------------------------------------- |
|
|
||||||
| `AppUrl` | - | Any | Gitea's URL |
|
|
||||||
| `AppName` | - | Any | Set from `app.ini`, usually "Gitea" |
|
|
||||||
| `AppDomain` | - | Any | Gitea's host name |
|
|
||||||
| `EllipsisString` | string, int | Any | Truncates a string to the specified length; adds ellipsis as needed |
|
|
||||||
| `Str2html` | string | Body only | Sanitizes text by removing any HTML tags from it. |
|
|
||||||
| `Safe` | string | Body only | Takes the input as HTML; can be used for `.ReviewComments.RenderedContent`. |
|
|
||||||
|
|
||||||
These are _functions_, not metadata, so they have to be used:
|
|
||||||
|
|
||||||
```html
|
|
||||||
Like this: {{Str2html "Escape<my>text"}}
|
|
||||||
Or this: {{"Escape<my>text" | Str2html}}
|
|
||||||
Or this: {{AppUrl}}
|
|
||||||
But not like this: {{.AppUrl}}
|
|
||||||
```
|
|
|
@ -1,261 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "邮件模板"
|
|
||||||
slug: "mail-templates"
|
|
||||||
sidebar_position: 45
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/mail-templates
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "邮件模板"
|
|
||||||
sidebar_position: 45
|
|
||||||
identifier: "mail-templates"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 邮件模板
|
|
||||||
|
|
||||||
为了定制特定操作的电子邮件主题和内容,可以使用模板来自定义 Gitea。这些功能的模板位于 [`custom` 目录](administration/customizing-gitea.md) 下。
|
|
||||||
如果没有自定义的替代方案,Gitea 将使用内部模板作为默认模板。
|
|
||||||
|
|
||||||
自定义模板在 Gitea 启动时加载。对它们的更改在 Gitea 重新启动之前不会被识别。
|
|
||||||
|
|
||||||
## 支持模板的邮件通知
|
|
||||||
|
|
||||||
目前,以下通知事件使用模板:
|
|
||||||
|
|
||||||
| 操作名称 | 用途 |
|
|
||||||
| ----------- | ------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| `new` | 创建了新的工单或合并请求。 |
|
|
||||||
| `comment` | 在现有工单或合并请求中创建了新的评论。 |
|
|
||||||
| `close` | 关闭了工单或合并请求。 |
|
|
||||||
| `reopen` | 重新打开了工单或合并请求。 |
|
|
||||||
| `review` | 在合并请求中进行审查的首要评论。 |
|
|
||||||
| `approve` | 对合并请求进行批准的首要评论。 |
|
|
||||||
| `reject` | 对合并请求提出更改请求的审查的首要评论。 |
|
|
||||||
| `code` | 关于合并请求的代码的单个评论。 |
|
|
||||||
| `assigned` | 用户被分配到工单或合并请求。 |
|
|
||||||
| `default` | 未包括在上述类别中的任何操作,或者当对应类别的模板不存在时使用的模板。 |
|
|
||||||
|
|
||||||
特定消息类型的模板路径为:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
custom/templates/mail/{操作类型}/{操作名称}.tmpl
|
|
||||||
```
|
|
||||||
|
|
||||||
其中 `{操作类型}` 是 `issue` 或 `pull`(针对合并请求),`{操作名称}` 是上述列出的操作名称之一。
|
|
||||||
|
|
||||||
例如,有关合并请求中的评论的电子邮件的特定模板是:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
custom/templates/mail/pull/comment.tmpl
|
|
||||||
```
|
|
||||||
|
|
||||||
然而,并不需要为每个操作类型/名称组合创建模板。
|
|
||||||
使用回退系统来选择适当的模板。在此列表中,将使用 _第一个存在的_ 模板:
|
|
||||||
|
|
||||||
- 所需**操作类型**和**操作名称**的特定模板。
|
|
||||||
- 操作类型为 `issue` 和所需**操作名称**的模板。
|
|
||||||
- 所需**操作类型**和操作名称为 `default` 的模板。
|
|
||||||
- 操作类型为` issue` 和操作名称为 `default` 的模板。
|
|
||||||
|
|
||||||
唯一必需的模板是操作类型为 `issue` 操作名称为 `default` 的模板,除非用户在 `custom` 目录中覆盖了它。
|
|
||||||
|
|
||||||
## 模板语法
|
|
||||||
|
|
||||||
邮件模板是 UTF-8 编码的文本文件,需要遵循以下格式之一:
|
|
||||||
|
|
||||||
```
|
|
||||||
用于主题行的文本和宏
|
|
||||||
------------
|
|
||||||
用于邮件正文的文本和宏
|
|
||||||
```
|
|
||||||
|
|
||||||
或者
|
|
||||||
|
|
||||||
```
|
|
||||||
用于邮件正文的文本和宏
|
|
||||||
```
|
|
||||||
|
|
||||||
指定 _主题_ 部分是可选的(因此也是虚线分隔符)。在使用时,_主题_ 和 _邮件正文_ 模板之间的分隔符需要至少三个虚线;分隔符行中不允许使用其他字符。
|
|
||||||
|
|
||||||
_主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://go.dev/pkg/text/template/) 解析,并提供了为每个通知组装的 _元数据上下文_。上下文包含以下元素:
|
|
||||||
|
|
||||||
| 名称 | 类型 | 可用性 | 用途 |
|
|
||||||
| -------------------- | ------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| `.FallbackSubject` | string | 始终可用 | 默认主题行。参见下文。 |
|
|
||||||
| `.Subject` | string | 仅在正文中可用 | 解析后的 _主题_。 |
|
|
||||||
| `.Body` | string | 始终可用 | 工单、合并请求或评论的消息,从 Markdown 解析为 HTML 并进行了清理。请勿与 _邮件正文_ 混淆。 |
|
|
||||||
| `.Link` | string | 始终可用 | 源工单、合并请求或评论的地址。 |
|
|
||||||
| `.Issue` | models.Issue | 始终可用 | 产生通知的工单(或合并请求)。要获取特定于合并请求的数据(例如 `HasMerged`),可以使用 `.Issue.PullRequest`,但需要注意,如果工单 _不是_ 合并请求,则该字段将为 `nil`。 |
|
|
||||||
| `.Comment` | models.Comment | 如果适用 | 如果通知是针对添加到工单或合并请求的评论,则其中包含有关评论的信息。 |
|
|
||||||
| `.IsPull` | bool | 始终可用 | 如果邮件通知与合并请求关联(即 `.Issue.PullRequest` 不为 `nil` ),则为 `true`。 |
|
|
||||||
| `.Repo` | string | 始终可用 | 仓库的名称,包括所有者名称(例如 `mike/stuff`) |
|
|
||||||
| `.User` | models.User | 始终可用 | 事件来源仓库的所有者。要获取用户名(例如 `mike`),可以使用 `.User.Name`。 |
|
|
||||||
| `.Doer` | models.User | 始终可用 | 执行触发通知事件的操作的用户。要获取用户名(例如 `rhonda`),可以使用 `.Doer.Name`。 |
|
|
||||||
| `.IsMention` | bool | 始终可用 | 如果此通知仅是因为在评论中提到了用户而生成的,并且收件人未订阅源,则为 `true`。如果收件人已订阅工单或仓库,则为 `false`。 |
|
|
||||||
| `.SubjectPrefix` | string | 始终可用 | 如果通知是关于除工单或合并请求创建之外的其他内容,则为 `Re:`;否则为空字符串。 |
|
|
||||||
| `.ActionType` | string | 始终可用 | `"issue"` 或 `"pull"`。它将与实际的 _操作类型_ 对应,与选择的模板无关。 |
|
|
||||||
| `.ActionName` | string | 始终可用 | 它将是上述操作类型之一(`new` ,`comment` 等),并与选择的模板对应。 |
|
|
||||||
| `.ReviewComments` | []models.Comment | 始终可用 | 审查中的代码评论列表。评论文本将在 `.RenderedContent` 中,引用的代码将在 `.Patch` 中。 |
|
|
||||||
|
|
||||||
所有名称区分大小写。
|
|
||||||
|
|
||||||
### 模板中的主题部分
|
|
||||||
|
|
||||||
用于邮件主题的模板引擎是 Golang 的 [`text/template`](https://go.dev/pkg/text/template/)。
|
|
||||||
有关语法的详细信息,请参阅链接的文档。
|
|
||||||
|
|
||||||
主题构建的步骤如下:
|
|
||||||
|
|
||||||
- 根据通知类型和可用的模板选择一个模板。
|
|
||||||
- 解析并解析模板(例如,将 `{{.Issue.Index}}` 转换为工单或合并请求的编号)。
|
|
||||||
- 将所有空格字符(例如 `TAB`,`LF` 等)转换为普通空格。
|
|
||||||
- 删除所有前导、尾随和多余的空格。
|
|
||||||
- 将字符串截断为前 256 个字母(字符)。
|
|
||||||
|
|
||||||
如果最终结果为空字符串,**或者**没有可用的主题模板(即所选模板不包含主题部分),将使用Gitea的**内部默认值**。
|
|
||||||
|
|
||||||
内部默认(回退)主题相当于:
|
|
||||||
|
|
||||||
```
|
|
||||||
{{.SubjectPrefix}}[{{.Repo}}] {{.Issue.Title}} (#{{.Issue.Index}})
|
|
||||||
```
|
|
||||||
|
|
||||||
例如:`Re: [mike/stuff] New color palette (#38)`
|
|
||||||
|
|
||||||
即使存在有效的主题模板,Gitea的默认主题也可以在模板的元数据中作为 `.FallbackSubject` 找到。
|
|
||||||
|
|
||||||
### 模板中的邮件正文部分
|
|
||||||
|
|
||||||
用于邮件正文的模板引擎是 Golang 的 [`html/template`](https://go.dev/pkg/html/template/)。
|
|
||||||
有关语法的详细信息,请参阅链接的文档。
|
|
||||||
|
|
||||||
邮件正文在邮件主题之后进行解析,因此还有一个额外的 _元数据_ 字段,即在考虑所有情况之后实际呈现的主题。
|
|
||||||
|
|
||||||
期望的结果是 HTML(包括结构元素,如`<html>`,`<body>`等)。可以通过 `<style>` 块、`class` 和 `style` 属性进行样式设置。但是,`html/template` 会进行一些 [自动转义](https://go.dev/pkg/html/template/#hdr-Contexts),需要考虑这一点。
|
|
||||||
|
|
||||||
不支持附件(例如图像或外部样式表)。但是,也可以引用其他模板,例如以集中方式提供 `<style>` 元素的内容。外部模板必须放置在 `custom/mail` 下,并相对于该目录引用。例如,可以使用 `{{template styles/base}}` 包含 `custom/mail/styles/base.tmpl`。
|
|
||||||
|
|
||||||
邮件以 `Content-Type: multipart/alternative` 发送,因此正文以 HTML 和文本格式发送。通过剥离 HTML 标记来获取文本版本。
|
|
||||||
|
|
||||||
## 故障排除
|
|
||||||
|
|
||||||
邮件的呈现方式直接取决于邮件应用程序的功能。许多邮件客户端甚至不支持 HTML,因此显示生成邮件中包含的文本版本。
|
|
||||||
|
|
||||||
如果模板无法呈现,则只有在发送邮件时才会注意到。
|
|
||||||
如果主题模板失败,将使用默认主题,如果从 _邮件正文_ 中成功呈现了任何内容,则将使用该内容,忽略其他内容。
|
|
||||||
|
|
||||||
如果遇到问题,请检查 [Gitea的日志](administration/logging-config.md) 以获取错误消息。
|
|
||||||
|
|
||||||
## 示例
|
|
||||||
|
|
||||||
`custom/templates/mail/issue/default.tmpl`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
[{{.Repo}}] @{{.Doer.Name}}
|
|
||||||
{{if eq .ActionName "new"}}
|
|
||||||
创建了
|
|
||||||
{{else if eq .ActionName "comment"}}
|
|
||||||
评论了
|
|
||||||
{{else if eq .ActionName "close"}}
|
|
||||||
关闭了
|
|
||||||
{{else if eq .ActionName "reopen"}}
|
|
||||||
重新打开了
|
|
||||||
{{else}}
|
|
||||||
更新了
|
|
||||||
{{end}}
|
|
||||||
{{if eq .ActionType "issue"}}
|
|
||||||
工单
|
|
||||||
{{else}}
|
|
||||||
合并请求
|
|
||||||
{{end}}
|
|
||||||
#{{.Issue.Index}}: {{.Issue.Title}}
|
|
||||||
------------
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
||||||
<title>{{.Subject}}</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
{{if .IsMention}}
|
|
||||||
<p>
|
|
||||||
您收到此邮件是因为 @{{.Doer.Name}} 提到了您。
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
<p>
|
|
||||||
<p>
|
|
||||||
<a href="{{AppUrl}}/{{.Doer.LowerName}}">@{{.Doer.Name}}</a>
|
|
||||||
{{if not (eq .Doer.FullName "")}}
|
|
||||||
({{.Doer.FullName}})
|
|
||||||
{{end}}
|
|
||||||
{{if eq .ActionName "new"}}
|
|
||||||
创建了
|
|
||||||
{{else if eq .ActionName "close"}}
|
|
||||||
关闭了
|
|
||||||
{{else if eq .ActionName "reopen"}}
|
|
||||||
重新打开了
|
|
||||||
{{else}}
|
|
||||||
更新了
|
|
||||||
{{end}}
|
|
||||||
<a href="{{.Link}}">{{.Repo}}#{{.Issue.Index}}</a>。
|
|
||||||
</p>
|
|
||||||
{{if not (eq .Body "")}}
|
|
||||||
<h3>消息内容:</h3>
|
|
||||||
<hr>
|
|
||||||
{{.Body | Str2html}}
|
|
||||||
{{end}}
|
|
||||||
</p>
|
|
||||||
<hr>
|
|
||||||
<p>
|
|
||||||
<a href="{{.Link}}">在 Gitea 上查看</a>。
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
该模板将生成以下内容:
|
|
||||||
|
|
||||||
### 主题
|
|
||||||
|
|
||||||
> [mike/stuff] @rhonda 在合并请求 #38 上进行了评论:New color palette
|
|
||||||
|
|
||||||
### 邮件正文
|
|
||||||
|
|
||||||
> [@rhonda](#)(Rhonda Myers)更新了 [mike/stuff#38](#)。
|
|
||||||
>
|
|
||||||
> #### 消息内容:
|
|
||||||
>
|
|
||||||
> \_********************************\_********************************
|
|
||||||
>
|
|
||||||
> Mike, I think we should tone down the blues a little.
|
|
||||||
>
|
|
||||||
> \_********************************\_********************************
|
|
||||||
>
|
|
||||||
> [在 Gitea 上查看](#)。
|
|
||||||
|
|
||||||
## 高级用法
|
|
||||||
|
|
||||||
模板系统包含一些函数,可用于进一步处理和格式化消息。以下是其中一些函数的列表:
|
|
||||||
|
|
||||||
| 函数名 | 参数 | 可用于 | 用法 |
|
|
||||||
| ----------------- | ----------- | ------------ | --------------------------------------------------------------------------------- |
|
|
||||||
| `AppUrl` | - | 任何地方 | Gitea 的 URL |
|
|
||||||
| `AppName` | - | 任何地方 | 从 `app.ini` 中设置,通常为 "Gitea" |
|
|
||||||
| `AppDomain` | - | 任何地方 | Gitea 的主机名 |
|
|
||||||
| `EllipsisString` | string, int | 任何地方 | 将字符串截断为指定长度;根据需要添加省略号 |
|
|
||||||
| `Str2html` | string | 仅正文部分 | 通过删除其中的 HTML 标签对文本进行清理 |
|
|
||||||
| `Safe` | string | 仅正文部分 | 将输入作为 HTML 处理;可用于 `.ReviewComments.RenderedContent` 等字段 |
|
|
||||||
|
|
||||||
这些都是 _函数_,而不是元数据,因此必须按以下方式使用:
|
|
||||||
|
|
||||||
```html
|
|
||||||
像这样使用: {{Str2html "Escape<my>text"}}
|
|
||||||
或者这样使用: {{"Escape<my>text" | Str2html}}
|
|
||||||
或者这样使用: {{AppUrl}}
|
|
||||||
但不要像这样使用: {{.AppUrl}}
|
|
||||||
```
|
|
|
@ -1,59 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-09-06T01:35:00-03:00"
|
|
||||||
title: "Repository indexer"
|
|
||||||
slug: "repo-indexer"
|
|
||||||
sidebar_position: 45
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/repo-indexer
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Repository indexer"
|
|
||||||
sidebar_position: 45
|
|
||||||
identifier: "repo-indexer"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Repository indexer
|
|
||||||
|
|
||||||
## Setting up the repository indexer
|
|
||||||
|
|
||||||
Gitea can search through the files of the repositories by enabling this function in your [`app.ini`](administration/config-cheat-sheet.md):
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[indexer]
|
|
||||||
; ...
|
|
||||||
REPO_INDEXER_ENABLED = true
|
|
||||||
REPO_INDEXER_PATH = indexers/repos.bleve
|
|
||||||
MAX_FILE_SIZE = 1048576
|
|
||||||
REPO_INDEXER_INCLUDE =
|
|
||||||
REPO_INDEXER_EXCLUDE = resources/bin/**
|
|
||||||
```
|
|
||||||
|
|
||||||
Please bear in mind that indexing the contents can consume a lot of system resources, especially when the index is created for the first time or globally updated (e.g. after upgrading Gitea).
|
|
||||||
|
|
||||||
### Choosing the files for indexing by size
|
|
||||||
|
|
||||||
The `MAX_FILE_SIZE` option will make the indexer skip all files larger than the specified value.
|
|
||||||
|
|
||||||
### Choosing the files for indexing by path
|
|
||||||
|
|
||||||
Gitea applies glob pattern matching from the [`gobwas/glob` library](https://github.com/gobwas/glob) to choose which files will be included in the index.
|
|
||||||
|
|
||||||
Limiting the list of files prevents the indexes from becoming polluted with derived or irrelevant files (e.g. lss, sym, map, etc.), so the search results are more relevant. It can also help reduce the index size.
|
|
||||||
|
|
||||||
`REPO_INDEXER_EXCLUDE_VENDORED` (default: true) excludes vendored files from index.
|
|
||||||
|
|
||||||
`REPO_INDEXER_INCLUDE` (default: empty) is a comma separated list of glob patterns to **include** in the index. An empty list means "_include all files_".
|
|
||||||
`REPO_INDEXER_EXCLUDE` (default: empty) is a comma separated list of glob patterns to **exclude** from the index. Files that match this list will not be indexed. `REPO_INDEXER_EXCLUDE` takes precedence over `REPO_INDEXER_INCLUDE`.
|
|
||||||
|
|
||||||
Pattern matching works as follows:
|
|
||||||
|
|
||||||
- To match all files with a `.txt` extension no matter what directory, use `**.txt`.
|
|
||||||
- To match all files with a `.txt` extension _only at the root level of the repository_, use `*.txt`.
|
|
||||||
- To match all files inside `resources/bin` and below, use `resources/bin/**`.
|
|
||||||
- To match all files _immediately inside_ `resources/bin`, use `resources/bin/*`.
|
|
||||||
- To match all files named `Makefile`, use `**Makefile`.
|
|
||||||
- Matching a directory has no effect; the pattern `resources/bin` will not include/exclude files inside that directory; `resources/bin/**` will.
|
|
||||||
- All files and patterns are normalized to lower case, so `**Makefile`, `**makefile` and `**MAKEFILE` are equivalent.
|
|
|
@ -1,59 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "仓库索引器"
|
|
||||||
slug: "repo-indexer"
|
|
||||||
sidebar_position: 45
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/repo-indexer
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "仓库索引器"
|
|
||||||
sidebar_position: 45
|
|
||||||
identifier: "repo-indexer"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 仓库索引器
|
|
||||||
|
|
||||||
## 设置仓库索引器
|
|
||||||
|
|
||||||
通过在您的 [`app.ini`](administration/config-cheat-sheet.md) 中启用此功能,Gitea 可以通过仓库的文件进行搜索:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[indexer]
|
|
||||||
; ...
|
|
||||||
REPO_INDEXER_ENABLED = true
|
|
||||||
REPO_INDEXER_PATH = indexers/repos.bleve
|
|
||||||
MAX_FILE_SIZE = 1048576
|
|
||||||
REPO_INDEXER_INCLUDE =
|
|
||||||
REPO_INDEXER_EXCLUDE = resources/bin/**
|
|
||||||
```
|
|
||||||
|
|
||||||
请记住,索引内容可能会消耗大量系统资源,特别是在首次创建索引或全局更新索引时(例如升级 Gitea 之后)。
|
|
||||||
|
|
||||||
### 按大小选择要索引的文件
|
|
||||||
|
|
||||||
`MAX_FILE_SIZE` 选项将使索引器跳过所有大于指定值的文件。
|
|
||||||
|
|
||||||
### 按路径选择要索引的文件
|
|
||||||
|
|
||||||
Gitea使用 [`gobwas/glob` 库](https://github.com/gobwas/glob) 中的 glob 模式匹配来选择要包含在索引中的文件。
|
|
||||||
|
|
||||||
限制文件列表可以防止索引被派生或无关的文件(例如 lss、sym、map 等)污染,从而使搜索结果更相关。这还有助于减小索引的大小。
|
|
||||||
|
|
||||||
`REPO_INDEXER_EXCLUDE_VENDORED`(默认值为 true)将排除供应商文件不包含在索引中。
|
|
||||||
|
|
||||||
`REPO_INDEXER_INCLUDE`(默认值为空)是一个逗号分隔的 glob 模式列表,用于在索引中**包含**的文件。空列表表示“_包含所有文件_”。
|
|
||||||
`REPO_INDEXER_EXCLUDE`(默认值为空)是一个逗号分隔的 glob 模式列表,用于从索引中**排除**的文件。与该列表匹配的文件将不会被索引。`REPO_INDEXER_EXCLUDE` 优先于 `REPO_INDEXER_INCLUDE`。
|
|
||||||
|
|
||||||
模式匹配工作方式如下:
|
|
||||||
|
|
||||||
- 要匹配所有带有 `.txt` 扩展名的文件,无论在哪个目录中,请使用 `**.txt`。
|
|
||||||
- 要匹配仅在仓库的根级别中具有 `.txt` 扩展名的所有文件,请使用 `*.txt`。
|
|
||||||
- 要匹配 `resources/bin` 目录及其子目录中的所有文件,请使用 `resources/bin/**`。
|
|
||||||
- 要匹配位于 `resources/bin` 目录下的所有文件,请使用 `resources/bin/*`。
|
|
||||||
- 要匹配所有名为 `Makefile` 的文件,请使用 `**Makefile`。
|
|
||||||
- 匹配目录没有效果;模式 `resources/bin` 不会包含/排除该目录中的文件;`resources/bin/**` 会。
|
|
||||||
- 所有文件和模式都规范化为小写,因此 `**Makefile`、`**makefile` 和 `**MAKEFILE` 是等效的。
|
|
|
@ -1,389 +0,0 @@
|
||||||
---
|
|
||||||
date: "2018-05-22T11:00:00+00:00"
|
|
||||||
title: "Reverse Proxies"
|
|
||||||
slug: "reverse-proxies"
|
|
||||||
sidebar_position: 16
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/reverse-proxies
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Reverse Proxies"
|
|
||||||
sidebar_position: 16
|
|
||||||
identifier: "reverse-proxies"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Reverse Proxies
|
|
||||||
|
|
||||||
## Nginx
|
|
||||||
|
|
||||||
If you want Nginx to serve your Gitea instance, add the following `server` section to the `http` section of `nginx.conf`:
|
|
||||||
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name git.example.com;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
client_max_body_size 512M;
|
|
||||||
proxy_pass http://localhost:3000;
|
|
||||||
proxy_set_header Connection $http_connection;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Resolving Error: 413 Request Entity Too Large
|
|
||||||
|
|
||||||
This error indicates nginx is configured to restrict the file upload size,
|
|
||||||
it affects attachment uploading, form posting, package uploading and LFS pushing, etc.
|
|
||||||
You can fine tune the `client_max_body_size` option according to [nginx document](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size).
|
|
||||||
|
|
||||||
## Nginx with a sub-path
|
|
||||||
|
|
||||||
In case you already have a site, and you want Gitea to share the domain name, you can setup Nginx to serve Gitea under a sub-path by adding the following `server` section inside the `http` section of `nginx.conf`:
|
|
||||||
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name git.example.com;
|
|
||||||
|
|
||||||
# Note: Trailing slash
|
|
||||||
location /gitea/ {
|
|
||||||
client_max_body_size 512M;
|
|
||||||
|
|
||||||
# make nginx use unescaped URI, keep "%2F" as is
|
|
||||||
rewrite ^ $request_uri;
|
|
||||||
rewrite ^/gitea(/.*) $1 break;
|
|
||||||
proxy_pass http://127.0.0.1:3000$uri;
|
|
||||||
|
|
||||||
# other common HTTP headers, see the "Nginx" config section above
|
|
||||||
proxy_set_header ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you **MUST** set something like `[server] ROOT_URL = http://git.example.com/git/` correctly in your configuration.
|
|
||||||
|
|
||||||
## Nginx and serve static resources directly
|
|
||||||
|
|
||||||
We can tune the performance in splitting requests into categories static and dynamic.
|
|
||||||
|
|
||||||
CSS files, JavaScript files, images and web fonts are static content.
|
|
||||||
The front page, a repository view or issue list is dynamic content.
|
|
||||||
|
|
||||||
Nginx can serve static resources directly and proxy only the dynamic requests to Gitea.
|
|
||||||
Nginx is optimized for serving static content, while the proxying of large responses might be the opposite of that
|
|
||||||
(see [https://serverfault.com/q/587386](https://serverfault.com/q/587386)).
|
|
||||||
|
|
||||||
Download a snapshot of the Gitea source repository to `/path/to/gitea/`.
|
|
||||||
After this, run `make frontend` in the repository directory to generate the static resources. We are only interested in the `public/` directory for this task, so you can delete the rest.
|
|
||||||
(You will need to have [Node with npm](https://nodejs.org/en/download/) and `make` installed to generate the static resources)
|
|
||||||
|
|
||||||
Depending on the scale of your user base, you might want to split the traffic to two distinct servers,
|
|
||||||
or use a cdn for the static files.
|
|
||||||
|
|
||||||
### Single node and single domain
|
|
||||||
|
|
||||||
Set `[server] STATIC_URL_PREFIX = /_/static` in your configuration.
|
|
||||||
|
|
||||||
```apacheconf
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name git.example.com;
|
|
||||||
|
|
||||||
location /_/static/assets/ {
|
|
||||||
alias /path/to/gitea/public/;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:3000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Two nodes and two domains
|
|
||||||
|
|
||||||
Set `[server] STATIC_URL_PREFIX = http://cdn.example.com/gitea` in your configuration.
|
|
||||||
|
|
||||||
```apacheconf
|
|
||||||
# application server running Gitea
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name git.example.com;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:3000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```apacheconf
|
|
||||||
# static content delivery server
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name cdn.example.com;
|
|
||||||
|
|
||||||
location /gitea/ {
|
|
||||||
alias /path/to/gitea/public/;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
return 404;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Apache HTTPD
|
|
||||||
|
|
||||||
If you want Apache HTTPD to serve your Gitea instance, you can add the following to your Apache HTTPD configuration (usually located at `/etc/apache2/httpd.conf` in Ubuntu):
|
|
||||||
|
|
||||||
```apacheconf
|
|
||||||
<VirtualHost *:80>
|
|
||||||
...
|
|
||||||
ProxyPreserveHost On
|
|
||||||
ProxyRequests off
|
|
||||||
AllowEncodedSlashes NoDecode
|
|
||||||
ProxyPass / http://localhost:3000/ nocanon
|
|
||||||
</VirtualHost>
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: The following Apache HTTPD mods must be enabled: `proxy`, `proxy_http`.
|
|
||||||
|
|
||||||
If you wish to use Let's Encrypt with webroot validation, add the line `ProxyPass /.well-known !` before `ProxyPass` to disable proxying these requests to Gitea.
|
|
||||||
|
|
||||||
## Apache HTTPD with a sub-path
|
|
||||||
|
|
||||||
In case you already have a site, and you want Gitea to share the domain name, you can setup Apache HTTPD to serve Gitea under a sub-path by adding the following to you Apache HTTPD configuration (usually located at `/etc/apache2/httpd.conf` in Ubuntu):
|
|
||||||
|
|
||||||
```apacheconf
|
|
||||||
<VirtualHost *:80>
|
|
||||||
...
|
|
||||||
<Proxy *>
|
|
||||||
Order allow,deny
|
|
||||||
Allow from all
|
|
||||||
</Proxy>
|
|
||||||
AllowEncodedSlashes NoDecode
|
|
||||||
# Note: no trailing slash after either /git or port
|
|
||||||
ProxyPass /git http://localhost:3000 nocanon
|
|
||||||
</VirtualHost>
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you **MUST** set something like `[server] ROOT_URL = http://git.example.com/git/` correctly in your configuration.
|
|
||||||
|
|
||||||
Note: The following Apache HTTPD mods must be enabled: `proxy`, `proxy_http`.
|
|
||||||
|
|
||||||
## Caddy
|
|
||||||
|
|
||||||
If you want Caddy to serve your Gitea instance, you can add the following server block to your Caddyfile:
|
|
||||||
|
|
||||||
```apacheconf
|
|
||||||
git.example.com {
|
|
||||||
reverse_proxy localhost:3000
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Caddy with a sub-path
|
|
||||||
|
|
||||||
In case you already have a site, and you want Gitea to share the domain name, you can setup Caddy to serve Gitea under a sub-path by adding the following to your server block in your Caddyfile:
|
|
||||||
|
|
||||||
```apacheconf
|
|
||||||
git.example.com {
|
|
||||||
route /git/* {
|
|
||||||
uri strip_prefix /git
|
|
||||||
reverse_proxy localhost:3000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then set `[server] ROOT_URL = http://git.example.com/git/` in your configuration.
|
|
||||||
|
|
||||||
## IIS
|
|
||||||
|
|
||||||
If you wish to run Gitea with IIS. You will need to setup IIS with URL Rewrite as reverse proxy.
|
|
||||||
|
|
||||||
1. Setup an empty website in IIS, named let's say, `Gitea Proxy`.
|
|
||||||
2. Follow the first two steps in [Microsoft's Technical Community Guide to Setup IIS with URL Rewrite](https://techcommunity.microsoft.com/t5/iis-support-blog/setup-iis-with-url-rewrite-as-a-reverse-proxy-for-real-world/ba-p/846222#M343). That is:
|
|
||||||
|
|
||||||
- Install Application Request Routing (ARR for short) either by using the Microsoft Web Platform Installer 5.1 (WebPI) or downloading the extension from [IIS.net](https://www.iis.net/downloads/microsoft/application-request-routing)
|
|
||||||
- Once the module is installed in IIS, you will see a new Icon in the IIS Administration Console called URL Rewrite.
|
|
||||||
- Open the IIS Manager Console and click on the `Gitea Proxy` Website from the tree view on the left. Select and double click the URL Rewrite Icon from the middle pane to load the URL Rewrite interface.
|
|
||||||
- Choose the `Add Rule` action from the right pane of the management console and select the `Reverse Proxy Rule` from the `Inbound and Outbound Rules` category.
|
|
||||||
- In the Inbound Rules section, set the server name to be the host that Gitea is running on with its port. e.g. if you are running Gitea on the localhost with port 3000, the following should work: `127.0.0.1:3000`
|
|
||||||
- Enable SSL Offloading
|
|
||||||
- In the Outbound Rules, ensure `Rewrite the domain names of the links in HTTP response` is set and set the `From:` field as above and the `To:` to your external hostname, say: `git.example.com`
|
|
||||||
- Now edit the `web.config` for your website to match the following: (changing `127.0.0.1:3000` and `git.example.com` as appropriate)
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<configuration>
|
|
||||||
<system.web>
|
|
||||||
<httpRuntime requestPathInvalidCharacters="" />
|
|
||||||
</system.web>
|
|
||||||
<system.webServer>
|
|
||||||
<security>
|
|
||||||
<requestFiltering>
|
|
||||||
<hiddenSegments>
|
|
||||||
<clear />
|
|
||||||
</hiddenSegments>
|
|
||||||
<denyUrlSequences>
|
|
||||||
<clear />
|
|
||||||
</denyUrlSequences>
|
|
||||||
<fileExtensions allowUnlisted="true">
|
|
||||||
<clear />
|
|
||||||
</fileExtensions>
|
|
||||||
</requestFiltering>
|
|
||||||
</security>
|
|
||||||
<rewrite>
|
|
||||||
<rules useOriginalURLEncoding="false">
|
|
||||||
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
|
|
||||||
<match url="(.*)" />
|
|
||||||
<action type="Rewrite" url="http://127.0.0.1:3000{UNENCODED_URL}" />
|
|
||||||
<serverVariables>
|
|
||||||
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="HTTP_ACCEPT_ENCODING" />
|
|
||||||
<set name="HTTP_ACCEPT_ENCODING" value="" />
|
|
||||||
</serverVariables>
|
|
||||||
</rule>
|
|
||||||
</rules>
|
|
||||||
<outboundRules>
|
|
||||||
<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
|
|
||||||
<!-- set the pattern correctly here - if you only want to accept http or https -->
|
|
||||||
<!-- change the pattern and the action value as appropriate -->
|
|
||||||
<match filterByTags="A, Form, Img" pattern="^http(s)?://127.0.0.1:3000/(.*)" />
|
|
||||||
<action type="Rewrite" value="http{R:1}://git.example.com/{R:2}" />
|
|
||||||
</rule>
|
|
||||||
<rule name="RestoreAcceptEncoding" preCondition="NeedsRestoringAcceptEncoding">
|
|
||||||
<match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^(.*)" />
|
|
||||||
<action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" />
|
|
||||||
</rule>
|
|
||||||
<preConditions>
|
|
||||||
<preCondition name="ResponseIsHtml1">
|
|
||||||
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
|
|
||||||
</preCondition>
|
|
||||||
<preCondition name="NeedsRestoringAcceptEncoding">
|
|
||||||
<add input="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" pattern=".+" />
|
|
||||||
</preCondition>
|
|
||||||
</preConditions>
|
|
||||||
</outboundRules>
|
|
||||||
</rewrite>
|
|
||||||
<urlCompression doDynamicCompression="true" />
|
|
||||||
<handlers>
|
|
||||||
<clear />
|
|
||||||
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
|
|
||||||
</handlers>
|
|
||||||
<!-- Map all extensions to the same MIME type, so all files can be
|
|
||||||
downloaded. -->
|
|
||||||
<staticContent>
|
|
||||||
<clear />
|
|
||||||
<mimeMap fileExtension="*" mimeType="application/octet-stream" />
|
|
||||||
</staticContent>
|
|
||||||
</system.webServer>
|
|
||||||
</configuration>
|
|
||||||
```
|
|
||||||
|
|
||||||
## HAProxy
|
|
||||||
|
|
||||||
If you want HAProxy to serve your Gitea instance, you can add the following to your HAProxy configuration
|
|
||||||
|
|
||||||
add an acl in the frontend section to redirect calls to gitea.example.com to the correct backend
|
|
||||||
|
|
||||||
```
|
|
||||||
frontend http-in
|
|
||||||
...
|
|
||||||
acl acl_gitea hdr(host) -i gitea.example.com
|
|
||||||
use_backend gitea if acl_gitea
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
add the previously defined backend section
|
|
||||||
|
|
||||||
```
|
|
||||||
backend gitea
|
|
||||||
server localhost:3000 check
|
|
||||||
```
|
|
||||||
|
|
||||||
If you redirect the http content to https, the configuration work the same way, just remember that the connection between HAProxy and Gitea will be done via http so you do not have to enable https in Gitea's configuration.
|
|
||||||
|
|
||||||
## HAProxy with a sub-path
|
|
||||||
|
|
||||||
In case you already have a site, and you want Gitea to share the domain name, you can setup HAProxy to serve Gitea under a sub-path by adding the following to you HAProxy configuration:
|
|
||||||
|
|
||||||
```
|
|
||||||
frontend http-in
|
|
||||||
...
|
|
||||||
acl acl_gitea path_beg /gitea
|
|
||||||
use_backend gitea if acl_gitea
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
With that configuration http://example.com/gitea/ will redirect to your Gitea instance.
|
|
||||||
|
|
||||||
then for the backend section
|
|
||||||
|
|
||||||
```
|
|
||||||
backend gitea
|
|
||||||
http-request replace-path /gitea\/?(.*) \/\1
|
|
||||||
server localhost:3000 check
|
|
||||||
```
|
|
||||||
|
|
||||||
The added http-request will automatically add a trailing slash if needed and internally remove /gitea from the path to allow it to work correctly with Gitea by setting properly http://example.com/gitea as the root.
|
|
||||||
|
|
||||||
Then you **MUST** set something like `[server] ROOT_URL = http://example.com/gitea/` correctly in your configuration.
|
|
||||||
|
|
||||||
## Traefik
|
|
||||||
|
|
||||||
If you want traefik to serve your Gitea instance, you can add the following label section to your `docker-compose.yaml` (Assuming the provider is docker).
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
gitea:
|
|
||||||
image: gitea/gitea
|
|
||||||
...
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.gitea.rule=Host(`example.com`)"
|
|
||||||
- "traefik.http.services.gitea-websecure.loadbalancer.server.port=3000"
|
|
||||||
```
|
|
||||||
|
|
||||||
This config assumes that you are handling HTTPS on the traefik side and using HTTP between Gitea and traefik.
|
|
||||||
|
|
||||||
## Traefik with a sub-path
|
|
||||||
|
|
||||||
In case you already have a site, and you want Gitea to share the domain name, you can setup Traefik to serve Gitea under a sub-path by adding the following to your `docker-compose.yaml` (Assuming the provider is docker) :
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
gitea:
|
|
||||||
image: gitea/gitea
|
|
||||||
...
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.gitea.rule=Host(`example.com`) && PathPrefix(`/gitea`)"
|
|
||||||
- "traefik.http.services.gitea-websecure.loadbalancer.server.port=3000"
|
|
||||||
- "traefik.http.middlewares.gitea-stripprefix.stripprefix.prefixes=/gitea"
|
|
||||||
- "traefik.http.routers.gitea.middlewares=gitea-stripprefix"
|
|
||||||
```
|
|
||||||
|
|
||||||
This config assumes that you are handling HTTPS on the traefik side and using HTTP between Gitea and traefik.
|
|
||||||
|
|
||||||
Then you **MUST** set something like `[server] ROOT_URL = http://example.com/gitea/` correctly in your configuration.
|
|
||||||
|
|
||||||
## General sub-path configuration
|
|
||||||
|
|
||||||
Usually it's not recommended to put Gitea in a sub-path, it's not widely used and may have some issues in rare cases.
|
|
||||||
|
|
||||||
If you really need to do so, to make Gitea works with sub-path (eg: `http://example.com/gitea/`), here are the requirements:
|
|
||||||
|
|
||||||
1. Set `[server] ROOT_URL = http://example.com/gitea/` in your `app.ini` file.
|
|
||||||
2. Make the reverse-proxy pass `http://example.com/gitea/foo` to `http://gitea-server:3000/foo`.
|
|
||||||
3. Make sure the reverse-proxy not decode the URI, the request `http://example.com/gitea/a%2Fb` should be passed as `http://gitea-server:3000/a%2Fb`.
|
|
||||||
|
|
||||||
## Docker / Container Registry
|
|
||||||
|
|
||||||
The container registry uses a fixed sub-path `/v2` which can't be changed.
|
|
||||||
Even if you deploy Gitea with a different sub-path, `/v2` will be used by the `docker` client.
|
|
||||||
Therefore you may need to add an additional route to your reverse proxy configuration.
|
|
|
@ -1,136 +0,0 @@
|
||||||
---
|
|
||||||
date: "2018-05-22T11:00:00+00:00"
|
|
||||||
title: "反向代理"
|
|
||||||
slug: "reverse-proxies"
|
|
||||||
sidebar_position: 16
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/reverse-proxies
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "反向代理"
|
|
||||||
sidebar_position: 16
|
|
||||||
identifier: "reverse-proxies"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 反向代理
|
|
||||||
|
|
||||||
## 使用 Nginx 作为反向代理服务
|
|
||||||
|
|
||||||
如果您想使用 Nginx 作为 Gitea 的反向代理服务,您可以参照以下 `nginx.conf` 配置中 `server` 的 `http` 部分:
|
|
||||||
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name git.example.com;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:3000;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 使用 Nginx 作为反向代理服务并将 Gitea 路由至一个子路径
|
|
||||||
|
|
||||||
如果您已经有一个域名并且想与 Gitea 共享该域名,您可以增加以下 `nginx.conf` 配置中 `server` 的 `http` 部分,为 Gitea 添加路由规则:
|
|
||||||
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name git.example.com;
|
|
||||||
|
|
||||||
# 注意: /git/ 最后需要有一个路径符号
|
|
||||||
location /git/ {
|
|
||||||
# 注意: 反向代理后端 URL 的最后需要有一个路径符号
|
|
||||||
proxy_pass http://localhost:3000/;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
然后您**必须**在 Gitea 的配置文件中正确的添加类似 `[server] ROOT_URL = http://git.example.com/git/` 的配置项。
|
|
||||||
|
|
||||||
## 使用 Apache HTTPD 作为反向代理服务
|
|
||||||
|
|
||||||
如果您想使用 Apache HTTPD 作为 Gitea 的反向代理服务,您可以为您的 Apache HTTPD 作如下配置(在 Ubuntu 中,配置文件通常在 `/etc/apache2/httpd.conf` 目录下):
|
|
||||||
|
|
||||||
```
|
|
||||||
<VirtualHost *:80>
|
|
||||||
...
|
|
||||||
ProxyPreserveHost On
|
|
||||||
ProxyRequests off
|
|
||||||
AllowEncodedSlashes NoDecode
|
|
||||||
ProxyPass / http://localhost:3000/ nocanon
|
|
||||||
</VirtualHost>
|
|
||||||
```
|
|
||||||
|
|
||||||
注:必须启用以下 Apache HTTPD 组件:`proxy`, `proxy_http`
|
|
||||||
|
|
||||||
## 使用 Apache HTTPD 作为反向代理服务并将 Gitea 路由至一个子路径
|
|
||||||
|
|
||||||
如果您已经有一个域名并且想与 Gitea 共享该域名,您可以增加以下配置为 Gitea 添加路由规则(在 Ubuntu 中,配置文件通常在 `/etc/apache2/httpd.conf` 目录下):
|
|
||||||
|
|
||||||
```
|
|
||||||
<VirtualHost *:80>
|
|
||||||
...
|
|
||||||
<Proxy *>
|
|
||||||
Order allow,deny
|
|
||||||
Allow from all
|
|
||||||
</Proxy>
|
|
||||||
AllowEncodedSlashes NoDecode
|
|
||||||
# 注意: 路径和 URL 后面都不要写路径符号 '/'
|
|
||||||
ProxyPass /git http://localhost:3000 nocanon
|
|
||||||
</VirtualHost>
|
|
||||||
```
|
|
||||||
|
|
||||||
然后您**必须**在 Gitea 的配置文件中正确的添加类似 `[server] ROOT_URL = http://git.example.com/git/` 的配置项。
|
|
||||||
|
|
||||||
注:必须启用以下 Apache HTTPD 组件:`proxy`, `proxy_http`
|
|
||||||
|
|
||||||
## 使用 Caddy 作为反向代理服务
|
|
||||||
|
|
||||||
如果您想使用 Caddy 作为 Gitea 的反向代理服务,您可以在 `Caddyfile` 中添加如下配置:
|
|
||||||
|
|
||||||
```
|
|
||||||
git.example.com {
|
|
||||||
proxy / http://localhost:3000
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 使用 Caddy 作为反向代理服务并将 Gitea 路由至一个子路径
|
|
||||||
|
|
||||||
如果您已经有一个域名并且想与 Gitea 共享该域名,您可以在您的 `Caddyfile` 文件中增加以下配置,为 Gitea 添加路由规则:
|
|
||||||
|
|
||||||
```
|
|
||||||
git.example.com {
|
|
||||||
# 注意: 路径 /git/ 最后需要有路径符号
|
|
||||||
proxy /git/ http://localhost:3000
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
然后您**必须**在 Gitea 的配置文件中正确的添加类似 `[server] ROOT_URL = http://git.example.com/git/` 的配置项。
|
|
||||||
|
|
||||||
## 使用 Traefik 作为反向代理服务
|
|
||||||
|
|
||||||
如果您想使用 traefik 作为 Gitea 的反向代理服务,您可以在 `docker-compose.yaml` 中添加 label 部分(假设使用 docker 作为 traefik 的 provider):
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
gitea:
|
|
||||||
image: gitea/gitea
|
|
||||||
...
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.gitea.rule=Host(`example.com`)"
|
|
||||||
- "traefik.http.services.gitea-websecure.loadbalancer.server.port=3000"
|
|
||||||
```
|
|
||||||
|
|
||||||
这份配置假设您使用 traefik 来处理 HTTPS 服务,并在其和 Gitea 之间使用 HTTP 进行通信。
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-12-31T13:55:00+05:00"
|
|
||||||
title: "Search Engines Indexation"
|
|
||||||
slug: "search-engines-indexation"
|
|
||||||
sidebar_position: 60
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/search-engines-indexation
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "Search Engines Indexation"
|
|
||||||
sidebar_position: 60
|
|
||||||
identifier: "search-engines-indexation"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Search engines indexation of your Gitea installation
|
|
||||||
|
|
||||||
By default your Gitea installation will be indexed by search engines.
|
|
||||||
If you don't want your repository to be visible for search engines read further.
|
|
||||||
|
|
||||||
## Block search engines indexation using robots.txt
|
|
||||||
|
|
||||||
To make Gitea serve a custom `robots.txt` (default: empty 404) for top level installations,
|
|
||||||
create a file with path `public/robots.txt` in the [`custom` folder or `CustomPath`](administration/customizing-gitea.md)
|
|
||||||
|
|
||||||
Examples on how to configure the `robots.txt` can be found at [https://moz.com/learn/seo/robotstxt](https://moz.com/learn/seo/robotstxt).
|
|
||||||
|
|
||||||
```txt
|
|
||||||
User-agent: *
|
|
||||||
Disallow: /
|
|
||||||
```
|
|
||||||
|
|
||||||
If you installed Gitea in a subdirectory, you will need to create or edit the `robots.txt` in the top level directory.
|
|
||||||
|
|
||||||
```txt
|
|
||||||
User-agent: *
|
|
||||||
Disallow: /gitea/
|
|
||||||
```
|
|
|
@ -1,39 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "搜索引擎索引"
|
|
||||||
slug: "search-engines-indexation"
|
|
||||||
sidebar_position: 60
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/search-engines-indexation
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "搜索引擎索引"
|
|
||||||
sidebar_position: 60
|
|
||||||
identifier: "search-engines-indexation"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Gitea 安装的搜索引擎索引
|
|
||||||
|
|
||||||
默认情况下,您的 Gitea 安装将被搜索引擎索引。
|
|
||||||
如果您不希望您的仓库对搜索引擎可见,请进一步阅读。
|
|
||||||
|
|
||||||
## 使用 robots.txt 阻止搜索引擎索引
|
|
||||||
|
|
||||||
为了使 Gitea 为顶级安装提供自定义的`robots.txt`(默认为空的 404),请在 [`custom`文件夹或`CustomPath`](administration/customizing-gitea.md)中创建一个名为 `public/robots.txt` 的文件。
|
|
||||||
|
|
||||||
有关如何配置 `robots.txt` 的示例,请参考 [https://moz.com/learn/seo/robotstxt](https://moz.com/learn/seo/robotstxt)。
|
|
||||||
|
|
||||||
```txt
|
|
||||||
User-agent: *
|
|
||||||
Disallow: /
|
|
||||||
```
|
|
||||||
|
|
||||||
如果您将Gitea安装在子目录中,则需要在顶级目录中创建或编辑 `robots.txt`。
|
|
||||||
|
|
||||||
```txt
|
|
||||||
User-agent: *
|
|
||||||
Disallow: /gitea/
|
|
||||||
```
|
|
|
@ -1,175 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-08-17T10:20:00+01:00"
|
|
||||||
title: "GPG Commit Signatures"
|
|
||||||
slug: "signing"
|
|
||||||
sidebar_position: 50
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/signing
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "GPG Commit Signatures"
|
|
||||||
sidebar_position: 50
|
|
||||||
identifier: "signing"
|
|
||||||
---
|
|
||||||
|
|
||||||
# GPG Commit Signatures
|
|
||||||
|
|
||||||
Gitea will verify GPG commit signatures in the provided tree by
|
|
||||||
checking if the commits are signed by a key within the Gitea database,
|
|
||||||
or if the commit matches the default key for Git.
|
|
||||||
|
|
||||||
Keys are not checked to determine if they have expired or revoked.
|
|
||||||
Keys are also not checked with keyservers.
|
|
||||||
|
|
||||||
A commit will be marked with a grey unlocked icon if no key can be
|
|
||||||
found to verify it. If a commit is marked with a red unlocked icon,
|
|
||||||
it is reported to be signed with a key with an id.
|
|
||||||
|
|
||||||
Please note: The signer of a commit does not have to be an author or
|
|
||||||
committer of a commit.
|
|
||||||
|
|
||||||
This functionality requires Git >= 1.7.9 but for full functionality
|
|
||||||
this requires Git >= 2.0.0.
|
|
||||||
|
|
||||||
## Automatic Signing
|
|
||||||
|
|
||||||
There are a number of places where Gitea will generate commits itself:
|
|
||||||
|
|
||||||
- Repository Initialisation
|
|
||||||
- Wiki Changes
|
|
||||||
- CRUD actions using the editor or the API
|
|
||||||
- Merges from Pull Requests
|
|
||||||
|
|
||||||
Depending on configuration and server trust you may want Gitea to
|
|
||||||
sign these commits.
|
|
||||||
|
|
||||||
## Installing and generating a GPG key for Gitea
|
|
||||||
|
|
||||||
It is up to a server administrator to determine how best to install
|
|
||||||
a signing key. Gitea generates all its commits using the server `git`
|
|
||||||
command at present - and therefore the server `gpg` will be used for
|
|
||||||
signing (if configured.) Administrators should review best-practices
|
|
||||||
for GPG - in particular it is probably advisable to only install a
|
|
||||||
signing secret subkey without the master signing and certifying secret
|
|
||||||
key.
|
|
||||||
|
|
||||||
## General Configuration
|
|
||||||
|
|
||||||
Gitea's configuration for signing can be found with the
|
|
||||||
`[repository.signing]` section of `app.ini`:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
...
|
|
||||||
[repository.signing]
|
|
||||||
SIGNING_KEY = default
|
|
||||||
SIGNING_NAME =
|
|
||||||
SIGNING_EMAIL =
|
|
||||||
INITIAL_COMMIT = always
|
|
||||||
CRUD_ACTIONS = pubkey, twofa, parentsigned
|
|
||||||
WIKI = never
|
|
||||||
MERGES = pubkey, twofa, basesigned, commitssigned
|
|
||||||
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
### `SIGNING_KEY`
|
|
||||||
|
|
||||||
The first option to discuss is the `SIGNING_KEY`. There are three main
|
|
||||||
options:
|
|
||||||
|
|
||||||
- `none` - this prevents Gitea from signing any commits
|
|
||||||
- `default` - Gitea will default to the key configured within `git config`
|
|
||||||
- `KEYID` - Gitea will sign commits with the gpg key with the ID
|
|
||||||
`KEYID`. In this case you should provide a `SIGNING_NAME` and
|
|
||||||
`SIGNING_EMAIL` to be displayed for this key.
|
|
||||||
|
|
||||||
The `default` option will interrogate `git config` for
|
|
||||||
`commit.gpgsign` option - if this is set, then it will use the results
|
|
||||||
of the `user.signingkey`, `user.name` and `user.email` as appropriate.
|
|
||||||
|
|
||||||
Please note: by adjusting Git's `config` file within Gitea's
|
|
||||||
repositories, `SIGNING_KEY=default` could be used to provide different
|
|
||||||
signing keys on a per-repository basis. However, this is clearly not an
|
|
||||||
ideal UI and therefore subject to change.
|
|
||||||
|
|
||||||
**Since 1.17**, Gitea runs git in its own home directory `[git].HOME_PATH` (default to `%(APP_DATA_PATH)/home`)
|
|
||||||
and uses its own config `{[git].HOME_PATH}/.gitconfig`.
|
|
||||||
If you have your own customized git config for Gitea, you should set these configs in system git config (aka `/etc/gitconfig`)
|
|
||||||
or the Gitea internal git config `{[git].HOME_PATH}/.gitconfig`.
|
|
||||||
Related home files for git command (like `.gnupg`) should also be put in Gitea's git home directory `[git].HOME_PATH`.
|
|
||||||
If you like to keep the `.gnupg` directory outside of `{[git].HOME_PATH}/`, consider setting the `$GNUPGHOME` environment variable to your preferred location.
|
|
||||||
|
|
||||||
### `INITIAL_COMMIT`
|
|
||||||
|
|
||||||
This option determines whether Gitea should sign the initial commit
|
|
||||||
when creating a repository. The possible values are:
|
|
||||||
|
|
||||||
- `never`: Never sign
|
|
||||||
- `pubkey`: Only sign if the user has a public key
|
|
||||||
- `twofa`: Only sign if the user logs in with two factor authentication
|
|
||||||
- `always`: Always sign
|
|
||||||
|
|
||||||
Options other than `never` and `always` can be combined as a comma
|
|
||||||
separated list. The commit will be signed if all selected options are true.
|
|
||||||
|
|
||||||
### `WIKI`
|
|
||||||
|
|
||||||
This options determines if Gitea should sign commits to the Wiki.
|
|
||||||
The possible values are:
|
|
||||||
|
|
||||||
- `never`: Never sign
|
|
||||||
- `pubkey`: Only sign if the user has a public key
|
|
||||||
- `twofa`: Only sign if the user logs in with two-factor authentication
|
|
||||||
- `parentsigned`: Only sign if the parent commit is signed.
|
|
||||||
- `always`: Always sign
|
|
||||||
|
|
||||||
Options other than `never` and `always` can be combined as a comma
|
|
||||||
separated list. The commit will be signed if all selected options are true.
|
|
||||||
|
|
||||||
### `CRUD_ACTIONS`
|
|
||||||
|
|
||||||
This option determines if Gitea should sign commits from the web
|
|
||||||
editor or API CRUD actions. The possible values are:
|
|
||||||
|
|
||||||
- `never`: Never sign
|
|
||||||
- `pubkey`: Only sign if the user has a public key
|
|
||||||
- `twofa`: Only sign if the user logs in with two-factor authentication
|
|
||||||
- `parentsigned`: Only sign if the parent commit is signed.
|
|
||||||
- `always`: Always sign
|
|
||||||
|
|
||||||
Options other than `never` and `always` can be combined as a comma
|
|
||||||
separated list. The change will be signed if all selected options are true.
|
|
||||||
|
|
||||||
### `MERGES`
|
|
||||||
|
|
||||||
This option determines if Gitea should sign merge commits from PRs.
|
|
||||||
The possible options are:
|
|
||||||
|
|
||||||
- `never`: Never sign
|
|
||||||
- `pubkey`: Only sign if the user has a public key
|
|
||||||
- `twofa`: Only sign if the user logs in with two-factor authentication
|
|
||||||
- `basesigned`: Only sign if the parent commit in the base repo is signed.
|
|
||||||
- `headsigned`: Only sign if the head commit in the head branch is signed.
|
|
||||||
- `commitssigned`: Only sign if all the commits in the head branch to the merge point are signed.
|
|
||||||
- `approved`: Only sign approved merges to a protected branch.
|
|
||||||
- `always`: Always sign
|
|
||||||
|
|
||||||
Options other than `never` and `always` can be combined as a comma
|
|
||||||
separated list. The merge will be signed if all selected options are true.
|
|
||||||
|
|
||||||
## Obtaining the Public Key of the Signing Key
|
|
||||||
|
|
||||||
The public key used to sign Gitea's commits can be obtained from the API at:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
/api/v1/signing-key.gpg
|
|
||||||
```
|
|
||||||
|
|
||||||
In cases where there is a repository specific key this can be obtained from:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
/api/v1/repos/:username/:reponame/signing-key.gpg
|
|
||||||
```
|
|
|
@ -1,142 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-23T09:00:00+08:00"
|
|
||||||
title: "GPG 提交签名"
|
|
||||||
slug: "signing"
|
|
||||||
sidebar_position: 50
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/signing
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "administration"
|
|
||||||
name: "GPG 提交签名"
|
|
||||||
sidebar_position: 50
|
|
||||||
identifier: "signing"
|
|
||||||
---
|
|
||||||
|
|
||||||
# GPG 提交签名
|
|
||||||
|
|
||||||
Gitea 将通过检查提交是否由 Gitea 数据库中的密钥签名,或者提交是否与 Git 的默认密钥匹配,来验证提供的树中的 GPG 提交签名。
|
|
||||||
|
|
||||||
密钥不会被检查以确定它们是否已过期或撤销。密钥也不会与密钥服务器进行检查。
|
|
||||||
|
|
||||||
如果找不到用于验证提交的密钥,提交将被标记为灰色的未锁定图标。如果提交被标记为红色的未锁定图标,则表示它使用带有 ID 的密钥签名。
|
|
||||||
|
|
||||||
请注意:提交的签署者不必是提交的作者或提交者。
|
|
||||||
|
|
||||||
此功能要求 Git >= 1.7.9,但要实现全部功能,需要 Git >= 2.0.0。
|
|
||||||
|
|
||||||
## 自动签名
|
|
||||||
|
|
||||||
有许多地方 Gitea 会生成提交:
|
|
||||||
|
|
||||||
- 仓库初始化
|
|
||||||
- Wiki 更改
|
|
||||||
- 使用编辑器或 API 进行的 CRUD 操作
|
|
||||||
- 从合并请求进行合并
|
|
||||||
|
|
||||||
根据配置和服务器信任,您可能希望 Gitea 对这些提交进行签名。
|
|
||||||
|
|
||||||
## 安装和生成 Gitea 的 GPG 密钥
|
|
||||||
|
|
||||||
如何安装签名密钥由服务器管理员决定。Gitea 目前使用服务器的 `git` 命令生成所有提交,因此将使用服务器的 `gpg` 进行签名(如果配置了)。管理员应该审查 GPG 的最佳实践 - 特别是可能建议仅安装签名的子密钥,而不是主签名和认证的密钥。
|
|
||||||
|
|
||||||
## 通用配置
|
|
||||||
|
|
||||||
Gitea 的签名配置可以在 `app.ini` 的 `[repository.signing]` 部分找到:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
...
|
|
||||||
[repository.signing]
|
|
||||||
SIGNING_KEY = default
|
|
||||||
SIGNING_NAME =
|
|
||||||
SIGNING_EMAIL =
|
|
||||||
INITIAL_COMMIT = always
|
|
||||||
CRUD_ACTIONS = pubkey, twofa, parentsigned
|
|
||||||
WIKI = never
|
|
||||||
MERGES = pubkey, twofa, basesigned, commitssigned
|
|
||||||
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
### `SIGNING_KEY`
|
|
||||||
|
|
||||||
首先讨论的选项是 `SIGNING_KEY`。有三个主要选项:
|
|
||||||
|
|
||||||
- `none` - 这将阻止 Gitea 对任何提交进行签名
|
|
||||||
- `default` - Gitea 将使用 `git config` 中配置的默认密钥
|
|
||||||
- `KEYID` - Gitea 将使用具有 ID `KEYID` 的 GPG 密钥对提交进行签名。在这种情况下,您应该提供 `SIGNING_NAME` 和 `SIGNING_EMAIL`,以便显示此密钥的信息。
|
|
||||||
|
|
||||||
`default` 选项将读取 `git config` 中的 `commit.gpgsign` 选项 - 如果设置了该选项,它将使用 `user.signingkey`、`user.name` 和 `user.email` 的结果。
|
|
||||||
|
|
||||||
请注意:通过在 Gitea 的仓库中调整 Git 的 `config` 文件,可以使用 `SIGNING_KEY=default` 为每个仓库提供不同的签名密钥。然而,这显然不是一个理想的用户界面,因此可能会发生更改。
|
|
||||||
|
|
||||||
**自 1.17 起**,Gitea 在自己的主目录 `[git].HOME_PATH`(默认为 `%(APP_DATA_PATH)/home`)中运行 git,并使用自己的配置文件 `{[git].HOME_PATH}/.gitconfig`。
|
|
||||||
如果您有自己定制的 Gitea git 配置,您应该将这些配置设置在系统 git 配置文件中(例如 `/etc/gitconfig`)或者 Gitea 的内部 git 配置文件 `{[git].HOME_PATH}/.gitconfig` 中。
|
|
||||||
与 git 命令相关的主目录文件(如 `.gnupg`)也应该放在 Gitea 的 git 主目录 `[git].HOME_PATH` 中。
|
|
||||||
如果您希望将 `.gnupg` 目录放在 `{[git].HOME_PATH}/` 之外的位置,请考虑设置 `$GNUPGHOME` 环境变量为您首选的位置。
|
|
||||||
|
|
||||||
### `INITIAL_COMMIT`
|
|
||||||
|
|
||||||
此选项确定在创建仓库时,Gitea 是否应该对初始提交进行签名。可能的取值有:
|
|
||||||
|
|
||||||
- `never`:从不签名
|
|
||||||
- `pubkey`:仅在用户拥有公钥时进行签名
|
|
||||||
- `twofa`:仅在用户使用 2FA 登录时进行签名
|
|
||||||
- `always`:始终签名
|
|
||||||
|
|
||||||
除了 `never` 和 `always` 之外的选项可以组合为逗号分隔的列表。如果所有选择的选项都为 true,则提交将被签名。
|
|
||||||
|
|
||||||
### `WIKI`
|
|
||||||
|
|
||||||
此选项确定 Gitea 是否应该对 Wiki 的提交进行签名。可能的取值有:
|
|
||||||
|
|
||||||
- `never`:从不签名
|
|
||||||
- `pubkey`:仅在用户拥有公钥时进行签名
|
|
||||||
- `twofa`:仅在用户使用 2FA 登录时进行签名
|
|
||||||
- `parentsigned`:仅在父提交已签名时进行签名。
|
|
||||||
- `always`:始终签名
|
|
||||||
|
|
||||||
除了 `never` 和 `always` 之外的选项可以组合为逗号分隔的列表。如果所有选择的选项都为 true,则提交将被签名。
|
|
||||||
|
|
||||||
### `CRUD_ACTIONS`
|
|
||||||
|
|
||||||
此选项确定 Gitea 是否应该对 Web 编辑器或 API CRUD 操作的提交进行签名。可能的取值有:
|
|
||||||
|
|
||||||
- `never`:从不签名
|
|
||||||
- `pubkey`:仅在用户拥有公钥时进行签名
|
|
||||||
- `twofa`:仅在用户使用 2FA 登录时进行签名
|
|
||||||
- `parentsigned`:仅在父提交已签名时进行签名。
|
|
||||||
- `always`:始终签名
|
|
||||||
|
|
||||||
除了 `never` 和 `always` 之外的选项可以组合为逗号分隔的列表。如果所有选择的选项都为 true,则更改将被签名。
|
|
||||||
|
|
||||||
### `MERGES`
|
|
||||||
|
|
||||||
此选项确定 Gitea 是否应该对 PR 的合并提交进行签名。可能的选项有:
|
|
||||||
|
|
||||||
- `never`:从不签名
|
|
||||||
- `pubkey`:仅在用户拥有公钥时进行签名
|
|
||||||
- `twofa`:仅在用户使用 2FA 登录时进行签名
|
|
||||||
- `basesigned`:仅在基础仓库中的父提交已签名时进行签名。
|
|
||||||
- `headsigned`:仅在头分支中的头提交已签名时进行签名。
|
|
||||||
- `commitssigned`:仅在头分支中的所有提交到合并点的提交都已签名时进行签名。
|
|
||||||
- `approved`:仅对已批准的合并到受保护分支的提交进行签名。
|
|
||||||
- `always`:始终签名
|
|
||||||
|
|
||||||
除了 `never` 和 `always` 之外的选项可以组合为逗号分隔的列表。如果所有选择的选项都为 true,则合并将被签名。
|
|
||||||
|
|
||||||
## 获取签名密钥的公钥
|
|
||||||
|
|
||||||
用于签署 Gitea 提交的公钥可以通过 API 获取:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
/api/v1/signing-key.gpg
|
|
||||||
```
|
|
||||||
|
|
||||||
在存在特定于仓库的密钥的情况下,可以通过以下方式获取:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
/api/v1/repos/:username/:reponame/signing-key.gpg
|
|
||||||
```
|
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
date: "2021-01-22T00:00:00+02:00"
|
|
||||||
title: "Contributing"
|
|
||||||
slug: "contributing"
|
|
||||||
sidebar_position: 35
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
name: "Contributing"
|
|
||||||
sidebar_position: 50
|
|
||||||
identifier: "contributing"
|
|
||||||
---
|
|
|
@ -1,124 +0,0 @@
|
||||||
---
|
|
||||||
date: "2021-11-01T23:41:00+08:00"
|
|
||||||
title: "Guidelines for Backend Development"
|
|
||||||
slug: "guidelines-backend"
|
|
||||||
sidebar_position: 20
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/guidelines-backend
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "contributing"
|
|
||||||
name: "Guidelines for Backend"
|
|
||||||
sidebar_position: 20
|
|
||||||
identifier: "guidelines-backend"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Guidelines for Backend Development
|
|
||||||
|
|
||||||
## Background
|
|
||||||
|
|
||||||
Gitea uses Golang as the backend programming language. It uses many third-party packages and also write some itself.
|
|
||||||
For example, Gitea uses [Chi](https://github.com/go-chi/chi) as basic web framework. [Xorm](https://xorm.io) is an ORM framework that is used to interact with the database.
|
|
||||||
So it's very important to manage these packages. Please take the below guidelines before you start to write backend code.
|
|
||||||
|
|
||||||
## Package Design Guideline
|
|
||||||
|
|
||||||
### Packages List
|
|
||||||
|
|
||||||
To maintain understandable code and avoid circular dependencies it is important to have a good code structure. The Gitea backend is divided into the following parts:
|
|
||||||
|
|
||||||
- `build`: Scripts to help build Gitea.
|
|
||||||
- `cmd`: All Gitea actual sub commands includes web, doctor, serv, hooks, admin and etc. `web` will start the web service. `serv` and `hooks` will be invoked by Git or OpenSSH. Other sub commands could help to maintain Gitea.
|
|
||||||
- `tests`: Common test utility functions
|
|
||||||
- `tests/integration`: Integration tests, to test back-end regressions
|
|
||||||
- `tests/e2e`: E2e tests, to test front-end and back-end compatibility and visual regressions.
|
|
||||||
- `models`: Contains the data structures used by xorm to construct database tables. It also contains functions to query and update the database. Dependencies to other Gitea code should be avoided. You can make exceptions in cases such as logging.
|
|
||||||
- `models/db`: Basic database operations. All other `models/xxx` packages should depend on this package. The `GetEngine` function should only be invoked from `models/`.
|
|
||||||
- `models/fixtures`: Sample data used in unit tests and integration tests. One `yml` file means one table which will be loaded into database when beginning the tests.
|
|
||||||
- `models/migrations`: Stores database migrations between versions. PRs that change a database structure **MUST** also have a migration step.
|
|
||||||
- `modules`: Different modules to handle specific functionality in Gitea. Work in Progress: Some of them should be moved to `services`, in particular those that depend on models because they rely on the database.
|
|
||||||
- `modules/setting`: Store all system configurations read from ini files and has been referenced by everywhere. But they should be used as function parameters when possible.
|
|
||||||
- `modules/git`: Package to interactive with `Git` command line or Gogit package.
|
|
||||||
- `public`: Compiled frontend files (javascript, images, css, etc.)
|
|
||||||
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) must not depend on routers.
|
|
||||||
- `routers/api` Contains routers for `/api/v1` aims to handle RESTful API requests.
|
|
||||||
- `routers/install` Could only respond when system is in INSTALL mode (INSTALL_LOCK=false).
|
|
||||||
- `routers/private` will only be invoked by internal sub commands, especially `serv` and `hooks`.
|
|
||||||
- `routers/web` will handle HTTP requests from web browsers or Git SMART HTTP protocols.
|
|
||||||
- `services`: Support functions for common routing operations or command executions. Uses `models` and `modules` to handle the requests.
|
|
||||||
- `templates`: Golang templates for generating the html output.
|
|
||||||
|
|
||||||
### Package Dependencies
|
|
||||||
|
|
||||||
Since Golang doesn't support import cycles, we have to decide the package dependencies carefully. There are some levels between those packages. Below is the ideal package dependencies direction.
|
|
||||||
|
|
||||||
`cmd` -> `routers` -> `services` -> `models` -> `modules`
|
|
||||||
|
|
||||||
From left to right, left packages could depend on right packages, but right packages MUST not depend on left packages. The sub packages on the same level could depend on according this level's rules.
|
|
||||||
|
|
||||||
**NOTICE**
|
|
||||||
|
|
||||||
Why do we need database transactions outside of `models`? And how?
|
|
||||||
Some actions should allow for rollback when database record insertion/update/deletion failed.
|
|
||||||
So services must be allowed to create a database transaction. Here is some example,
|
|
||||||
|
|
||||||
```go
|
|
||||||
// services/repository/repository.go
|
|
||||||
func CreateXXXX() error {
|
|
||||||
return db.WithTx(func(ctx context.Context) error {
|
|
||||||
// do something, if err is returned, it will rollback automatically
|
|
||||||
if err := issues.UpdateIssue(ctx, repoID); err != nil {
|
|
||||||
// ...
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// ...
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You should **not** use `db.GetEngine(ctx)` in `services` directly, but just write a function under `models/`.
|
|
||||||
If the function will be used in the transaction, just let `context.Context` as the function's first parameter.
|
|
||||||
|
|
||||||
```go
|
|
||||||
// models/issues/issue.go
|
|
||||||
func UpdateIssue(ctx context.Context, repoID int64) error {
|
|
||||||
e := db.GetEngine(ctx)
|
|
||||||
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Package Name
|
|
||||||
|
|
||||||
For the top level package, use a plural as package name, i.e. `services`, `models`, for sub packages, use singular,
|
|
||||||
i.e. `services/user`, `models/repository`.
|
|
||||||
|
|
||||||
### Import Alias
|
|
||||||
|
|
||||||
Since there are some packages which use the same package name, it is possible that you find packages like `modules/user`, `models/user`, and `services/user`. When these packages are imported in one Go file, it's difficult to know which package we are using and if it's a variable name or an import name. So, we always recommend to use import aliases. To differ from package variables which are commonly in camelCase, just use **snake_case** for import aliases.
|
|
||||||
i.e. `import user_service "code.gitea.io/gitea/services/user"`
|
|
||||||
|
|
||||||
### Implementing `io.Closer`
|
|
||||||
|
|
||||||
If a type implements `io.Closer`, calling `Close` multiple times must not fail or `panic` but return an error or `nil`.
|
|
||||||
|
|
||||||
### Important Gotchas
|
|
||||||
|
|
||||||
- Never write `x.Update(exemplar)` without an explicit `WHERE` clause:
|
|
||||||
- This will cause all rows in the table to be updated with the non-zero values of the exemplar - including IDs.
|
|
||||||
- You should usually write `x.ID(id).Update(exemplar)`.
|
|
||||||
- If during a migration you are inserting into a table using `x.Insert(exemplar)` where the ID is preset:
|
|
||||||
- You will need to ``SET IDENTITY_INSERT `table` ON`` for the MSSQL variant (the migration will fail otherwise)
|
|
||||||
- However, you will also need to update the id sequence for postgres - the migration will silently pass here but later insertions will fail:
|
|
||||||
``SELECT setval('table_name_id_seq', COALESCE((SELECT MAX(id)+1 FROM `table_name`), 1), false)``
|
|
||||||
|
|
||||||
### Future Tasks
|
|
||||||
|
|
||||||
Currently, we are creating some refactors to do the following things:
|
|
||||||
|
|
||||||
- Correct that codes which doesn't follow the rules.
|
|
||||||
- There are too many files in `models`, so we are moving some of them into a sub package `models/xxx`.
|
|
||||||
- Some `modules` sub packages should be moved to `services` because they depend on `models`.
|
|
|
@ -1,119 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-25T23:41:00+08:00"
|
|
||||||
title: "后端开发指南"
|
|
||||||
slug: "guidelines-backend"
|
|
||||||
sidebar_position: 20
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/guidelines-backend
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "contributing"
|
|
||||||
name: "后端开发指南"
|
|
||||||
sidebar_position: 20
|
|
||||||
identifier: "guidelines-backend"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 后端开发指南
|
|
||||||
|
|
||||||
## 背景
|
|
||||||
|
|
||||||
Gitea使用Golang作为后端编程语言。它使用了许多第三方包,并且自己也编写了一些包。
|
|
||||||
例如,Gitea使用[Chi](https://github.com/go-chi/chi)作为基本的Web框架。[Xorm](https://xorm.io)是一个用于与数据库交互的ORM框架。
|
|
||||||
因此,管理这些包非常重要。在开始编写后端代码之前,请参考以下准则。
|
|
||||||
|
|
||||||
## 包设计准则
|
|
||||||
|
|
||||||
### 包列表
|
|
||||||
|
|
||||||
为了保持易于理解的代码并避免循环依赖,拥有良好的代码结构是很重要的。Gitea后端分为以下几个部分:
|
|
||||||
|
|
||||||
- `build`:帮助构建Gitea的脚本。
|
|
||||||
- `cmd`:包含所有Gitea的实际子命令,包括web、doctor、serv、hooks、admin等。`web`将启动Web服务。`serv`和`hooks`将被Git或OpenSSH调用。其他子命令可以帮助维护Gitea。
|
|
||||||
- `tests`:常用的测试函数
|
|
||||||
- `tests/integration`:集成测试,用于测试后端回归。
|
|
||||||
- `tests/e2e`:端到端测试,用于测试前端和后端的兼容性和视觉回归。
|
|
||||||
- `models`:包含由xorm用于构建数据库表的数据结构。它还包含查询和更新数据库的函数。应避免与其他Gitea代码的依赖关系。在某些情况下,比如日志记录时可以例外。
|
|
||||||
- `models/db`:基本的数据库操作。所有其他`models/xxx`包都应依赖于此包。`GetEngine`函数只能从models/中调用。
|
|
||||||
- `models/fixtures`:单元测试和集成测试中使用的示例数据。一个`yml`文件表示一个将在测试开始时加载到数据库中的表。
|
|
||||||
- `models/migrations`:存储不同版本之间的数据库迁移。修改数据库结构的PR**必须**包含一个迁移步骤。
|
|
||||||
- `modules`:在Gitea中处理特定功能的不同模块。工作正在进行中:其中一些模块应该移到`services`中,特别是那些依赖于models的模块,因为它们依赖于数据库。
|
|
||||||
- `modules/setting`:存储从ini文件中读取的所有系统配置,并在各处引用。但是在可能的情况下,应将其作为函数参数使用。
|
|
||||||
- `modules/git`:用于与`Git`命令行或Gogit包交互的包。
|
|
||||||
- `public`:编译后的前端文件(JavaScript、图像、CSS等)
|
|
||||||
- `routers`:处理服务器请求。由于它使用其他Gitea包来处理请求,因此其他包(models、modules或services)不能依赖于routers。
|
|
||||||
- `routers/api`:包含`/api/v1`相关路由,用于处理RESTful API请求。
|
|
||||||
- `routers/install`:只能在系统处于安装模式(INSTALL_LOCK=false)时响应。
|
|
||||||
- `routers/private`:仅由内部子命令调用,特别是`serv`和`hooks`。
|
|
||||||
- `routers/web`:处理来自Web浏览器或Git SMART HTTP协议的HTTP请求。
|
|
||||||
- `services`:用于常见路由操作或命令执行的支持函数。使用`models`和`modules`来处理请求。
|
|
||||||
- `templates`:用于生成HTML输出的Golang模板。
|
|
||||||
|
|
||||||
### 包依赖关系
|
|
||||||
|
|
||||||
由于Golang不支持导入循环,我们必须仔细决定包之间的依赖关系。这些包之间有一些级别。以下是理想的包依赖关系方向。
|
|
||||||
|
|
||||||
`cmd` -> `routers` -> `services` -> `models` -> `modules`
|
|
||||||
|
|
||||||
从左到右,左侧的包可以依赖于右侧的包,但右侧的包不能依赖于左侧的包。在同一级别的子包中,可以根据该级别的规则进行依赖。
|
|
||||||
|
|
||||||
**注意事项**
|
|
||||||
|
|
||||||
为什么我们需要在`models`之外使用数据库事务?以及如何使用?
|
|
||||||
某些操作在数据库记录插入/更新/删除失败时应该允许回滚。
|
|
||||||
因此,服务必须能够创建数据库事务。以下是一些示例:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// services/repository/repository.go
|
|
||||||
func CreateXXXX() error {
|
|
||||||
return db.WithTx(func(ctx context.Context) error {
|
|
||||||
// do something, if err is returned, it will rollback automatically
|
|
||||||
if err := issues.UpdateIssue(ctx, repoID); err != nil {
|
|
||||||
// ...
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// ...
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
在`services`中**不应该**直接使用`db.GetEngine(ctx)`,而是应该在`models/`下编写一个函数。
|
|
||||||
如果该函数将在事务中使用,请将`context.Context`作为函数的第一个参数。
|
|
||||||
|
|
||||||
```go
|
|
||||||
// models/issues/issue.go
|
|
||||||
func UpdateIssue(ctx context.Context, repoID int64) error {
|
|
||||||
e := db.GetEngine(ctx)
|
|
||||||
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 包名称
|
|
||||||
|
|
||||||
对于顶层包,请使用复数作为包名,例如`services`、`models`,对于子包,请使用单数,例如`services/user`、`models/repository`。
|
|
||||||
|
|
||||||
### 导入别名
|
|
||||||
|
|
||||||
由于有一些使用相同包名的包,例如`modules/user`、`models/user`和`services/user`,当这些包在一个Go文件中被导入时,很难知道我们使用的是哪个包以及它是变量名还是导入名。因此,我们始终建议使用导入别名。为了与常见的驼峰命名法的包变量区分开,建议使用**snake_case**作为导入别名的命名规则。
|
|
||||||
例如:`import user_service "code.gitea.io/gitea/services/user"`
|
|
||||||
|
|
||||||
### 重要注意事项
|
|
||||||
|
|
||||||
- 永远不要写成`x.Update(exemplar)`,而没有明确的`WHERE`子句:
|
|
||||||
- 这将导致表中的所有行都被使用exemplar的非零值进行更新,包括ID。
|
|
||||||
- 通常应该写成`x.ID(id).Update(exemplar)`。
|
|
||||||
- 如果在迁移过程中使用`x.Insert(exemplar)`向表中插入记录,而ID是预设的:
|
|
||||||
- 对于MSSQL变体,你将需要执行``SET IDENTITY_INSERT `table` ON``(否则迁移将失败)
|
|
||||||
- 对于PostgreSQL,你还需要更新ID序列,否则迁移将悄无声息地通过,但后续的插入将失败:
|
|
||||||
``SELECT setval('table_name_id_seq', COALESCE((SELECT MAX(id)+1 FROM `table_name`), 1), false)``
|
|
||||||
|
|
||||||
### 未来的任务
|
|
||||||
|
|
||||||
目前,我们正在进行一些重构,以完成以下任务:
|
|
||||||
|
|
||||||
- 纠正不符合规则的代码。
|
|
||||||
- `models`中的文件太多了,所以我们正在将其中的一些移动到子包`models/xxx`中。
|
|
||||||
- 由于它们依赖于`models`,因此应将某些`modules`子包移动到`services`中。
|
|
|
@ -1,149 +0,0 @@
|
||||||
---
|
|
||||||
date: "2021-10-13T16:00:00+02:00"
|
|
||||||
title: "Guidelines for Frontend Development"
|
|
||||||
slug: "guidelines-frontend"
|
|
||||||
sidebar_position: 30
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/guidelines-frontend
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "contributing"
|
|
||||||
name: "Guidelines for Frontend"
|
|
||||||
sidebar_position: 30
|
|
||||||
identifier: "guidelines-frontend"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Guidelines for Frontend Development
|
|
||||||
|
|
||||||
## Background
|
|
||||||
|
|
||||||
Gitea uses [Fomantic-UI](https://fomantic-ui.com/introduction/getting-started.html) (based on [jQuery](https://api.jquery.com)) and [Vue3](https://vuejs.org/) for its frontend.
|
|
||||||
|
|
||||||
The HTML pages are rendered by [Go HTML Template](https://pkg.go.dev/html/template).
|
|
||||||
|
|
||||||
The source files can be found in the following directories:
|
|
||||||
|
|
||||||
* **CSS styles:** `web_src/css/`
|
|
||||||
* **JavaScript files:** `web_src/js/`
|
|
||||||
* **Vue components:** `web_src/js/components/`
|
|
||||||
* **Go HTML templates:** `templates/`
|
|
||||||
|
|
||||||
## General Guidelines
|
|
||||||
|
|
||||||
We recommend [Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.html) and [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html)
|
|
||||||
|
|
||||||
### Gitea specific guidelines:
|
|
||||||
|
|
||||||
1. Every feature (Fomantic-UI/jQuery module) should be put in separate files/directories.
|
|
||||||
2. HTML ids and classes should use kebab-case, it's preferred to contain 2-3 feature related keywords.
|
|
||||||
3. HTML ids and classes used in JavaScript should be unique for the whole project, and should contain 2-3 feature related keywords. We recommend to use the `js-` prefix for classes that are only used in JavaScript.
|
|
||||||
4. CSS styling for classes provided by frameworks should not be overwritten. Always use new class names with 2-3 feature related keywords to overwrite framework styles. Gitea's helper CSS classes in `helpers.less` could be helpful.
|
|
||||||
5. The backend can pass complex data to the frontend by using `ctx.PageData["myModuleData"] = map[]{}`, but do not expose whole models to the frontend to avoid leaking sensitive data.
|
|
||||||
6. Simple pages and SEO-related pages use Go HTML Template render to generate static Fomantic-UI HTML output. Complex pages can use Vue3.
|
|
||||||
7. Clarify variable types, prefer `elem.disabled = true` instead of `elem.setAttribute('disabled', 'anything')`, prefer `$el.prop('checked', var === 'yes')` instead of `$el.prop('checked', var)`.
|
|
||||||
8. Use semantic elements, prefer `<button class="ui button">` instead of `<div class="ui button">`.
|
|
||||||
9. Avoid unnecessary `!important` in CSS, add comments to explain why it's necessary if it can't be avoided.
|
|
||||||
10. Avoid mixing different events in one event listener, prefer to use individual event listeners for every event.
|
|
||||||
11. Custom event names are recommended to use `ce-` prefix.
|
|
||||||
12. Gitea's tailwind-style CSS classes use `gt-` prefix (`gt-relative`), while Gitea's own private framework-level CSS classes use `g-` prefix (`g-modal-confirm`).
|
|
||||||
13. Avoid inline scripts & styles as much as possible, it's recommended to put JS code into JS files and use CSS classes. If inline scripts & styles are unavoidable, explain the reason why it can't be avoided.
|
|
||||||
|
|
||||||
### Accessibility / ARIA
|
|
||||||
|
|
||||||
In history, Gitea heavily uses Fomantic UI which is not an accessibility-friendly framework.
|
|
||||||
Gitea uses some patches to make Fomantic UI more accessible (see `aria.md` and related JS files),
|
|
||||||
but there are still many problems which need a lot of work and time to fix.
|
|
||||||
|
|
||||||
### Framework Usage
|
|
||||||
|
|
||||||
Mixing different frameworks together is discouraged, it makes the code difficult to be maintained.
|
|
||||||
A JavaScript module should follow one major framework and follow the framework's best practice.
|
|
||||||
|
|
||||||
Recommended implementations:
|
|
||||||
|
|
||||||
* Vue + Vanilla JS
|
|
||||||
* Fomantic-UI (jQuery)
|
|
||||||
* htmx (partial page reloads for otherwise static components)
|
|
||||||
* Vanilla JS
|
|
||||||
|
|
||||||
Discouraged implementations:
|
|
||||||
|
|
||||||
* Vue + Fomantic-UI (jQuery)
|
|
||||||
* jQuery + Vanilla JS
|
|
||||||
* htmx + any other framework which requires heavy JS code, or unnecessary features like htmx scripting (`hx-on`)
|
|
||||||
|
|
||||||
To make UI consistent, Vue components can use Fomantic-UI CSS classes.
|
|
||||||
We use htmx for simple interactions. You can see an example for simple interactions where htmx should be used in this [PR](https://github.com/go-gitea/gitea/pull/28908). Do not use htmx if you require more advanced reactivity, use another framework (Vue/Vanilla JS).
|
|
||||||
Although mixing different frameworks is discouraged,
|
|
||||||
it should also work if the mixing is necessary and the code is well-designed and maintainable.
|
|
||||||
|
|
||||||
### `async` Functions
|
|
||||||
|
|
||||||
Only mark a function as `async` if and only if there are `await` calls
|
|
||||||
or `Promise` returns inside the function.
|
|
||||||
|
|
||||||
It's not recommended to use `async` event listeners, which may lead to problems.
|
|
||||||
The reason is that the code after await is executed outside the event dispatch.
|
|
||||||
Reference: https://github.com/github/eslint-plugin-github/blob/main/docs/rules/async-preventdefault.md
|
|
||||||
|
|
||||||
If an event listener must be `async`, the `e.preventDefault()` should be before any `await`,
|
|
||||||
it's recommended to put it at the beginning of the function.
|
|
||||||
|
|
||||||
If we want to call an `async` function in a non-async context,
|
|
||||||
it's recommended to use `const _promise = asyncFoo()` to tell readers
|
|
||||||
that this is done by purpose, we want to call the async function and ignore the Promise.
|
|
||||||
Some lint rules and IDEs also have warnings if the returned Promise is not handled.
|
|
||||||
|
|
||||||
### Fetching data
|
|
||||||
|
|
||||||
To fetch data, use the wrapper functions `GET`, `POST` etc. from `modules/fetch.js`. They
|
|
||||||
accept a `data` option for the content, will automatically set CSRF token and return a
|
|
||||||
Promise for a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).
|
|
||||||
|
|
||||||
### HTML Attributes and `dataset`
|
|
||||||
|
|
||||||
The usage of `dataset` is forbidden, its camel-casing behaviour makes it hard to grep for attributes.
|
|
||||||
However, there are still some special cases, so the current guideline is:
|
|
||||||
|
|
||||||
* For legacy code:
|
|
||||||
* `$.data()` should be refactored to `$.attr()`.
|
|
||||||
* `$.data()` can be used to bind some non-string data to elements in rare cases, but it is highly discouraged.
|
|
||||||
|
|
||||||
* For new code:
|
|
||||||
* `node.dataset` should not be used, use `node.getAttribute` instead.
|
|
||||||
* never bind any user data to a DOM node, use a suitable design pattern to describe the relation between node and data.
|
|
||||||
|
|
||||||
### Show/Hide Elements
|
|
||||||
|
|
||||||
* Vue components are recommended to use `v-if` and `v-show` to show/hide elements.
|
|
||||||
* Go template code should use Gitea's `.gt-hidden` and `showElem()/hideElem()/toggleElem()`, see more details in `.gt-hidden`'s comment.
|
|
||||||
|
|
||||||
### Styles and Attributes in Go HTML Template
|
|
||||||
|
|
||||||
It's recommended to use:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<div class="gt-name1 gt-name2 {{if .IsFoo}}gt-foo{{end}}" {{if .IsFoo}}data-foo{{end}}></div>
|
|
||||||
```
|
|
||||||
|
|
||||||
instead of:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<div class="gt-name1 gt-name2{{if .IsFoo}} gt-foo{{end}}"{{if .IsFoo}} data-foo{{end}}></div>
|
|
||||||
```
|
|
||||||
|
|
||||||
to make the code more readable.
|
|
||||||
|
|
||||||
### Legacy Code
|
|
||||||
|
|
||||||
A lot of legacy code already existed before this document's written. It's recommended to refactor legacy code to follow the guidelines.
|
|
||||||
|
|
||||||
### Vue3 and JSX
|
|
||||||
|
|
||||||
Gitea is using Vue3 now. We decided not to introduce JSX to keep the HTML and the JavaScript code separated.
|
|
||||||
|
|
||||||
### UI Examples
|
|
||||||
|
|
||||||
Gitea uses some self-made UI elements and customizes others to integrate them better into the general UI approach. When running Gitea in development mode (`RUN_MODE=dev`), a page with some standardized UI examples is available under `http(s)://your-gitea-url:port/devtest`.
|
|
|
@ -1,134 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-25T16:00:00+02:00"
|
|
||||||
title: "前端开发指南"
|
|
||||||
slug: "guidelines-frontend"
|
|
||||||
sidebar_position: 20
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/guidelines-frontend
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "contributing"
|
|
||||||
name: "前端开发指南"
|
|
||||||
sidebar_position: 20
|
|
||||||
identifier: "guidelines-frontend"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 前端开发指南
|
|
||||||
|
|
||||||
## 背景
|
|
||||||
|
|
||||||
Gitea 在其前端中使用[Fomantic-UI](https://fomantic-ui.com/introduction/getting-started.html)(基于[jQuery](https://api.jquery.com))和 [Vue3](https://vuejs.org/)。
|
|
||||||
|
|
||||||
HTML 页面由[Go HTML Template](https://pkg.go.dev/html/template)渲染。
|
|
||||||
|
|
||||||
源文件可以在以下目录中找到:
|
|
||||||
|
|
||||||
* **CSS 样式**: `web_src/css/`
|
|
||||||
* **JavaScript 文件**: `web_src/js/`
|
|
||||||
* **Vue 组件**: `web_src/js/components/`
|
|
||||||
* **Go HTML 模板**: `templates/`
|
|
||||||
|
|
||||||
## 通用准则
|
|
||||||
|
|
||||||
我们推荐使用[Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.html)和[Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html)。
|
|
||||||
|
|
||||||
## Gitea 特定准则:
|
|
||||||
|
|
||||||
1. 每个功能(Fomantic-UI/jQuery 模块)应放在单独的文件/目录中。
|
|
||||||
2. HTML 的 id 和 class 应使用 kebab-case,最好包含2-3个与功能相关的关键词。
|
|
||||||
3. 在 JavaScript 中使用的 HTML 的 id 和 class 应在整个项目中是唯一的,并且应包含2-3个与功能相关的关键词。建议在仅在 JavaScript 中使用的 class 中使用 `js-` 前缀。
|
|
||||||
4. 不应覆盖框架提供的 class 的 CSS 样式。始终使用具有2-3个与功能相关的关键词的新 class 名称来覆盖框架样式。Gitea 中的帮助 CSS 类在 `helpers.less` 中。
|
|
||||||
5. 后端可以通过使用`ctx.PageData["myModuleData"] = map[]{}`将复杂数据传递给前端,但不要将整个模型暴露给前端,以避免泄露敏感数据。
|
|
||||||
6. 简单页面和与 SEO 相关的页面使用 Go HTML 模板渲染生成静态的 Fomantic-UI HTML 输出。复杂页面可以使用 Vue3。
|
|
||||||
7. 明确变量类型,优先使用`elem.disabled = true`而不是`elem.setAttribute('disabled', 'anything')`,优先使用`$el.prop('checked', var === 'yes')`而不是`$el.prop('checked', var)`。
|
|
||||||
8. 使用语义化元素,优先使用`<button class="ui button">`而不是`<div class="ui button">`。
|
|
||||||
9. 避免在 CSS 中使用不必要的`!important`,如果无法避免,添加注释解释为什么需要它。
|
|
||||||
10. 避免在一个事件监听器中混合不同的事件,优先为每个事件使用独立的事件监听器。
|
|
||||||
11. 推荐使用自定义事件名称前缀`ce-`。
|
|
||||||
12. Gitea 的 tailwind-style CSS 类使用`gt-`前缀(`gt-relative`),而 Gitea 自身的私有框架级 CSS 类使用`g-`前缀(`g-modal-confirm`)。
|
|
||||||
|
|
||||||
### 可访问性 / ARIA
|
|
||||||
|
|
||||||
在历史上,Gitea大量使用了可访问性不友好的框架 Fomantic UI。
|
|
||||||
Gitea使用一些补丁使Fomantic UI更具可访问性(参见`aria.js`和`aria.md`),
|
|
||||||
但仍然存在许多问题需要大量的工作和时间来修复。
|
|
||||||
|
|
||||||
### 框架使用
|
|
||||||
|
|
||||||
不建议混合使用不同的框架,这会使代码难以维护。
|
|
||||||
一个 JavaScript 模块应遵循一个主要框架,并遵循该框架的最佳实践。
|
|
||||||
|
|
||||||
推荐的实现方式:
|
|
||||||
|
|
||||||
* Vue + Vanilla JS
|
|
||||||
* Fomantic-UI(jQuery)
|
|
||||||
* Vanilla JS
|
|
||||||
|
|
||||||
不推荐的实现方式:
|
|
||||||
|
|
||||||
* Vue + Fomantic-UI(jQuery)
|
|
||||||
* jQuery + Vanilla JS
|
|
||||||
|
|
||||||
为了保持界面一致,Vue 组件可以使用 Fomantic-UI 的 CSS 类。
|
|
||||||
尽管不建议混合使用不同的框架,
|
|
||||||
但如果混合使用是必要的,并且代码设计良好且易于维护,也可以工作。
|
|
||||||
|
|
||||||
### async 函数
|
|
||||||
|
|
||||||
只有当函数内部存在`await`调用或返回`Promise`时,才将函数标记为`async`。
|
|
||||||
|
|
||||||
不建议使用`async`事件监听器,这可能会导致问题。
|
|
||||||
原因是`await`后的代码在事件分发之外执行。
|
|
||||||
参考:https://github.com/github/eslint-plugin-github/blob/main/docs/rules/async-preventdefault.md
|
|
||||||
|
|
||||||
如果一个事件监听器必须是`async`,应在任何`await`之前使用`e.preventDefault()`,
|
|
||||||
建议将其放在函数的开头。
|
|
||||||
|
|
||||||
如果我们想在非异步上下文中调用`async`函数,
|
|
||||||
建议使用`const _promise = asyncFoo()`来告诉读者
|
|
||||||
这是有意为之的,我们想调用异步函数并忽略Promise。
|
|
||||||
一些 lint 规则和 IDE 也会在未处理返回的 Promise 时发出警告。
|
|
||||||
|
|
||||||
### HTML 属性和 dataset
|
|
||||||
|
|
||||||
禁止使用`dataset`,它的驼峰命名行为使得搜索属性变得困难。
|
|
||||||
然而,仍然存在一些特殊情况,因此当前的准则是:
|
|
||||||
|
|
||||||
* 对于旧代码:
|
|
||||||
* 应将`$.data()`重构为`$.attr()`。
|
|
||||||
* 在极少数情况下,可以使用`$.data()`将一些非字符串数据绑定到元素上,但强烈不推荐使用。
|
|
||||||
|
|
||||||
* 对于新代码:
|
|
||||||
* 不应使用`node.dataset`,而应使用`node.getAttribute`。
|
|
||||||
* 不要将任何用户数据绑定到 DOM 节点上,使用合适的设计模式描述节点和数据之间的关系。
|
|
||||||
|
|
||||||
### 显示/隐藏元素
|
|
||||||
|
|
||||||
* 推荐在Vue组件中使用`v-if`和`v-show`来显示/隐藏元素。
|
|
||||||
* Go 模板代码应使用 Gitea 的 `.gt-hidden` 和 `showElem()/hideElem()/toggleElem()` 来显示/隐藏元素,请参阅`.gt-hidden`的注释以获取更多详细信息。
|
|
||||||
|
|
||||||
### Go HTML 模板中的样式和属性
|
|
||||||
|
|
||||||
建议使用以下方式:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<div class="gt-name1 gt-name2 {{if .IsFoo}}gt-foo{{end}}" {{if .IsFoo}}data-foo{{end}}></div>
|
|
||||||
```
|
|
||||||
|
|
||||||
而不是:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<div class="gt-name1 gt-name2{{if .IsFoo}} gt-foo{{end}}"{{if .IsFoo}} data-foo{{end}}></div>
|
|
||||||
```
|
|
||||||
|
|
||||||
以使代码更易读。
|
|
||||||
|
|
||||||
### 旧代码
|
|
||||||
|
|
||||||
许多旧代码已经存在于本文撰写之前。建议重构旧代码以遵循指南。
|
|
||||||
|
|
||||||
### Vue3 和 JSX
|
|
||||||
|
|
||||||
Gitea 现在正在使用 Vue3。我们决定不引入 JSX,以保持 HTML 代码和 JavaScript 代码分离。
|
|
|
@ -1,49 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-02-14T00:00:00+00:00"
|
|
||||||
title: "Guidelines for Refactoring"
|
|
||||||
slug: "guidelines-refactoring"
|
|
||||||
sidebar_position: 40
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/guidelines-refactoring
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "contributing"
|
|
||||||
name: "Guidelines for Refactoring"
|
|
||||||
sidebar_position: 40
|
|
||||||
identifier: "guidelines-refactoring"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Guidelines for Refactoring
|
|
||||||
|
|
||||||
## Background
|
|
||||||
|
|
||||||
Since the first line of code was written at Feb 12, 2014, Gitea has grown to be a large project.
|
|
||||||
As a result, the codebase has become larger and larger. The larger the codebase is, the more difficult it is to maintain.
|
|
||||||
A lot of outdated mechanisms exist, a lot of frameworks are mixed together, some legacy code might cause bugs and block new features.
|
|
||||||
To make the codebase more maintainable and make Gitea better, developers should keep in mind to use modern mechanisms to refactor the old code.
|
|
||||||
|
|
||||||
This document is a collection of guidelines for refactoring the codebase.
|
|
||||||
|
|
||||||
## Refactoring Suggestions
|
|
||||||
|
|
||||||
* Design more about the future, but not only resolve the current problem.
|
|
||||||
* Reduce ambiguity, reduce conflicts, improve maintainability.
|
|
||||||
* Describe the refactoring, for example:
|
|
||||||
* Why the refactoring is needed.
|
|
||||||
* How the legacy problems would be solved.
|
|
||||||
* What's the Pros/Cons of the refactoring.
|
|
||||||
* Only do necessary changes, keep the old logic as much as possible.
|
|
||||||
* Introduce some intermediate steps to make the refactoring easier to review, a complete refactoring plan could be done in several PRs.
|
|
||||||
* If there is any divergence, the TOC(Technical Oversight Committee) should be involved to help to make decisions.
|
|
||||||
* Add necessary tests to make sure the refactoring is correct.
|
|
||||||
* Non-bug refactoring is preferred to be done at the beginning of a milestone, it would be easier to find problems before the release.
|
|
||||||
|
|
||||||
## Reviewing & Merging Suggestions
|
|
||||||
|
|
||||||
* A refactoring PR shouldn't be kept open for a long time (usually 7 days), it should be reviewed as soon as possible.
|
|
||||||
* A refactoring PR should be merged as soon as possible, it should not be blocked by other PRs.
|
|
||||||
* If there is no objection from TOC, a refactoring PR could be merged after 7 days with one core member's approval (not the author).
|
|
||||||
* Tolerate some dirty/hacky intermediate steps if the final result is good.
|
|
||||||
* Tolerate some regression bugs if the refactoring is necessary, fix bugs as soon as possible.
|
|
|
@ -1,49 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-25T00:00:00+00:00"
|
|
||||||
title: "重构指南"
|
|
||||||
slug: "guidelines-refactoring"
|
|
||||||
sidebar_position: 20
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/guidelines-refactoring
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "contributing"
|
|
||||||
name: "重构指南"
|
|
||||||
sidebar_position: 20
|
|
||||||
identifier: "guidelines-refactoring"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 重构指南
|
|
||||||
|
|
||||||
## 背景
|
|
||||||
|
|
||||||
自2014年2月12日编写了第一行代码以来,Gitea已经发展成为一个庞大的项目。
|
|
||||||
因此,代码库变得越来越大。代码库越大,维护就越困难。
|
|
||||||
存在许多过时的机制,许多框架混合在一起,一些遗留代码可能会导致错误并阻碍新功能的开发。
|
|
||||||
为了使代码库更易于维护,使Gitea变得更好,开发人员应牢记使用现代机制来重构旧代码。
|
|
||||||
|
|
||||||
本文档是关于重构代码库的指南集合。
|
|
||||||
|
|
||||||
## 重构建议
|
|
||||||
|
|
||||||
* 设计更多关于未来的内容,而不仅仅解决当前问题。
|
|
||||||
* 减少模糊性,减少冲突,提高可维护性。
|
|
||||||
* 描述重构,例如:
|
|
||||||
* 为什么需要重构。
|
|
||||||
* 如何解决旧问题。
|
|
||||||
* 重构的优点/缺点是什么。
|
|
||||||
* 只做必要的更改,尽量保留旧逻辑。
|
|
||||||
* 引入一些中间步骤,使重构更容易审查,完整的重构计划可以在几个PR中完成。
|
|
||||||
* 如果存在分歧,应该请TOC(技术监督委员会)参与决策。
|
|
||||||
* 添加必要的测试以确保重构的正确性。
|
|
||||||
* 非错误重构优先在里程碑的开始时进行,这样可以更容易地在发布之前发现问题。
|
|
||||||
|
|
||||||
## 审查和合并建议
|
|
||||||
|
|
||||||
* 重构的PR不应该长时间保持打开状态(通常为7天),应尽快进行审查。
|
|
||||||
* 重构的PR应尽快合并,不应被其他PR阻塞。
|
|
||||||
* 如果TOC没有异议,重构的PR可以在7天后由一名核心成员(非作者)批准后合并。
|
|
||||||
* 如果最终结果良好,容忍一些不完美/临时的步骤。
|
|
||||||
* 如果重构是必要的,容忍一些回归错误,并尽快修复错误。
|
|
|
@ -1,64 +0,0 @@
|
||||||
---
|
|
||||||
date: "2021-01-22T00:00:00+02:00"
|
|
||||||
title: "Übersetzungs Richtlinien"
|
|
||||||
slug: "localization"
|
|
||||||
sidebar_position: 70
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "contributing"
|
|
||||||
name: "Übersetzungsrichtlinien"
|
|
||||||
sidebar_position: 70
|
|
||||||
identifier: "localization"
|
|
||||||
---
|
|
||||||
|
|
||||||
## Allgemeines
|
|
||||||
|
|
||||||
Anrede: Wenig förmlich:
|
|
||||||
|
|
||||||
* "Du"-Form
|
|
||||||
* Keine "Amtsdeusch"-Umschreibungen, einfach so als ob man den Nutzer direkt persönlich ansprechen würde
|
|
||||||
|
|
||||||
Genauer definiert:
|
|
||||||
|
|
||||||
* "falsch" anstatt "nicht korrekt/inkorrekt"
|
|
||||||
* Benutzerkonto oder Konto? Oder Account?
|
|
||||||
* "Wende dich an ..." anstatt "kontaktiere ..."
|
|
||||||
* In der selben Zeit übersetzen (sonst wird aus "is" "war")
|
|
||||||
* Richtige Anführungszeichen verwenden. Also `"` statt `''` oder `'` oder \` oder `´`
|
|
||||||
* `„` für beginnende Anführungszeichen, `“` für schließende Anführungszeichen
|
|
||||||
|
|
||||||
Es gelten Artikel und Worttrennungen aus dem Duden.
|
|
||||||
|
|
||||||
## Formulierungen in Modals und Buttons
|
|
||||||
|
|
||||||
Es sollten die gleichen Formulierungen auf Buttons und Modals verwendet werden.
|
|
||||||
|
|
||||||
Beispiel: Wenn der Button mit `löschen` beschriftet ist, sollte im Modal die Frage lauten `Willst du das wirklich löschen?` und nicht `Willst du das wirklich entfernen?`. Gleiches gilt für Success/Errormeldungen nach der Aktion.
|
|
||||||
|
|
||||||
## Trennungen
|
|
||||||
|
|
||||||
* Pull-Request
|
|
||||||
* Time-Tracker
|
|
||||||
* E-Mail-Adresse (siehe Duden)
|
|
||||||
|
|
||||||
## Artikeldefinitionen für Anglizismen
|
|
||||||
|
|
||||||
* _Der_ Commit (m.)
|
|
||||||
* _Der_ Branch (m.), plural: die Branches
|
|
||||||
* _Das_ Issue (n.)
|
|
||||||
* _Der_ Fork (m.)
|
|
||||||
* _Das_ Repository (n.), plural: die Repositories
|
|
||||||
* _Der_ Pull-Request (m.)
|
|
||||||
* _Der_ Token (m.), plural: die Token
|
|
||||||
* _Das_ Review (n.)
|
|
||||||
* _Der_ Key (m.)
|
|
||||||
* _Der_ Committer (m.), plural: die Committer
|
|
||||||
|
|
||||||
## Weiterführende Links
|
|
||||||
|
|
||||||
Diese beiden Links sind sehr empfehlenswert:
|
|
||||||
|
|
||||||
* http://docs.translatehouse.org/projects/localization-guide/en/latest/guide/translation_guidelines_german.html
|
|
||||||
* https://docs.qgis.org/2.18/en/docs/documentation_guidelines/do_translations.html
|
|
|
@ -1,39 +0,0 @@
|
||||||
---
|
|
||||||
date: "2016-12-01T16:00:00+02:00"
|
|
||||||
title: "Localization"
|
|
||||||
slug: "localization"
|
|
||||||
sidebar_position: 70
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /en-us/localization
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "contributing"
|
|
||||||
name: "Localization"
|
|
||||||
sidebar_position: 70
|
|
||||||
identifier: "localization"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Localization
|
|
||||||
|
|
||||||
Gitea's localization happens through our [Crowdin project](https://crowdin.com/project/gitea).
|
|
||||||
|
|
||||||
For changes to an **English** translation, a pull request can be made that changes the appropriate key in
|
|
||||||
the [english locale](https://github.com/go-gitea/gitea/blob/main/options/locale/locale_en-US.ini).
|
|
||||||
|
|
||||||
For changes to a **non-English** translation, refer to the Crowdin project above.
|
|
||||||
|
|
||||||
## Supported Languages
|
|
||||||
|
|
||||||
Any language listed in the above Crowdin project will be supported as long as 25% or more has been translated.
|
|
||||||
|
|
||||||
After a translation has been accepted, it will be reflected in the main repository after the next Crowdin sync, which is generally after any PR is merged.
|
|
||||||
|
|
||||||
At the time of writing, this means that a changed translation may not appear until the following Gitea release.
|
|
||||||
|
|
||||||
If you use a bleeding edge build, it should appear as soon as you update after the change is synced.
|
|
||||||
|
|
||||||
# How to Contribute
|
|
||||||
|
|
||||||
Different Languages have different translation guidelines. Please visit the respective page for more information.
|
|
|
@ -1,34 +0,0 @@
|
||||||
---
|
|
||||||
date: "2016-12-01T16:00:00+02:00"
|
|
||||||
title: "本地化"
|
|
||||||
slug: "localization"
|
|
||||||
sidebar_position: 70
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
aliases:
|
|
||||||
- /zh-cn/localization
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "contributing"
|
|
||||||
name: "本地化"
|
|
||||||
sidebar_position: 70
|
|
||||||
identifier: "localization"
|
|
||||||
---
|
|
||||||
|
|
||||||
# 本地化
|
|
||||||
|
|
||||||
Gitea的本地化是通过我们的[Crowdin项目](https://crowdin.com/project/gitea)进行的。
|
|
||||||
|
|
||||||
对于对**英语翻译**的更改,可以发出pull-request,来更改[英语语言环境](https://github.com/go-gitea/gitea/blob/main/options/locale/locale_en-US.ini)中合适的关键字。
|
|
||||||
|
|
||||||
有关对**非英语**翻译的更改,请参阅上面的 Crowdin 项目。
|
|
||||||
|
|
||||||
## 支持的语言
|
|
||||||
|
|
||||||
上述 Crowdin 项目中列出的任何语言一旦翻译了 25% 或更多都将得到支持。
|
|
||||||
|
|
||||||
翻译被接受后,它将在下一次 Crowdin 同步后反映在主存储库中,这通常是在任何 PR 合并之后。
|
|
||||||
|
|
||||||
在撰写本文时,这意味着更改后的翻译可能要到 Gitea 的下一个版本才会出现。
|
|
||||||
|
|
||||||
如果使用开发版本,则在同步更改内容后,它应该会在更新后立即显示。
|
|
|
@ -1,17 +0,0 @@
|
||||||
---
|
|
||||||
date: "2023-05-25T00:00:00+02:00"
|
|
||||||
title: "翻译指南"
|
|
||||||
sidebar_position: 70
|
|
||||||
toc: true
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "contributing"
|
|
||||||
name: "翻译指南"
|
|
||||||
sidebar_position: 70
|
|
||||||
identifier: "translation-guidelines"
|
|
||||||
---
|
|
||||||
|
|
||||||
本页面用于提供一套通用规则,以确保翻译的一致性。
|
|
||||||
|
|
||||||
* [German](/de-de/übersetzungs-richtlinien/)
|
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
date: "2016-12-01T16:00:00+02:00"
|
|
||||||
title: "Development"
|
|
||||||
slug: "development"
|
|
||||||
sidebar_position: 40
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
name: "Development"
|
|
||||||
sidebar_position: 40
|
|
||||||
identifier: "development"
|
|
||||||
---
|
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
date: "2016-12-01T16:00:00+02:00"
|
|
||||||
title: "开发"
|
|
||||||
slug: "development"
|
|
||||||
sidebar_position: 40
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
name: "开发"
|
|
||||||
sidebar_position: 40
|
|
||||||
identifier: "development"
|
|
||||||
---
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue