Merge branch 'main' into actions-follow-logs

# Conflicts:
#	web_src/js/components/RepoActionView.vue
This commit is contained in:
bytedream 2024-12-20 00:29:53 +01:00
commit a0ca89e72c
2501 changed files with 97092 additions and 92562 deletions

View File

@ -2,9 +2,10 @@ root = "."
tmp_dir = ".air"
[build]
pre_cmd = ["killall -9 gitea 2>/dev/null || true"] # kill off potential zombie processes from previous runs
cmd = "make --no-print-directory backend"
bin = "gitea"
delay = 1000
delay = 2000
include_ext = ["go", "tmpl"]
include_file = ["main.go"]
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
@ -20,3 +21,6 @@ exclude_dir = [
]
exclude_regex = ["_test.go$", "_gen.go$"]
stop_on_error = true
[log]
main_only = true

View File

@ -1,16 +1,17 @@
{
"name": "Gitea DevContainer",
"image": "mcr.microsoft.com/devcontainers/go:1.22-bullseye",
"image": "mcr.microsoft.com/devcontainers/go:1.23-bookworm",
"features": {
// installs nodejs into container
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
"ghcr.io/devcontainers/features/git-lfs:1.1.0": {},
"ghcr.io/devcontainers/features/git-lfs:1.2.2": {},
"ghcr.io/devcontainers-contrib/features/poetry:2": {},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.12"
}
},
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}
},
"customizations": {
"vscode": {
@ -25,8 +26,9 @@
"Vue.volar",
"ms-azuretools.vscode-docker",
"vitest.explorer",
"qwtel.sqlite-viewer",
"GitHub.vscode-pull-request-github"
"cweijan.vscode-database-client2",
"GitHub.vscode-pull-request-github",
"Azurite.azurite"
]
}
},

View File

@ -14,7 +14,7 @@ _test
# MS VSCode
.vscode
__debug_bin
__debug_bin*
# Architecture specific extensions/prefixes
*.[568vq]
@ -78,7 +78,6 @@ cpu.out
/public/assets/css
/public/assets/fonts
/public/assets/img/avatar
/public/assets/img/webpack
/vendor
/web_src/fomantic/node_modules
/web_src/fomantic/build/*
@ -96,6 +95,9 @@ cpu.out
/.air
/.go-licenses
# Files and folders that were previously generated
/public/assets/img/webpack
# Snapcraft
snap/.snapcraft/
parts/

1
.envrc Normal file
View File

@ -0,0 +1 @@
use flake

999
.eslintrc.cjs Normal file
View File

@ -0,0 +1,999 @@
const restrictedSyntax = ['WithStatement', 'ForInStatement', 'LabeledStatement', 'SequenceExpression'];
module.exports = {
root: true,
reportUnusedDisableDirectives: true,
ignorePatterns: [
'/web_src/js/vendor',
'/web_src/fomantic',
'/public/assets/js',
],
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
ecmaVersion: 'latest',
project: true,
extraFileExtensions: ['.vue'],
parser: '@typescript-eslint/parser', // for vue plugin - https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser
},
settings: {
'import-x/extensions': ['.js', '.ts'],
'import-x/parsers': {
'@typescript-eslint/parser': ['.js', '.ts'],
},
'import-x/resolver': {
typescript: true,
},
},
plugins: [
'@eslint-community/eslint-plugin-eslint-comments',
'@stylistic/eslint-plugin-js',
'@typescript-eslint/eslint-plugin',
'eslint-plugin-array-func',
'eslint-plugin-github',
'eslint-plugin-import-x',
'eslint-plugin-no-jquery',
'eslint-plugin-no-use-extend-native',
'eslint-plugin-regexp',
'eslint-plugin-sonarjs',
'eslint-plugin-unicorn',
'eslint-plugin-vitest',
'eslint-plugin-vitest-globals',
'eslint-plugin-wc',
],
env: {
es2024: true,
node: true,
},
overrides: [
{
files: ['web_src/**/*'],
globals: {
__webpack_public_path__: true,
process: false, // https://github.com/webpack/webpack/issues/15833
},
},
{
files: ['web_src/**/*', 'docs/**/*'],
env: {
browser: true,
node: false,
},
},
{
files: ['*.config.*'],
rules: {
'import-x/no-unused-modules': [0],
},
},
{
files: ['**/*.d.ts'],
rules: {
'import-x/no-unused-modules': [0],
'@typescript-eslint/consistent-type-definitions': [0],
'@typescript-eslint/consistent-type-imports': [0],
},
},
{
files: ['web_src/js/types.ts'],
rules: {
'import-x/no-unused-modules': [0],
},
},
{
files: ['**/*.test.*', 'web_src/js/test/setup.ts'],
env: {
'vitest-globals/env': true,
},
rules: {
'vitest/consistent-test-filename': [0],
'vitest/consistent-test-it': [0],
'vitest/expect-expect': [0],
'vitest/max-expects': [0],
'vitest/max-nested-describe': [0],
'vitest/no-alias-methods': [0],
'vitest/no-commented-out-tests': [0],
'vitest/no-conditional-expect': [0],
'vitest/no-conditional-in-test': [0],
'vitest/no-conditional-tests': [0],
'vitest/no-disabled-tests': [0],
'vitest/no-done-callback': [0],
'vitest/no-duplicate-hooks': [0],
'vitest/no-focused-tests': [0],
'vitest/no-hooks': [0],
'vitest/no-identical-title': [2],
'vitest/no-interpolation-in-snapshots': [0],
'vitest/no-large-snapshots': [0],
'vitest/no-mocks-import': [0],
'vitest/no-restricted-matchers': [0],
'vitest/no-restricted-vi-methods': [0],
'vitest/no-standalone-expect': [0],
'vitest/no-test-prefixes': [0],
'vitest/no-test-return-statement': [0],
'vitest/prefer-called-with': [0],
'vitest/prefer-comparison-matcher': [0],
'vitest/prefer-each': [0],
'vitest/prefer-equality-matcher': [0],
'vitest/prefer-expect-resolves': [0],
'vitest/prefer-hooks-in-order': [0],
'vitest/prefer-hooks-on-top': [2],
'vitest/prefer-lowercase-title': [0],
'vitest/prefer-mock-promise-shorthand': [0],
'vitest/prefer-snapshot-hint': [0],
'vitest/prefer-spy-on': [0],
'vitest/prefer-strict-equal': [0],
'vitest/prefer-to-be': [0],
'vitest/prefer-to-be-falsy': [0],
'vitest/prefer-to-be-object': [0],
'vitest/prefer-to-be-truthy': [0],
'vitest/prefer-to-contain': [0],
'vitest/prefer-to-have-length': [0],
'vitest/prefer-todo': [0],
'vitest/require-hook': [0],
'vitest/require-to-throw-message': [0],
'vitest/require-top-level-describe': [0],
'vitest/valid-describe-callback': [2],
'vitest/valid-expect': [2],
'vitest/valid-title': [2],
},
},
{
files: ['web_src/js/modules/fetch.ts', 'web_src/js/standalone/**/*'],
rules: {
'no-restricted-syntax': [2, ...restrictedSyntax],
},
},
{
files: ['**/*.vue'],
plugins: [
'eslint-plugin-vue',
'eslint-plugin-vue-scoped-css',
],
extends: [
'plugin:vue/vue3-recommended',
'plugin:vue-scoped-css/vue3-recommended',
],
rules: {
'vue/attributes-order': [0],
'vue/html-closing-bracket-spacing': [2, {startTag: 'never', endTag: 'never', selfClosingTag: 'never'}],
'vue/max-attributes-per-line': [0],
'vue/singleline-html-element-content-newline': [0],
},
},
{
files: ['tests/e2e/**'],
plugins: [
'eslint-plugin-playwright'
],
extends: [
'plugin:playwright/recommended',
],
},
],
rules: {
'@eslint-community/eslint-comments/disable-enable-pair': [2],
'@eslint-community/eslint-comments/no-aggregating-enable': [2],
'@eslint-community/eslint-comments/no-duplicate-disable': [2],
'@eslint-community/eslint-comments/no-restricted-disable': [0],
'@eslint-community/eslint-comments/no-unlimited-disable': [2],
'@eslint-community/eslint-comments/no-unused-disable': [2],
'@eslint-community/eslint-comments/no-unused-enable': [2],
'@eslint-community/eslint-comments/no-use': [0],
'@eslint-community/eslint-comments/require-description': [0],
'@stylistic/js/array-bracket-newline': [0],
'@stylistic/js/array-bracket-spacing': [2, 'never'],
'@stylistic/js/array-element-newline': [0],
'@stylistic/js/arrow-parens': [2, 'always'],
'@stylistic/js/arrow-spacing': [2, {before: true, after: true}],
'@stylistic/js/block-spacing': [0],
'@stylistic/js/brace-style': [2, '1tbs', {allowSingleLine: true}],
'@stylistic/js/comma-dangle': [2, 'always-multiline'],
'@stylistic/js/comma-spacing': [2, {before: false, after: true}],
'@stylistic/js/comma-style': [2, 'last'],
'@stylistic/js/computed-property-spacing': [2, 'never'],
'@stylistic/js/dot-location': [2, 'property'],
'@stylistic/js/eol-last': [2],
'@stylistic/js/function-call-argument-newline': [0],
'@stylistic/js/function-call-spacing': [2, 'never'],
'@stylistic/js/function-paren-newline': [0],
'@stylistic/js/generator-star-spacing': [0],
'@stylistic/js/implicit-arrow-linebreak': [0],
'@stylistic/js/indent': [2, 2, {ignoreComments: true, SwitchCase: 1}],
'@stylistic/js/key-spacing': [2],
'@stylistic/js/keyword-spacing': [2],
'@stylistic/js/line-comment-position': [0],
'@stylistic/js/linebreak-style': [2, 'unix'],
'@stylistic/js/lines-around-comment': [0],
'@stylistic/js/lines-between-class-members': [0],
'@stylistic/js/max-len': [0],
'@stylistic/js/max-statements-per-line': [0],
'@stylistic/js/multiline-comment-style': [0],
'@stylistic/js/multiline-ternary': [0],
'@stylistic/js/new-parens': [2],
'@stylistic/js/newline-per-chained-call': [0],
'@stylistic/js/no-confusing-arrow': [0],
'@stylistic/js/no-extra-parens': [0],
'@stylistic/js/no-extra-semi': [2],
'@stylistic/js/no-floating-decimal': [0],
'@stylistic/js/no-mixed-operators': [0],
'@stylistic/js/no-mixed-spaces-and-tabs': [2],
'@stylistic/js/no-multi-spaces': [2, {ignoreEOLComments: true, exceptions: {Property: true}}],
'@stylistic/js/no-multiple-empty-lines': [2, {max: 1, maxEOF: 0, maxBOF: 0}],
'@stylistic/js/no-tabs': [2],
'@stylistic/js/no-trailing-spaces': [2],
'@stylistic/js/no-whitespace-before-property': [2],
'@stylistic/js/nonblock-statement-body-position': [2],
'@stylistic/js/object-curly-newline': [0],
'@stylistic/js/object-curly-spacing': [2, 'never'],
'@stylistic/js/object-property-newline': [0],
'@stylistic/js/one-var-declaration-per-line': [0],
'@stylistic/js/operator-linebreak': [2, 'after'],
'@stylistic/js/padded-blocks': [2, 'never'],
'@stylistic/js/padding-line-between-statements': [0],
'@stylistic/js/quote-props': [0],
'@stylistic/js/quotes': [2, 'single', {avoidEscape: true, allowTemplateLiterals: true}],
'@stylistic/js/rest-spread-spacing': [2, 'never'],
'@stylistic/js/semi': [2, 'always', {omitLastInOneLineBlock: true}],
'@stylistic/js/semi-spacing': [2, {before: false, after: true}],
'@stylistic/js/semi-style': [2, 'last'],
'@stylistic/js/space-before-blocks': [2, 'always'],
'@stylistic/js/space-before-function-paren': [2, {anonymous: 'ignore', named: 'never', asyncArrow: 'always'}],
'@stylistic/js/space-in-parens': [2, 'never'],
'@stylistic/js/space-infix-ops': [2],
'@stylistic/js/space-unary-ops': [2],
'@stylistic/js/spaced-comment': [2, 'always'],
'@stylistic/js/switch-colon-spacing': [2],
'@stylistic/js/template-curly-spacing': [2, 'never'],
'@stylistic/js/template-tag-spacing': [2, 'never'],
'@stylistic/js/wrap-iife': [2, 'inside'],
'@stylistic/js/wrap-regex': [0],
'@stylistic/js/yield-star-spacing': [2, 'after'],
'@typescript-eslint/adjacent-overload-signatures': [0],
'@typescript-eslint/array-type': [0],
'@typescript-eslint/await-thenable': [2],
'@typescript-eslint/ban-ts-comment': [2, {'ts-expect-error': false, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}],
'@typescript-eslint/ban-tslint-comment': [0],
'@typescript-eslint/class-literal-property-style': [0],
'@typescript-eslint/class-methods-use-this': [0],
'@typescript-eslint/consistent-generic-constructors': [0],
'@typescript-eslint/consistent-indexed-object-style': [0],
'@typescript-eslint/consistent-return': [0],
'@typescript-eslint/consistent-type-assertions': [2, {assertionStyle: 'as', objectLiteralTypeAssertions: 'allow'}],
'@typescript-eslint/consistent-type-definitions': [2, 'type'],
'@typescript-eslint/consistent-type-exports': [2, {fixMixedExportsWithInlineTypeSpecifier: false}],
'@typescript-eslint/consistent-type-imports': [2, {prefer: 'type-imports', fixStyle: 'separate-type-imports', disallowTypeAnnotations: true}],
'@typescript-eslint/default-param-last': [0],
'@typescript-eslint/dot-notation': [0],
'@typescript-eslint/explicit-function-return-type': [0],
'@typescript-eslint/explicit-member-accessibility': [0],
'@typescript-eslint/explicit-module-boundary-types': [0],
'@typescript-eslint/init-declarations': [0],
'@typescript-eslint/max-params': [0],
'@typescript-eslint/member-ordering': [0],
'@typescript-eslint/method-signature-style': [0],
'@typescript-eslint/naming-convention': [0],
'@typescript-eslint/no-array-constructor': [2],
'@typescript-eslint/no-array-delete': [2],
'@typescript-eslint/no-base-to-string': [0],
'@typescript-eslint/no-confusing-non-null-assertion': [2],
'@typescript-eslint/no-confusing-void-expression': [0],
'@typescript-eslint/no-deprecated': [2],
'@typescript-eslint/no-dupe-class-members': [0],
'@typescript-eslint/no-duplicate-enum-values': [2],
'@typescript-eslint/no-duplicate-type-constituents': [2, {ignoreUnions: true}],
'@typescript-eslint/no-dynamic-delete': [0],
'@typescript-eslint/no-empty-function': [0],
'@typescript-eslint/no-empty-interface': [0],
'@typescript-eslint/no-empty-object-type': [2],
'@typescript-eslint/no-explicit-any': [0],
'@typescript-eslint/no-extra-non-null-assertion': [2],
'@typescript-eslint/no-extraneous-class': [0],
'@typescript-eslint/no-floating-promises': [0],
'@typescript-eslint/no-for-in-array': [2],
'@typescript-eslint/no-implied-eval': [2],
'@typescript-eslint/no-import-type-side-effects': [0], // dupe with consistent-type-imports
'@typescript-eslint/no-inferrable-types': [0],
'@typescript-eslint/no-invalid-this': [0],
'@typescript-eslint/no-invalid-void-type': [0],
'@typescript-eslint/no-loop-func': [0],
'@typescript-eslint/no-loss-of-precision': [0],
'@typescript-eslint/no-magic-numbers': [0],
'@typescript-eslint/no-meaningless-void-operator': [0],
'@typescript-eslint/no-misused-new': [2],
'@typescript-eslint/no-misused-promises': [2, {checksVoidReturn: {attributes: false, arguments: false}}],
'@typescript-eslint/no-mixed-enums': [0],
'@typescript-eslint/no-namespace': [2],
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': [0],
'@typescript-eslint/no-non-null-asserted-optional-chain': [2],
'@typescript-eslint/no-non-null-assertion': [0],
'@typescript-eslint/no-redeclare': [0],
'@typescript-eslint/no-redundant-type-constituents': [2],
'@typescript-eslint/no-require-imports': [2],
'@typescript-eslint/no-restricted-imports': [0],
'@typescript-eslint/no-restricted-types': [0],
'@typescript-eslint/no-shadow': [0],
'@typescript-eslint/no-this-alias': [0], // handled by unicorn/no-this-assignment
'@typescript-eslint/no-unnecessary-boolean-literal-compare': [0],
'@typescript-eslint/no-unnecessary-condition': [0],
'@typescript-eslint/no-unnecessary-qualifier': [0],
'@typescript-eslint/no-unnecessary-template-expression': [0],
'@typescript-eslint/no-unnecessary-type-arguments': [0],
'@typescript-eslint/no-unnecessary-type-assertion': [2],
'@typescript-eslint/no-unnecessary-type-constraint': [2],
'@typescript-eslint/no-unsafe-argument': [0],
'@typescript-eslint/no-unsafe-assignment': [0],
'@typescript-eslint/no-unsafe-call': [0],
'@typescript-eslint/no-unsafe-declaration-merging': [2],
'@typescript-eslint/no-unsafe-enum-comparison': [2],
'@typescript-eslint/no-unsafe-function-type': [2],
'@typescript-eslint/no-unsafe-member-access': [0],
'@typescript-eslint/no-unsafe-return': [0],
'@typescript-eslint/no-unsafe-unary-minus': [2],
'@typescript-eslint/no-unused-expressions': [0],
'@typescript-eslint/no-unused-vars': [2, {vars: 'all', args: 'all', caughtErrors: 'all', ignoreRestSiblings: false, argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_'}],
'@typescript-eslint/no-use-before-define': [0],
'@typescript-eslint/no-useless-constructor': [0],
'@typescript-eslint/no-useless-empty-export': [0],
'@typescript-eslint/no-wrapper-object-types': [2],
'@typescript-eslint/non-nullable-type-assertion-style': [0],
'@typescript-eslint/only-throw-error': [2],
'@typescript-eslint/parameter-properties': [0],
'@typescript-eslint/prefer-as-const': [2],
'@typescript-eslint/prefer-destructuring': [0],
'@typescript-eslint/prefer-enum-initializers': [0],
'@typescript-eslint/prefer-find': [2],
'@typescript-eslint/prefer-for-of': [2],
'@typescript-eslint/prefer-function-type': [2],
'@typescript-eslint/prefer-includes': [2],
'@typescript-eslint/prefer-literal-enum-member': [0],
'@typescript-eslint/prefer-namespace-keyword': [0],
'@typescript-eslint/prefer-nullish-coalescing': [0],
'@typescript-eslint/prefer-optional-chain': [2, {requireNullish: true}],
'@typescript-eslint/prefer-promise-reject-errors': [0],
'@typescript-eslint/prefer-readonly': [0],
'@typescript-eslint/prefer-readonly-parameter-types': [0],
'@typescript-eslint/prefer-reduce-type-parameter': [0],
'@typescript-eslint/prefer-regexp-exec': [0],
'@typescript-eslint/prefer-return-this-type': [0],
'@typescript-eslint/prefer-string-starts-ends-with': [2, {allowSingleElementEquality: 'always'}],
'@typescript-eslint/promise-function-async': [0],
'@typescript-eslint/require-array-sort-compare': [0],
'@typescript-eslint/require-await': [0],
'@typescript-eslint/restrict-plus-operands': [2],
'@typescript-eslint/restrict-template-expressions': [0],
'@typescript-eslint/return-await': [0],
'@typescript-eslint/strict-boolean-expressions': [0],
'@typescript-eslint/switch-exhaustiveness-check': [0],
'@typescript-eslint/triple-slash-reference': [2],
'@typescript-eslint/typedef': [0],
'@typescript-eslint/unbound-method': [0], // too many false-positives
'@typescript-eslint/unified-signatures': [2],
'accessor-pairs': [2],
'array-callback-return': [2, {checkForEach: true}],
'array-func/avoid-reverse': [2],
'array-func/from-map': [2],
'array-func/no-unnecessary-this-arg': [2],
'array-func/prefer-array-from': [2],
'array-func/prefer-flat-map': [0], // handled by unicorn/prefer-array-flat-map
'array-func/prefer-flat': [0], // handled by unicorn/prefer-array-flat
'arrow-body-style': [0],
'block-scoped-var': [2],
'camelcase': [0],
'capitalized-comments': [0],
'class-methods-use-this': [0],
'complexity': [0],
'consistent-return': [0],
'consistent-this': [0],
'constructor-super': [2],
'curly': [0],
'default-case-last': [2],
'default-case': [0],
'default-param-last': [0],
'dot-notation': [0],
'eqeqeq': [2],
'for-direction': [2],
'func-name-matching': [2],
'func-names': [0],
'func-style': [0],
'getter-return': [2],
'github/a11y-aria-label-is-well-formatted': [0],
'github/a11y-no-title-attribute': [0],
'github/a11y-no-visually-hidden-interactive-element': [0],
'github/a11y-role-supports-aria-props': [0],
'github/a11y-svg-has-accessible-name': [0],
'github/array-foreach': [0],
'github/async-currenttarget': [2],
'github/async-preventdefault': [2],
'github/authenticity-token': [0],
'github/get-attribute': [0],
'github/js-class-name': [0],
'github/no-blur': [0],
'github/no-d-none': [0],
'github/no-dataset': [2],
'github/no-dynamic-script-tag': [2],
'github/no-implicit-buggy-globals': [2],
'github/no-inner-html': [0],
'github/no-innerText': [2],
'github/no-then': [2],
'github/no-useless-passive': [2],
'github/prefer-observers': [2],
'github/require-passive-events': [2],
'github/unescaped-html-literal': [0],
'grouped-accessor-pairs': [2],
'guard-for-in': [0],
'id-blacklist': [0],
'id-length': [0],
'id-match': [0],
'import-x/consistent-type-specifier-style': [0],
'import-x/default': [0],
'import-x/dynamic-import-chunkname': [0],
'import-x/export': [2],
'import-x/exports-last': [0],
'import-x/extensions': [2, 'always', {ignorePackages: true}],
'import-x/first': [2],
'import-x/group-exports': [0],
'import-x/max-dependencies': [0],
'import-x/named': [2],
'import-x/namespace': [0],
'import-x/newline-after-import': [0],
'import-x/no-absolute-path': [0],
'import-x/no-amd': [2],
'import-x/no-anonymous-default-export': [0],
'import-x/no-commonjs': [2],
'import-x/no-cycle': [2, {ignoreExternal: true, maxDepth: 1}],
'import-x/no-default-export': [0],
'import-x/no-deprecated': [0],
'import-x/no-dynamic-require': [0],
'import-x/no-empty-named-blocks': [2],
'import-x/no-extraneous-dependencies': [2],
'import-x/no-import-module-exports': [0],
'import-x/no-internal-modules': [0],
'import-x/no-mutable-exports': [0],
'import-x/no-named-as-default-member': [0],
'import-x/no-named-as-default': [0],
'import-x/no-named-default': [0],
'import-x/no-named-export': [0],
'import-x/no-namespace': [0],
'import-x/no-nodejs-modules': [0],
'import-x/no-relative-packages': [0],
'import-x/no-relative-parent-imports': [0],
'import-x/no-restricted-paths': [0],
'import-x/no-self-import': [2],
'import-x/no-unassigned-import': [0],
'import-x/no-unresolved': [2, {commonjs: true, ignore: ['\\?.+$']}],
'import-x/no-unused-modules': [2, {unusedExports: true}],
'import-x/no-useless-path-segments': [2, {commonjs: true}],
'import-x/no-webpack-loader-syntax': [2],
'import-x/order': [0],
'import-x/prefer-default-export': [0],
'import-x/unambiguous': [0],
'init-declarations': [0],
'line-comment-position': [0],
'logical-assignment-operators': [0],
'max-classes-per-file': [0],
'max-depth': [0],
'max-lines-per-function': [0],
'max-lines': [0],
'max-nested-callbacks': [0],
'max-params': [0],
'max-statements': [0],
'multiline-comment-style': [2, 'separate-lines'],
'new-cap': [0],
'no-alert': [0],
'no-array-constructor': [0], // handled by @typescript-eslint/no-array-constructor
'no-async-promise-executor': [0],
'no-await-in-loop': [0],
'no-bitwise': [0],
'no-buffer-constructor': [0],
'no-caller': [2],
'no-case-declarations': [2],
'no-class-assign': [2],
'no-compare-neg-zero': [2],
'no-cond-assign': [2, 'except-parens'],
'no-console': [1, {allow: ['debug', 'info', 'warn', 'error']}],
'no-const-assign': [2],
'no-constant-binary-expression': [2],
'no-constant-condition': [0],
'no-constructor-return': [2],
'no-continue': [0],
'no-control-regex': [0],
'no-debugger': [1],
'no-delete-var': [2],
'no-div-regex': [0],
'no-dupe-args': [2],
'no-dupe-class-members': [2],
'no-dupe-else-if': [2],
'no-dupe-keys': [2],
'no-duplicate-case': [2],
'no-duplicate-imports': [0],
'no-else-return': [2],
'no-empty-character-class': [2],
'no-empty-function': [0],
'no-empty-pattern': [2],
'no-empty-static-block': [2],
'no-empty': [2, {allowEmptyCatch: true}],
'no-eq-null': [2],
'no-eval': [2],
'no-ex-assign': [2],
'no-extend-native': [2],
'no-extra-bind': [2],
'no-extra-boolean-cast': [2],
'no-extra-label': [0],
'no-fallthrough': [2],
'no-func-assign': [2],
'no-global-assign': [2],
'no-implicit-coercion': [2],
'no-implicit-globals': [0],
'no-implied-eval': [0], // handled by @typescript-eslint/no-implied-eval
'no-import-assign': [2],
'no-inline-comments': [0],
'no-inner-declarations': [2],
'no-invalid-regexp': [2],
'no-invalid-this': [0],
'no-irregular-whitespace': [2],
'no-iterator': [2],
'no-jquery/no-ajax-events': [2],
'no-jquery/no-ajax': [2],
'no-jquery/no-and-self': [2],
'no-jquery/no-animate-toggle': [2],
'no-jquery/no-animate': [2],
'no-jquery/no-append-html': [2],
'no-jquery/no-attr': [2],
'no-jquery/no-bind': [2],
'no-jquery/no-box-model': [2],
'no-jquery/no-browser': [2],
'no-jquery/no-camel-case': [2],
'no-jquery/no-class-state': [2],
'no-jquery/no-class': [0],
'no-jquery/no-clone': [2],
'no-jquery/no-closest': [0],
'no-jquery/no-constructor-attributes': [2],
'no-jquery/no-contains': [2],
'no-jquery/no-context-prop': [2],
'no-jquery/no-css': [2],
'no-jquery/no-data': [0],
'no-jquery/no-deferred': [2],
'no-jquery/no-delegate': [2],
'no-jquery/no-done-fail': [2],
'no-jquery/no-each-collection': [0],
'no-jquery/no-each-util': [0],
'no-jquery/no-each': [0],
'no-jquery/no-error-shorthand': [2],
'no-jquery/no-error': [2],
'no-jquery/no-escape-selector': [2],
'no-jquery/no-event-shorthand': [2],
'no-jquery/no-extend': [2],
'no-jquery/no-fade': [2],
'no-jquery/no-filter': [0],
'no-jquery/no-find-collection': [0],
'no-jquery/no-find-util': [2],
'no-jquery/no-find': [0],
'no-jquery/no-fx-interval': [2],
'no-jquery/no-fx': [2],
'no-jquery/no-global-eval': [2],
'no-jquery/no-global-selector': [0],
'no-jquery/no-grep': [2],
'no-jquery/no-has': [2],
'no-jquery/no-hold-ready': [2],
'no-jquery/no-html': [0],
'no-jquery/no-in-array': [2],
'no-jquery/no-is-array': [2],
'no-jquery/no-is-empty-object': [2],
'no-jquery/no-is-function': [2],
'no-jquery/no-is-numeric': [2],
'no-jquery/no-is-plain-object': [2],
'no-jquery/no-is-window': [2],
'no-jquery/no-is': [2],
'no-jquery/no-jquery-constructor': [0],
'no-jquery/no-live': [2],
'no-jquery/no-load-shorthand': [2],
'no-jquery/no-load': [2],
'no-jquery/no-map-collection': [0],
'no-jquery/no-map-util': [2],
'no-jquery/no-map': [2],
'no-jquery/no-merge': [2],
'no-jquery/no-node-name': [2],
'no-jquery/no-noop': [2],
'no-jquery/no-now': [2],
'no-jquery/no-on-ready': [2],
'no-jquery/no-other-methods': [0],
'no-jquery/no-other-utils': [2],
'no-jquery/no-param': [2],
'no-jquery/no-parent': [0],
'no-jquery/no-parents': [2],
'no-jquery/no-parse-html-literal': [2],
'no-jquery/no-parse-html': [2],
'no-jquery/no-parse-json': [2],
'no-jquery/no-parse-xml': [2],
'no-jquery/no-prop': [2],
'no-jquery/no-proxy': [2],
'no-jquery/no-ready-shorthand': [2],
'no-jquery/no-ready': [2],
'no-jquery/no-selector-prop': [2],
'no-jquery/no-serialize': [2],
'no-jquery/no-size': [2],
'no-jquery/no-sizzle': [2],
'no-jquery/no-slide': [2],
'no-jquery/no-sub': [2],
'no-jquery/no-support': [2],
'no-jquery/no-text': [2],
'no-jquery/no-trigger': [0],
'no-jquery/no-trim': [2],
'no-jquery/no-type': [2],
'no-jquery/no-unique': [2],
'no-jquery/no-unload-shorthand': [2],
'no-jquery/no-val': [0],
'no-jquery/no-visibility': [2],
'no-jquery/no-when': [2],
'no-jquery/no-wrap': [2],
'no-jquery/variable-pattern': [2],
'no-label-var': [2],
'no-labels': [0], // handled by no-restricted-syntax
'no-lone-blocks': [2],
'no-lonely-if': [0],
'no-loop-func': [0],
'no-loss-of-precision': [2],
'no-magic-numbers': [0],
'no-misleading-character-class': [2],
'no-multi-assign': [0],
'no-multi-str': [2],
'no-negated-condition': [0],
'no-nested-ternary': [0],
'no-new-func': [2],
'no-new-native-nonconstructor': [2],
'no-new-object': [2],
'no-new-symbol': [2],
'no-new-wrappers': [2],
'no-new': [0],
'no-nonoctal-decimal-escape': [2],
'no-obj-calls': [2],
'no-octal-escape': [2],
'no-octal': [2],
'no-param-reassign': [0],
'no-plusplus': [0],
'no-promise-executor-return': [0],
'no-proto': [2],
'no-prototype-builtins': [2],
'no-redeclare': [0], // must be disabled for typescript overloads
'no-regex-spaces': [2],
'no-restricted-exports': [0],
'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-imports': [0],
'no-restricted-syntax': [2, ...restrictedSyntax, {selector: 'CallExpression[callee.name="fetch"]', message: 'use modules/fetch.ts instead'}],
'no-return-assign': [0],
'no-script-url': [2],
'no-self-assign': [2, {props: true}],
'no-self-compare': [2],
'no-sequences': [2],
'no-setter-return': [2],
'no-shadow-restricted-names': [2],
'no-shadow': [0],
'no-sparse-arrays': [2],
'no-template-curly-in-string': [2],
'no-ternary': [0],
'no-this-before-super': [2],
'no-throw-literal': [2],
'no-undef-init': [2],
'no-undef': [0],
'no-undefined': [0],
'no-underscore-dangle': [0],
'no-unexpected-multiline': [2],
'no-unmodified-loop-condition': [2],
'no-unneeded-ternary': [2],
'no-unreachable-loop': [2],
'no-unreachable': [2],
'no-unsafe-finally': [2],
'no-unsafe-negation': [2],
'no-unused-expressions': [2],
'no-unused-labels': [2],
'no-unused-private-class-members': [2],
'no-unused-vars': [0], // handled by @typescript-eslint/no-unused-vars
'no-use-before-define': [2, {functions: false, classes: true, variables: true, allowNamedExports: true}],
'no-use-extend-native/no-use-extend-native': [2],
'no-useless-backreference': [2],
'no-useless-call': [2],
'no-useless-catch': [2],
'no-useless-computed-key': [2],
'no-useless-concat': [2],
'no-useless-constructor': [2],
'no-useless-escape': [2],
'no-useless-rename': [2],
'no-useless-return': [2],
'no-var': [2],
'no-void': [2],
'no-warning-comments': [0],
'no-with': [0], // handled by no-restricted-syntax
'object-shorthand': [2, 'always'],
'one-var-declaration-per-line': [0],
'one-var': [0],
'operator-assignment': [2, 'always'],
'operator-linebreak': [2, 'after'],
'prefer-arrow-callback': [2, {allowNamedFunctions: true, allowUnboundThis: true}],
'prefer-const': [2, {destructuring: 'all', ignoreReadBeforeAssign: true}],
'prefer-destructuring': [0],
'prefer-exponentiation-operator': [2],
'prefer-named-capture-group': [0],
'prefer-numeric-literals': [2],
'prefer-object-has-own': [2],
'prefer-object-spread': [2],
'prefer-promise-reject-errors': [2, {allowEmptyReject: false}],
'prefer-regex-literals': [2],
'prefer-rest-params': [2],
'prefer-spread': [2],
'prefer-template': [2],
'radix': [2, 'as-needed'],
'regexp/confusing-quantifier': [2],
'regexp/control-character-escape': [2],
'regexp/hexadecimal-escape': [0],
'regexp/letter-case': [0],
'regexp/match-any': [2],
'regexp/negation': [2],
'regexp/no-contradiction-with-assertion': [0],
'regexp/no-control-character': [0],
'regexp/no-dupe-characters-character-class': [2],
'regexp/no-dupe-disjunctions': [2],
'regexp/no-empty-alternative': [2],
'regexp/no-empty-capturing-group': [2],
'regexp/no-empty-character-class': [0],
'regexp/no-empty-group': [2],
'regexp/no-empty-lookarounds-assertion': [2],
'regexp/no-empty-string-literal': [2],
'regexp/no-escape-backspace': [2],
'regexp/no-extra-lookaround-assertions': [0],
'regexp/no-invalid-regexp': [2],
'regexp/no-invisible-character': [2],
'regexp/no-lazy-ends': [2],
'regexp/no-legacy-features': [2],
'regexp/no-misleading-capturing-group': [0],
'regexp/no-misleading-unicode-character': [0],
'regexp/no-missing-g-flag': [2],
'regexp/no-non-standard-flag': [2],
'regexp/no-obscure-range': [2],
'regexp/no-octal': [2],
'regexp/no-optional-assertion': [2],
'regexp/no-potentially-useless-backreference': [2],
'regexp/no-standalone-backslash': [2],
'regexp/no-super-linear-backtracking': [0],
'regexp/no-super-linear-move': [0],
'regexp/no-trivially-nested-assertion': [2],
'regexp/no-trivially-nested-quantifier': [2],
'regexp/no-unused-capturing-group': [0],
'regexp/no-useless-assertions': [2],
'regexp/no-useless-backreference': [2],
'regexp/no-useless-character-class': [2],
'regexp/no-useless-dollar-replacements': [2],
'regexp/no-useless-escape': [2],
'regexp/no-useless-flag': [2],
'regexp/no-useless-lazy': [2],
'regexp/no-useless-non-capturing-group': [2],
'regexp/no-useless-quantifier': [2],
'regexp/no-useless-range': [2],
'regexp/no-useless-set-operand': [2],
'regexp/no-useless-string-literal': [2],
'regexp/no-useless-two-nums-quantifier': [2],
'regexp/no-zero-quantifier': [2],
'regexp/optimal-lookaround-quantifier': [2],
'regexp/optimal-quantifier-concatenation': [0],
'regexp/prefer-character-class': [0],
'regexp/prefer-d': [0],
'regexp/prefer-escape-replacement-dollar-char': [0],
'regexp/prefer-lookaround': [0],
'regexp/prefer-named-backreference': [0],
'regexp/prefer-named-capture-group': [0],
'regexp/prefer-named-replacement': [0],
'regexp/prefer-plus-quantifier': [2],
'regexp/prefer-predefined-assertion': [2],
'regexp/prefer-quantifier': [0],
'regexp/prefer-question-quantifier': [2],
'regexp/prefer-range': [2],
'regexp/prefer-regexp-exec': [2],
'regexp/prefer-regexp-test': [2],
'regexp/prefer-result-array-groups': [0],
'regexp/prefer-set-operation': [2],
'regexp/prefer-star-quantifier': [2],
'regexp/prefer-unicode-codepoint-escapes': [2],
'regexp/prefer-w': [0],
'regexp/require-unicode-regexp': [0],
'regexp/simplify-set-operations': [2],
'regexp/sort-alternatives': [0],
'regexp/sort-character-class-elements': [0],
'regexp/sort-flags': [0],
'regexp/strict': [2],
'regexp/unicode-escape': [0],
'regexp/use-ignore-case': [0],
'require-atomic-updates': [0],
'require-await': [0], // handled by @typescript-eslint/require-await
'require-unicode-regexp': [0],
'require-yield': [2],
'sonarjs/cognitive-complexity': [0],
'sonarjs/elseif-without-else': [0],
'sonarjs/max-switch-cases': [0],
'sonarjs/no-all-duplicated-branches': [2],
'sonarjs/no-collapsible-if': [0],
'sonarjs/no-collection-size-mischeck': [2],
'sonarjs/no-duplicate-string': [0],
'sonarjs/no-duplicated-branches': [0],
'sonarjs/no-element-overwrite': [2],
'sonarjs/no-empty-collection': [2],
'sonarjs/no-extra-arguments': [2],
'sonarjs/no-gratuitous-expressions': [2],
'sonarjs/no-identical-conditions': [2],
'sonarjs/no-identical-expressions': [2],
'sonarjs/no-identical-functions': [2, 5],
'sonarjs/no-ignored-return': [2],
'sonarjs/no-inverted-boolean-check': [2],
'sonarjs/no-nested-switch': [0],
'sonarjs/no-nested-template-literals': [0],
'sonarjs/no-one-iteration-loop': [2],
'sonarjs/no-redundant-boolean': [2],
'sonarjs/no-redundant-jump': [2],
'sonarjs/no-same-line-conditional': [2],
'sonarjs/no-small-switch': [0],
'sonarjs/no-unused-collection': [2],
'sonarjs/no-use-of-empty-return-value': [2],
'sonarjs/no-useless-catch': [2],
'sonarjs/non-existent-operator': [2],
'sonarjs/prefer-immediate-return': [0],
'sonarjs/prefer-object-literal': [0],
'sonarjs/prefer-single-boolean-return': [0],
'sonarjs/prefer-while': [2],
'sort-imports': [0],
'sort-keys': [0],
'sort-vars': [0],
'strict': [0],
'symbol-description': [2],
'unicode-bom': [2, 'never'],
'unicorn/better-regex': [0],
'unicorn/catch-error-name': [0],
'unicorn/consistent-destructuring': [2],
'unicorn/consistent-empty-array-spread': [2],
'unicorn/consistent-existence-index-check': [0],
'unicorn/consistent-function-scoping': [0],
'unicorn/custom-error-definition': [0],
'unicorn/empty-brace-spaces': [2],
'unicorn/error-message': [0],
'unicorn/escape-case': [0],
'unicorn/expiring-todo-comments': [0],
'unicorn/explicit-length-check': [0],
'unicorn/filename-case': [0],
'unicorn/import-index': [0],
'unicorn/import-style': [0],
'unicorn/new-for-builtins': [2],
'unicorn/no-abusive-eslint-disable': [0],
'unicorn/no-anonymous-default-export': [0],
'unicorn/no-array-callback-reference': [0],
'unicorn/no-array-for-each': [2],
'unicorn/no-array-method-this-argument': [2],
'unicorn/no-array-push-push': [2],
'unicorn/no-array-reduce': [2],
'unicorn/no-await-expression-member': [0],
'unicorn/no-await-in-promise-methods': [2],
'unicorn/no-console-spaces': [0],
'unicorn/no-document-cookie': [2],
'unicorn/no-empty-file': [2],
'unicorn/no-for-loop': [0],
'unicorn/no-hex-escape': [0],
'unicorn/no-instanceof-array': [0],
'unicorn/no-invalid-fetch-options': [2],
'unicorn/no-invalid-remove-event-listener': [2],
'unicorn/no-keyword-prefix': [0],
'unicorn/no-length-as-slice-end': [2],
'unicorn/no-lonely-if': [2],
'unicorn/no-magic-array-flat-depth': [0],
'unicorn/no-negated-condition': [0],
'unicorn/no-negation-in-equality-check': [2],
'unicorn/no-nested-ternary': [0],
'unicorn/no-new-array': [0],
'unicorn/no-new-buffer': [0],
'unicorn/no-null': [0],
'unicorn/no-object-as-default-parameter': [0],
'unicorn/no-process-exit': [0],
'unicorn/no-single-promise-in-promise-methods': [2],
'unicorn/no-static-only-class': [2],
'unicorn/no-thenable': [2],
'unicorn/no-this-assignment': [2],
'unicorn/no-typeof-undefined': [2],
'unicorn/no-unnecessary-await': [2],
'unicorn/no-unnecessary-polyfills': [2],
'unicorn/no-unreadable-array-destructuring': [0],
'unicorn/no-unreadable-iife': [2],
'unicorn/no-unused-properties': [2],
'unicorn/no-useless-fallback-in-spread': [2],
'unicorn/no-useless-length-check': [2],
'unicorn/no-useless-promise-resolve-reject': [2],
'unicorn/no-useless-spread': [2],
'unicorn/no-useless-switch-case': [2],
'unicorn/no-useless-undefined': [0],
'unicorn/no-zero-fractions': [2],
'unicorn/number-literal-case': [0],
'unicorn/numeric-separators-style': [0],
'unicorn/prefer-add-event-listener': [2],
'unicorn/prefer-array-find': [2],
'unicorn/prefer-array-flat-map': [2],
'unicorn/prefer-array-flat': [2],
'unicorn/prefer-array-index-of': [2],
'unicorn/prefer-array-some': [2],
'unicorn/prefer-at': [0],
'unicorn/prefer-blob-reading-methods': [2],
'unicorn/prefer-code-point': [0],
'unicorn/prefer-date-now': [2],
'unicorn/prefer-default-parameters': [0],
'unicorn/prefer-dom-node-append': [2],
'unicorn/prefer-dom-node-dataset': [0],
'unicorn/prefer-dom-node-remove': [2],
'unicorn/prefer-dom-node-text-content': [2],
'unicorn/prefer-event-target': [2],
'unicorn/prefer-export-from': [0],
'unicorn/prefer-global-this': [0],
'unicorn/prefer-includes': [2],
'unicorn/prefer-json-parse-buffer': [0],
'unicorn/prefer-keyboard-event-key': [2],
'unicorn/prefer-logical-operator-over-ternary': [2],
'unicorn/prefer-math-min-max': [2],
'unicorn/prefer-math-trunc': [2],
'unicorn/prefer-modern-dom-apis': [0],
'unicorn/prefer-modern-math-apis': [2],
'unicorn/prefer-module': [2],
'unicorn/prefer-native-coercion-functions': [2],
'unicorn/prefer-negative-index': [2],
'unicorn/prefer-node-protocol': [2],
'unicorn/prefer-number-properties': [0],
'unicorn/prefer-object-from-entries': [2],
'unicorn/prefer-object-has-own': [0],
'unicorn/prefer-optional-catch-binding': [2],
'unicorn/prefer-prototype-methods': [0],
'unicorn/prefer-query-selector': [2],
'unicorn/prefer-reflect-apply': [0],
'unicorn/prefer-regexp-test': [2],
'unicorn/prefer-set-has': [0],
'unicorn/prefer-set-size': [2],
'unicorn/prefer-spread': [0],
'unicorn/prefer-string-raw': [0],
'unicorn/prefer-string-replace-all': [0],
'unicorn/prefer-string-slice': [0],
'unicorn/prefer-string-starts-ends-with': [2],
'unicorn/prefer-string-trim-start-end': [2],
'unicorn/prefer-structured-clone': [2],
'unicorn/prefer-switch': [0],
'unicorn/prefer-ternary': [0],
'unicorn/prefer-text-content': [2],
'unicorn/prefer-top-level-await': [0],
'unicorn/prefer-type-error': [0],
'unicorn/prevent-abbreviations': [0],
'unicorn/relative-url-style': [2],
'unicorn/require-array-join-separator': [2],
'unicorn/require-number-to-fixed-digits-argument': [2],
'unicorn/require-post-message-target-origin': [0],
'unicorn/string-content': [0],
'unicorn/switch-case-braces': [0],
'unicorn/template-indent': [2],
'unicorn/text-encoding-identifier-case': [0],
'unicorn/throw-new-error': [2],
'use-isnan': [2],
'valid-typeof': [2, {requireStringLiterals: true}],
'vars-on-top': [0],
'wc/attach-shadow-constructor': [2],
'wc/define-tag-after-class-definition': [0],
'wc/expose-class-on-global': [0],
'wc/file-name-matches-element': [2],
'wc/guard-define-call': [0],
'wc/guard-super-call': [2],
'wc/max-elements-per-file': [0],
'wc/no-child-traversal-in-attributechangedcallback': [2],
'wc/no-child-traversal-in-connectedcallback': [2],
'wc/no-closed-shadow-root': [2],
'wc/no-constructor-attributes': [2],
'wc/no-constructor-params': [2],
'wc/no-constructor': [2],
'wc/no-customized-built-in-elements': [2],
'wc/no-exports-with-element': [0],
'wc/no-invalid-element-name': [2],
'wc/no-invalid-extends': [2],
'wc/no-method-prefixed-with-on': [2],
'wc/no-self-class': [2],
'wc/no-typos': [2],
'wc/require-listener-teardown': [2],
'wc/tag-name-matches-class': [2],
'yoda': [2, 'never'],
},
};

View File

@ -1,841 +0,0 @@
root: true
reportUnusedDisableDirectives: true
ignorePatterns:
- /web_src/js/vendor
parserOptions:
sourceType: module
ecmaVersion: latest
plugins:
- "@eslint-community/eslint-plugin-eslint-comments"
- "@stylistic/eslint-plugin-js"
- eslint-plugin-array-func
- eslint-plugin-github
- eslint-plugin-i
- eslint-plugin-jquery
- eslint-plugin-no-jquery
- eslint-plugin-no-use-extend-native
- eslint-plugin-regexp
- eslint-plugin-sonarjs
- eslint-plugin-unicorn
- eslint-plugin-vitest
- eslint-plugin-vitest-globals
- eslint-plugin-wc
env:
es2024: true
node: true
overrides:
- files: ["web_src/**/*"]
globals:
__webpack_public_path__: true
process: false # https://github.com/webpack/webpack/issues/15833
- files: ["web_src/**/*", "docs/**/*"]
env:
browser: true
node: false
- files: ["web_src/**/*worker.*"]
env:
worker: true
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]
- files: ["*.config.*"]
rules:
i/no-unused-modules: [0]
- files: ["**/*.test.*", "web_src/js/test/setup.js"]
env:
vitest-globals/env: true
rules:
vitest/consistent-test-filename: [0]
vitest/consistent-test-it: [0]
vitest/expect-expect: [0]
vitest/max-expects: [0]
vitest/max-nested-describe: [0]
vitest/no-alias-methods: [0]
vitest/no-commented-out-tests: [0]
vitest/no-conditional-expect: [0]
vitest/no-conditional-in-test: [0]
vitest/no-conditional-tests: [0]
vitest/no-disabled-tests: [0]
vitest/no-done-callback: [0]
vitest/no-duplicate-hooks: [0]
vitest/no-focused-tests: [0]
vitest/no-hooks: [0]
vitest/no-identical-title: [2]
vitest/no-interpolation-in-snapshots: [0]
vitest/no-large-snapshots: [0]
vitest/no-mocks-import: [0]
vitest/no-restricted-matchers: [0]
vitest/no-restricted-vi-methods: [0]
vitest/no-standalone-expect: [0]
vitest/no-test-prefixes: [0]
vitest/no-test-return-statement: [0]
vitest/prefer-called-with: [0]
vitest/prefer-comparison-matcher: [0]
vitest/prefer-each: [0]
vitest/prefer-equality-matcher: [0]
vitest/prefer-expect-resolves: [0]
vitest/prefer-hooks-in-order: [0]
vitest/prefer-hooks-on-top: [2]
vitest/prefer-lowercase-title: [0]
vitest/prefer-mock-promise-shorthand: [0]
vitest/prefer-snapshot-hint: [0]
vitest/prefer-spy-on: [0]
vitest/prefer-strict-equal: [0]
vitest/prefer-to-be: [0]
vitest/prefer-to-be-falsy: [0]
vitest/prefer-to-be-object: [0]
vitest/prefer-to-be-truthy: [0]
vitest/prefer-to-contain: [0]
vitest/prefer-to-have-length: [0]
vitest/prefer-todo: [0]
vitest/require-hook: [0]
vitest/require-to-throw-message: [0]
vitest/require-top-level-describe: [0]
vitest/valid-describe-callback: [2]
vitest/valid-expect: [2]
vitest/valid-title: [2]
- files: ["web_src/js/modules/fetch.js", "web_src/js/standalone/**/*"]
rules:
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
rules:
"@eslint-community/eslint-comments/disable-enable-pair": [2]
"@eslint-community/eslint-comments/no-aggregating-enable": [2]
"@eslint-community/eslint-comments/no-duplicate-disable": [2]
"@eslint-community/eslint-comments/no-restricted-disable": [0]
"@eslint-community/eslint-comments/no-unlimited-disable": [2]
"@eslint-community/eslint-comments/no-unused-disable": [2]
"@eslint-community/eslint-comments/no-unused-enable": [2]
"@eslint-community/eslint-comments/no-use": [0]
"@eslint-community/eslint-comments/require-description": [0]
"@stylistic/js/array-bracket-newline": [0]
"@stylistic/js/array-bracket-spacing": [2, never]
"@stylistic/js/array-element-newline": [0]
"@stylistic/js/arrow-parens": [2, always]
"@stylistic/js/arrow-spacing": [2, {before: true, after: true}]
"@stylistic/js/block-spacing": [0]
"@stylistic/js/brace-style": [2, 1tbs, {allowSingleLine: true}]
"@stylistic/js/comma-dangle": [2, always-multiline]
"@stylistic/js/comma-spacing": [2, {before: false, after: true}]
"@stylistic/js/comma-style": [2, last]
"@stylistic/js/computed-property-spacing": [2, never]
"@stylistic/js/dot-location": [2, property]
"@stylistic/js/eol-last": [2]
"@stylistic/js/function-call-spacing": [2, never]
"@stylistic/js/function-call-argument-newline": [0]
"@stylistic/js/function-paren-newline": [0]
"@stylistic/js/generator-star-spacing": [0]
"@stylistic/js/implicit-arrow-linebreak": [0]
"@stylistic/js/indent": [2, 2, {ignoreComments: true, SwitchCase: 1}]
"@stylistic/js/key-spacing": [2]
"@stylistic/js/keyword-spacing": [2]
"@stylistic/js/linebreak-style": [2, unix]
"@stylistic/js/lines-around-comment": [0]
"@stylistic/js/lines-between-class-members": [0]
"@stylistic/js/max-len": [0]
"@stylistic/js/max-statements-per-line": [0]
"@stylistic/js/multiline-ternary": [0]
"@stylistic/js/new-parens": [2]
"@stylistic/js/newline-per-chained-call": [0]
"@stylistic/js/no-confusing-arrow": [0]
"@stylistic/js/no-extra-parens": [0]
"@stylistic/js/no-extra-semi": [2]
"@stylistic/js/no-floating-decimal": [0]
"@stylistic/js/no-mixed-operators": [0]
"@stylistic/js/no-mixed-spaces-and-tabs": [2]
"@stylistic/js/no-multi-spaces": [2, {ignoreEOLComments: true, exceptions: {Property: true}}]
"@stylistic/js/no-multiple-empty-lines": [2, {max: 1, maxEOF: 0, maxBOF: 0}]
"@stylistic/js/no-tabs": [2]
"@stylistic/js/no-trailing-spaces": [2]
"@stylistic/js/no-whitespace-before-property": [2]
"@stylistic/js/nonblock-statement-body-position": [2]
"@stylistic/js/object-curly-newline": [0]
"@stylistic/js/object-curly-spacing": [2, never]
"@stylistic/js/object-property-newline": [0]
"@stylistic/js/one-var-declaration-per-line": [0]
"@stylistic/js/operator-linebreak": [2, after]
"@stylistic/js/padded-blocks": [2, never]
"@stylistic/js/padding-line-between-statements": [0]
"@stylistic/js/quote-props": [0]
"@stylistic/js/quotes": [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
"@stylistic/js/rest-spread-spacing": [2, never]
"@stylistic/js/semi": [2, always, {omitLastInOneLineBlock: true}]
"@stylistic/js/semi-spacing": [2, {before: false, after: true}]
"@stylistic/js/semi-style": [2, last]
"@stylistic/js/space-before-blocks": [2, always]
"@stylistic/js/space-before-function-paren": [0]
"@stylistic/js/space-in-parens": [2, never]
"@stylistic/js/space-infix-ops": [2]
"@stylistic/js/space-unary-ops": [2]
"@stylistic/js/spaced-comment": [2, always]
"@stylistic/js/switch-colon-spacing": [2]
"@stylistic/js/template-curly-spacing": [2, never]
"@stylistic/js/template-tag-spacing": [2, never]
"@stylistic/js/wrap-iife": [2, inside]
"@stylistic/js/wrap-regex": [0]
"@stylistic/js/yield-star-spacing": [2, after]
accessor-pairs: [2]
array-callback-return: [2, {checkForEach: true}]
array-func/avoid-reverse: [2]
array-func/from-map: [2]
array-func/no-unnecessary-this-arg: [2]
array-func/prefer-array-from: [2]
array-func/prefer-flat-map: [0] # handled by unicorn/prefer-array-flat-map
array-func/prefer-flat: [0] # handled by unicorn/prefer-array-flat
arrow-body-style: [0]
block-scoped-var: [2]
camelcase: [0]
capitalized-comments: [0]
class-methods-use-this: [0]
complexity: [0]
consistent-return: [0]
consistent-this: [0]
constructor-super: [2]
curly: [0]
default-case-last: [2]
default-case: [0]
default-param-last: [0]
dot-notation: [0]
eqeqeq: [2]
for-direction: [2]
func-name-matching: [2]
func-names: [0]
func-style: [0]
getter-return: [2]
github/a11y-aria-label-is-well-formatted: [0]
github/a11y-no-title-attribute: [0]
github/a11y-no-visually-hidden-interactive-element: [0]
github/a11y-role-supports-aria-props: [0]
github/a11y-svg-has-accessible-name: [0]
github/array-foreach: [0]
github/async-currenttarget: [2]
github/async-preventdefault: [2]
github/authenticity-token: [0]
github/get-attribute: [0]
github/js-class-name: [0]
github/no-blur: [0]
github/no-d-none: [0]
github/no-dataset: [2]
github/no-dynamic-script-tag: [2]
github/no-implicit-buggy-globals: [2]
github/no-inner-html: [0]
github/no-innerText: [2]
github/no-then: [2]
github/no-useless-passive: [2]
github/prefer-observers: [2]
github/require-passive-events: [2]
github/unescaped-html-literal: [0]
grouped-accessor-pairs: [2]
guard-for-in: [0]
id-blacklist: [0]
id-length: [0]
id-match: [0]
i/consistent-type-specifier-style: [0]
i/default: [0]
i/dynamic-import-chunkname: [0]
i/export: [2]
i/exports-last: [0]
i/extensions: [2, always, {ignorePackages: true}]
i/first: [2]
i/group-exports: [0]
i/max-dependencies: [0]
i/named: [2]
i/namespace: [0]
i/newline-after-import: [0]
i/no-absolute-path: [0]
i/no-amd: [2]
i/no-anonymous-default-export: [0]
i/no-commonjs: [2]
i/no-cycle: [2, {ignoreExternal: true, maxDepth: 1}]
i/no-default-export: [0]
i/no-deprecated: [0]
i/no-dynamic-require: [0]
i/no-empty-named-blocks: [2]
i/no-extraneous-dependencies: [2]
i/no-import-module-exports: [0]
i/no-internal-modules: [0]
i/no-mutable-exports: [0]
i/no-named-as-default-member: [0]
i/no-named-as-default: [2]
i/no-named-default: [0]
i/no-named-export: [0]
i/no-namespace: [0]
i/no-nodejs-modules: [0]
i/no-relative-packages: [0]
i/no-relative-parent-imports: [0]
i/no-restricted-paths: [0]
i/no-self-import: [2]
i/no-unassigned-import: [0]
i/no-unresolved: [2, {commonjs: true, ignore: ["\\?.+$", ^vitest/]}]
i/no-unused-modules: [2, {unusedExports: true}]
i/no-useless-path-segments: [2, {commonjs: true}]
i/no-webpack-loader-syntax: [2]
i/order: [0]
i/prefer-default-export: [0]
i/unambiguous: [0]
init-declarations: [0]
jquery/no-ajax-events: [2]
jquery/no-ajax: [2]
jquery/no-animate: [2]
jquery/no-attr: [0]
jquery/no-bind: [2]
jquery/no-class: [0]
jquery/no-clone: [2]
jquery/no-closest: [0]
jquery/no-css: [2]
jquery/no-data: [0]
jquery/no-deferred: [2]
jquery/no-delegate: [2]
jquery/no-each: [0]
jquery/no-extend: [2]
jquery/no-fade: [2]
jquery/no-filter: [0]
jquery/no-find: [0]
jquery/no-global-eval: [2]
jquery/no-grep: [2]
jquery/no-has: [2]
jquery/no-hide: [2]
jquery/no-html: [0]
jquery/no-in-array: [2]
jquery/no-is-array: [2]
jquery/no-is-function: [2]
jquery/no-is: [2]
jquery/no-load: [2]
jquery/no-map: [2]
jquery/no-merge: [2]
jquery/no-param: [2]
jquery/no-parent: [0]
jquery/no-parents: [0]
jquery/no-parse-html: [2]
jquery/no-prop: [2]
jquery/no-proxy: [2]
jquery/no-ready: [2]
jquery/no-serialize: [2]
jquery/no-show: [2]
jquery/no-size: [2]
jquery/no-sizzle: [0]
jquery/no-slide: [0]
jquery/no-submit: [0]
jquery/no-text: [0]
jquery/no-toggle: [2]
jquery/no-trigger: [0]
jquery/no-trim: [2]
jquery/no-val: [0]
jquery/no-when: [2]
jquery/no-wrap: [2]
line-comment-position: [0]
logical-assignment-operators: [0]
max-classes-per-file: [0]
max-depth: [0]
max-lines-per-function: [0]
max-lines: [0]
max-nested-callbacks: [0]
max-params: [0]
max-statements: [0]
multiline-comment-style: [2, separate-lines]
new-cap: [0]
no-alert: [0]
no-array-constructor: [2]
no-async-promise-executor: [0]
no-await-in-loop: [0]
no-bitwise: [0]
no-buffer-constructor: [0]
no-caller: [2]
no-case-declarations: [2]
no-class-assign: [2]
no-compare-neg-zero: [2]
no-cond-assign: [2, except-parens]
no-console: [1, {allow: [debug, info, warn, error]}]
no-const-assign: [2]
no-constant-binary-expression: [2]
no-constant-condition: [0]
no-constructor-return: [2]
no-continue: [0]
no-control-regex: [0]
no-debugger: [1]
no-delete-var: [2]
no-div-regex: [0]
no-dupe-args: [2]
no-dupe-class-members: [2]
no-dupe-else-if: [2]
no-dupe-keys: [2]
no-duplicate-case: [2]
no-duplicate-imports: [2]
no-else-return: [2]
no-empty-character-class: [2]
no-empty-function: [0]
no-empty-pattern: [2]
no-empty-static-block: [2]
no-empty: [2, {allowEmptyCatch: true}]
no-eq-null: [2]
no-eval: [2]
no-ex-assign: [2]
no-extend-native: [2]
no-extra-bind: [2]
no-extra-boolean-cast: [2]
no-extra-label: [0]
no-fallthrough: [2]
no-func-assign: [2]
no-global-assign: [2]
no-implicit-coercion: [2]
no-implicit-globals: [0]
no-implied-eval: [2]
no-import-assign: [2]
no-inline-comments: [0]
no-inner-declarations: [2]
no-invalid-regexp: [2]
no-invalid-this: [0]
no-irregular-whitespace: [2]
no-iterator: [2]
no-jquery/no-ajax-events: [2]
no-jquery/no-ajax: [2]
no-jquery/no-and-self: [2]
no-jquery/no-animate-toggle: [2]
no-jquery/no-animate: [2]
no-jquery/no-append-html: [2]
no-jquery/no-attr: [0]
no-jquery/no-bind: [2]
no-jquery/no-box-model: [2]
no-jquery/no-browser: [2]
no-jquery/no-camel-case: [2]
no-jquery/no-class-state: [0]
no-jquery/no-class: [0]
no-jquery/no-clone: [2]
no-jquery/no-closest: [0]
no-jquery/no-constructor-attributes: [2]
no-jquery/no-contains: [2]
no-jquery/no-context-prop: [2]
no-jquery/no-css: [2]
no-jquery/no-data: [0]
no-jquery/no-deferred: [2]
no-jquery/no-delegate: [2]
no-jquery/no-each-collection: [0]
no-jquery/no-each-util: [0]
no-jquery/no-each: [0]
no-jquery/no-error-shorthand: [2]
no-jquery/no-error: [2]
no-jquery/no-escape-selector: [2]
no-jquery/no-event-shorthand: [2]
no-jquery/no-extend: [2]
no-jquery/no-fade: [2]
no-jquery/no-filter: [0]
no-jquery/no-find-collection: [0]
no-jquery/no-find-util: [2]
no-jquery/no-find: [0]
no-jquery/no-fx-interval: [2]
no-jquery/no-global-eval: [2]
no-jquery/no-global-selector: [0]
no-jquery/no-grep: [2]
no-jquery/no-has: [2]
no-jquery/no-hold-ready: [2]
no-jquery/no-html: [0]
no-jquery/no-in-array: [2]
no-jquery/no-is-array: [2]
no-jquery/no-is-empty-object: [2]
no-jquery/no-is-function: [2]
no-jquery/no-is-numeric: [2]
no-jquery/no-is-plain-object: [2]
no-jquery/no-is-window: [2]
no-jquery/no-is: [2]
no-jquery/no-jquery-constructor: [0]
no-jquery/no-live: [2]
no-jquery/no-load-shorthand: [2]
no-jquery/no-load: [2]
no-jquery/no-map-collection: [0]
no-jquery/no-map-util: [2]
no-jquery/no-map: [2]
no-jquery/no-merge: [2]
no-jquery/no-node-name: [2]
no-jquery/no-noop: [2]
no-jquery/no-now: [2]
no-jquery/no-on-ready: [2]
no-jquery/no-other-methods: [0]
no-jquery/no-other-utils: [2]
no-jquery/no-param: [2]
no-jquery/no-parent: [0]
no-jquery/no-parents: [0]
no-jquery/no-parse-html-literal: [0]
no-jquery/no-parse-html: [2]
no-jquery/no-parse-json: [2]
no-jquery/no-parse-xml: [2]
no-jquery/no-prop: [2]
no-jquery/no-proxy: [2]
no-jquery/no-ready-shorthand: [2]
no-jquery/no-ready: [2]
no-jquery/no-selector-prop: [2]
no-jquery/no-serialize: [2]
no-jquery/no-size: [2]
no-jquery/no-sizzle: [0]
no-jquery/no-slide: [2]
no-jquery/no-sub: [2]
no-jquery/no-support: [2]
no-jquery/no-text: [0]
no-jquery/no-trigger: [0]
no-jquery/no-trim: [2]
no-jquery/no-type: [2]
no-jquery/no-unique: [2]
no-jquery/no-unload-shorthand: [2]
no-jquery/no-val: [0]
no-jquery/no-visibility: [2]
no-jquery/no-when: [2]
no-jquery/no-wrap: [2]
no-jquery/variable-pattern: [2]
no-label-var: [2]
no-labels: [0] # handled by no-restricted-syntax
no-lone-blocks: [2]
no-lonely-if: [0]
no-loop-func: [0]
no-loss-of-precision: [2]
no-magic-numbers: [0]
no-misleading-character-class: [2]
no-multi-assign: [0]
no-multi-str: [2]
no-negated-condition: [0]
no-nested-ternary: [0]
no-new-func: [2]
no-new-native-nonconstructor: [2]
no-new-object: [2]
no-new-symbol: [2]
no-new-wrappers: [2]
no-new: [0]
no-nonoctal-decimal-escape: [2]
no-obj-calls: [2]
no-octal-escape: [2]
no-octal: [2]
no-param-reassign: [0]
no-plusplus: [0]
no-promise-executor-return: [0]
no-proto: [2]
no-prototype-builtins: [2]
no-redeclare: [2]
no-regex-spaces: [2]
no-restricted-exports: [0]
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, 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, self, status, statusbar, stop, toolbar, top, __dirname, __filename]
no-restricted-imports: [0]
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression, {selector: "CallExpression[callee.name='fetch']", message: "use modules/fetch.js instead"}]
no-return-assign: [0]
no-script-url: [2]
no-self-assign: [2, {props: true}]
no-self-compare: [2]
no-sequences: [2]
no-setter-return: [2]
no-shadow-restricted-names: [2]
no-shadow: [0]
no-sparse-arrays: [2]
no-template-curly-in-string: [2]
no-ternary: [0]
no-this-before-super: [2]
no-throw-literal: [2]
no-undef-init: [2]
no-undef: [2, {typeof: true}]
no-undefined: [0]
no-underscore-dangle: [0]
no-unexpected-multiline: [2]
no-unmodified-loop-condition: [2]
no-unneeded-ternary: [0]
no-unreachable-loop: [2]
no-unreachable: [2]
no-unsafe-finally: [2]
no-unsafe-negation: [2]
no-unused-expressions: [2]
no-unused-labels: [2]
no-unused-private-class-members: [2]
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}]
no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}]
no-use-extend-native/no-use-extend-native: [2]
no-useless-backreference: [2]
no-useless-call: [2]
no-useless-catch: [2]
no-useless-computed-key: [2]
no-useless-concat: [2]
no-useless-constructor: [2]
no-useless-escape: [2]
no-useless-rename: [2]
no-useless-return: [2]
no-var: [2]
no-void: [2]
no-warning-comments: [0]
no-with: [0] # handled by no-restricted-syntax
object-shorthand: [2, always]
one-var-declaration-per-line: [0]
one-var: [0]
operator-assignment: [2, always]
operator-linebreak: [2, after]
prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}]
prefer-const: [2, {destructuring: all, ignoreReadBeforeAssign: true}]
prefer-destructuring: [0]
prefer-exponentiation-operator: [2]
prefer-named-capture-group: [0]
prefer-numeric-literals: [2]
prefer-object-has-own: [2]
prefer-object-spread: [2]
prefer-promise-reject-errors: [2, {allowEmptyReject: false}]
prefer-regex-literals: [2]
prefer-rest-params: [2]
prefer-spread: [2]
prefer-template: [2]
radix: [2, as-needed]
regexp/confusing-quantifier: [2]
regexp/control-character-escape: [2]
regexp/hexadecimal-escape: [0]
regexp/letter-case: [0]
regexp/match-any: [2]
regexp/negation: [2]
regexp/no-contradiction-with-assertion: [0]
regexp/no-control-character: [0]
regexp/no-dupe-characters-character-class: [2]
regexp/no-dupe-disjunctions: [2]
regexp/no-empty-alternative: [2]
regexp/no-empty-capturing-group: [2]
regexp/no-empty-character-class: [0]
regexp/no-empty-group: [2]
regexp/no-empty-lookarounds-assertion: [2]
regexp/no-empty-string-literal: [2]
regexp/no-escape-backspace: [2]
regexp/no-extra-lookaround-assertions: [0]
regexp/no-invalid-regexp: [2]
regexp/no-invisible-character: [2]
regexp/no-lazy-ends: [2]
regexp/no-legacy-features: [2]
regexp/no-misleading-capturing-group: [0]
regexp/no-misleading-unicode-character: [0]
regexp/no-missing-g-flag: [2]
regexp/no-non-standard-flag: [2]
regexp/no-obscure-range: [2]
regexp/no-octal: [2]
regexp/no-optional-assertion: [2]
regexp/no-potentially-useless-backreference: [2]
regexp/no-standalone-backslash: [2]
regexp/no-super-linear-backtracking: [0]
regexp/no-super-linear-move: [0]
regexp/no-trivially-nested-assertion: [2]
regexp/no-trivially-nested-quantifier: [2]
regexp/no-unused-capturing-group: [0]
regexp/no-useless-assertions: [2]
regexp/no-useless-backreference: [2]
regexp/no-useless-character-class: [2]
regexp/no-useless-dollar-replacements: [2]
regexp/no-useless-escape: [2]
regexp/no-useless-flag: [2]
regexp/no-useless-lazy: [2]
regexp/no-useless-non-capturing-group: [2]
regexp/no-useless-quantifier: [2]
regexp/no-useless-range: [2]
regexp/no-useless-set-operand: [2]
regexp/no-useless-string-literal: [2]
regexp/no-useless-two-nums-quantifier: [2]
regexp/no-zero-quantifier: [2]
regexp/optimal-lookaround-quantifier: [2]
regexp/optimal-quantifier-concatenation: [0]
regexp/prefer-character-class: [0]
regexp/prefer-d: [0]
regexp/prefer-escape-replacement-dollar-char: [0]
regexp/prefer-lookaround: [0]
regexp/prefer-named-backreference: [0]
regexp/prefer-named-capture-group: [0]
regexp/prefer-named-replacement: [0]
regexp/prefer-plus-quantifier: [2]
regexp/prefer-predefined-assertion: [2]
regexp/prefer-quantifier: [0]
regexp/prefer-question-quantifier: [2]
regexp/prefer-range: [2]
regexp/prefer-regexp-exec: [2]
regexp/prefer-regexp-test: [2]
regexp/prefer-result-array-groups: [0]
regexp/prefer-set-operation: [2]
regexp/prefer-star-quantifier: [2]
regexp/prefer-unicode-codepoint-escapes: [2]
regexp/prefer-w: [0]
regexp/require-unicode-regexp: [0]
regexp/simplify-set-operations: [2]
regexp/sort-alternatives: [0]
regexp/sort-character-class-elements: [0]
regexp/sort-flags: [0]
regexp/strict: [2]
regexp/unicode-escape: [0]
regexp/use-ignore-case: [0]
require-atomic-updates: [0]
require-await: [0]
require-unicode-regexp: [0]
require-yield: [2]
sonarjs/cognitive-complexity: [0]
sonarjs/elseif-without-else: [0]
sonarjs/max-switch-cases: [0]
sonarjs/no-all-duplicated-branches: [2]
sonarjs/no-collapsible-if: [0]
sonarjs/no-collection-size-mischeck: [2]
sonarjs/no-duplicate-string: [0]
sonarjs/no-duplicated-branches: [0]
sonarjs/no-element-overwrite: [2]
sonarjs/no-empty-collection: [2]
sonarjs/no-extra-arguments: [2]
sonarjs/no-gratuitous-expressions: [2]
sonarjs/no-identical-conditions: [2]
sonarjs/no-identical-expressions: [2]
sonarjs/no-identical-functions: [2, 5]
sonarjs/no-ignored-return: [2]
sonarjs/no-inverted-boolean-check: [2]
sonarjs/no-nested-switch: [0]
sonarjs/no-nested-template-literals: [0]
sonarjs/no-one-iteration-loop: [2]
sonarjs/no-redundant-boolean: [2]
sonarjs/no-redundant-jump: [2]
sonarjs/no-same-line-conditional: [2]
sonarjs/no-small-switch: [0]
sonarjs/no-unused-collection: [2]
sonarjs/no-use-of-empty-return-value: [2]
sonarjs/no-useless-catch: [2]
sonarjs/non-existent-operator: [2]
sonarjs/prefer-immediate-return: [0]
sonarjs/prefer-object-literal: [0]
sonarjs/prefer-single-boolean-return: [0]
sonarjs/prefer-while: [2]
sort-imports: [0]
sort-keys: [0]
sort-vars: [0]
strict: [0]
symbol-description: [2]
unicode-bom: [2, never]
unicorn/better-regex: [0]
unicorn/catch-error-name: [0]
unicorn/consistent-destructuring: [2]
unicorn/consistent-function-scoping: [2]
unicorn/custom-error-definition: [0]
unicorn/empty-brace-spaces: [2]
unicorn/error-message: [0]
unicorn/escape-case: [0]
unicorn/expiring-todo-comments: [0]
unicorn/explicit-length-check: [0]
unicorn/filename-case: [0]
unicorn/import-index: [0]
unicorn/import-style: [0]
unicorn/new-for-builtins: [2]
unicorn/no-abusive-eslint-disable: [0]
unicorn/no-array-callback-reference: [0]
unicorn/no-array-for-each: [2]
unicorn/no-array-method-this-argument: [2]
unicorn/no-array-push-push: [2]
unicorn/no-array-reduce: [2]
unicorn/no-await-expression-member: [0]
unicorn/no-console-spaces: [0]
unicorn/no-document-cookie: [2]
unicorn/no-empty-file: [2]
unicorn/no-for-loop: [0]
unicorn/no-hex-escape: [0]
unicorn/no-instanceof-array: [0]
unicorn/no-invalid-remove-event-listener: [2]
unicorn/no-keyword-prefix: [0]
unicorn/no-lonely-if: [2]
unicorn/no-negated-condition: [0]
unicorn/no-nested-ternary: [0]
unicorn/no-new-array: [0]
unicorn/no-new-buffer: [0]
unicorn/no-null: [0]
unicorn/no-object-as-default-parameter: [0]
unicorn/no-process-exit: [0]
unicorn/no-static-only-class: [2]
unicorn/no-thenable: [2]
unicorn/no-this-assignment: [2]
unicorn/no-typeof-undefined: [2]
unicorn/no-unnecessary-await: [2]
unicorn/no-unnecessary-polyfills: [2]
unicorn/no-unreadable-array-destructuring: [0]
unicorn/no-unreadable-iife: [2]
unicorn/no-unused-properties: [2]
unicorn/no-useless-fallback-in-spread: [2]
unicorn/no-useless-length-check: [2]
unicorn/no-useless-promise-resolve-reject: [2]
unicorn/no-useless-spread: [2]
unicorn/no-useless-switch-case: [2]
unicorn/no-useless-undefined: [0]
unicorn/no-zero-fractions: [2]
unicorn/number-literal-case: [0]
unicorn/numeric-separators-style: [0]
unicorn/prefer-add-event-listener: [2]
unicorn/prefer-array-find: [2]
unicorn/prefer-array-flat-map: [2]
unicorn/prefer-array-flat: [2]
unicorn/prefer-array-index-of: [2]
unicorn/prefer-array-some: [2]
unicorn/prefer-at: [0]
unicorn/prefer-blob-reading-methods: [2]
unicorn/prefer-code-point: [0]
unicorn/prefer-date-now: [2]
unicorn/prefer-default-parameters: [0]
unicorn/prefer-dom-node-append: [2]
unicorn/prefer-dom-node-dataset: [0]
unicorn/prefer-dom-node-remove: [2]
unicorn/prefer-dom-node-text-content: [2]
unicorn/prefer-event-target: [2]
unicorn/prefer-export-from: [0]
unicorn/prefer-includes: [2]
unicorn/prefer-json-parse-buffer: [0]
unicorn/prefer-keyboard-event-key: [2]
unicorn/prefer-logical-operator-over-ternary: [2]
unicorn/prefer-math-trunc: [2]
unicorn/prefer-modern-dom-apis: [0]
unicorn/prefer-modern-math-apis: [2]
unicorn/prefer-module: [2]
unicorn/prefer-native-coercion-functions: [2]
unicorn/prefer-negative-index: [2]
unicorn/prefer-node-protocol: [2]
unicorn/prefer-number-properties: [0]
unicorn/prefer-object-from-entries: [2]
unicorn/prefer-object-has-own: [0]
unicorn/prefer-optional-catch-binding: [2]
unicorn/prefer-prototype-methods: [0]
unicorn/prefer-query-selector: [0]
unicorn/prefer-reflect-apply: [0]
unicorn/prefer-regexp-test: [2]
unicorn/prefer-set-has: [0]
unicorn/prefer-set-size: [2]
unicorn/prefer-spread: [0]
unicorn/prefer-string-replace-all: [0]
unicorn/prefer-string-slice: [0]
unicorn/prefer-string-starts-ends-with: [2]
unicorn/prefer-string-trim-start-end: [2]
unicorn/prefer-switch: [0]
unicorn/prefer-ternary: [0]
unicorn/prefer-text-content: [2]
unicorn/prefer-top-level-await: [0]
unicorn/prefer-type-error: [0]
unicorn/prevent-abbreviations: [0]
unicorn/relative-url-style: [2]
unicorn/require-array-join-separator: [2]
unicorn/require-number-to-fixed-digits-argument: [2]
unicorn/require-post-message-target-origin: [0]
unicorn/string-content: [0]
unicorn/switch-case-braces: [0]
unicorn/template-indent: [2]
unicorn/text-encoding-identifier-case: [0]
unicorn/throw-new-error: [2]
use-isnan: [2]
valid-typeof: [2, {requireStringLiterals: true}]
vars-on-top: [0]
wc/attach-shadow-constructor: [2]
wc/define-tag-after-class-definition: [0]
wc/expose-class-on-global: [0]
wc/file-name-matches-element: [2]
wc/guard-define-call: [0]
wc/guard-super-call: [2]
wc/max-elements-per-file: [0]
wc/no-child-traversal-in-attributechangedcallback: [2]
wc/no-child-traversal-in-connectedcallback: [2]
wc/no-closed-shadow-root: [2]
wc/no-constructor-attributes: [2]
wc/no-constructor-params: [2]
wc/no-constructor: [2]
wc/no-customized-built-in-elements: [2]
wc/no-exports-with-element: [0]
wc/no-invalid-element-name: [2]
wc/no-invalid-extends: [2]
wc/no-method-prefixed-with-on: [2]
wc/no-self-class: [2]
wc/no-typos: [2]
wc/require-listener-teardown: [2]
wc/tag-name-matches-class: [2]
yoda: [2, never]

1
.gitattributes vendored
View File

@ -1,5 +1,6 @@
* text=auto eol=lf
*.tmpl linguist-language=Handlebars
*.pb.go linguist-generated
/assets/*.json linguist-generated
/public/assets/img/svg/*.svg linguist-generated
/templates/swagger/v1_json.tmpl linguist-generated

View File

@ -3,7 +3,7 @@
<!--
1. Please speak English, this is the language all maintainers can speak and write.
2. Please ask questions or configuration/deploy problems on our Discord
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
3. Please take a moment to check that your issue doesn't already exist.
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
5. Please give all relevant information below for bug reports, because
@ -21,7 +21,7 @@
- [ ] MySQL
- [ ] MSSQL
- [ ] SQLite
- Can you reproduce the bug at https://try.gitea.io:
- Can you reproduce the bug at https://demo.gitea.com:
- [ ] Yes (provide example URL)
- [ ] No
- Log gist:

View File

@ -11,7 +11,7 @@ body:
value: |
1. Please speak English, this is the language all maintainers can speak and write.
2. Please ask questions or configuration/deploy problems on our Discord
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
3. Make sure you are using the latest release and
take a moment to check that your issue hasn't been reported before.
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
@ -37,7 +37,7 @@ body:
label: Can you reproduce the bug on the Gitea demo site?
description: |
If so, please provide a URL in the Description field
URL of Gitea demo: https://try.gitea.io
URL of Gitea demo: https://demo.gitea.com
options:
- "Yes"
- "No"
@ -74,7 +74,7 @@ body:
attributes:
label: How are you running Gitea?
description: |
Please include information on whether you built Gitea yourself, used one of our downloads, are using https://try.gitea.io or are using some other package
Please include information on whether you built Gitea yourself, used one of our downloads, are using https://demo.gitea.com or are using some other package
Please also tell us how you are running Gitea, e.g. if it is being run from docker, a command-line, systemd etc.
If you are using a package or systemd tell us what distribution you are using
validations:

View File

@ -7,7 +7,7 @@ contact_links:
url: https://discord.gg/Gitea
about: Please ask questions and discuss configuration or deployment problems here.
- name: Discourse Forum
url: https://discourse.gitea.io
url: https://forum.gitea.com
about: Questions and configuration or deployment problems can also be discussed on our forum.
- name: Frequently Asked Questions
url: https://docs.gitea.com/help/faq

View File

@ -7,7 +7,7 @@ body:
value: |
1. Please speak English, this is the language all maintainers can speak and write.
2. Please ask questions or configuration/deploy problems on our Discord
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
3. Please take a moment to check that your feature hasn't already been suggested.
- type: textarea
id: description

View File

@ -11,7 +11,7 @@ body:
value: |
1. Please speak English, this is the language all maintainers can speak and write.
2. Please ask questions or configuration/deploy problems on our Discord
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
3. Please take a moment to check that your issue doesn't already exist.
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
5. Please give all relevant information below for bug reports, because
@ -46,7 +46,7 @@ body:
label: Can you reproduce the bug on the Gitea demo site?
description: |
If so, please provide a URL in the Description field
URL of Gitea demo: https://try.gitea.io
URL of Gitea demo: https://demo.gitea.com
options:
- "Yes"
- "No"

View File

@ -3,3 +3,5 @@ self-hosted-runner:
- actuated-4cpu-8gb
- actuated-4cpu-16gb
- nscloud
- namespace-profile-gitea-release-docker
- namespace-profile-gitea-release-binary

17
.github/labeler.yml vendored
View File

@ -4,13 +4,6 @@ modifies/docs:
- "**/*.md"
- "docs/**"
modifies/frontend:
- changed-files:
- any-glob-to-any-file:
- "web_src/**"
- "tailwind.config.js"
- "webpack.config.js"
modifies/templates:
- changed-files:
- all-globs-to-any-file:
@ -53,7 +46,7 @@ modifies/internal:
- ".gitpod.yml"
- ".markdownlint.yaml"
- ".spectral.yaml"
- ".stylelintrc.yaml"
- "stylelint.config.js"
- ".yamllint.yaml"
- ".github/**"
- ".gitea/"
@ -77,8 +70,14 @@ modifies/go:
- any-glob-to-any-file:
- "**/*.go"
modifies/js:
modifies/frontend:
- changed-files:
- any-glob-to-any-file:
- "**/*.js"
- "**/*.ts"
- "**/*.vue"
docs-update-needed:
- changed-files:
- any-glob-to-any-file:
- "custom/conf/app.example.ini"

View File

@ -1,9 +1,10 @@
<!-- start tips -->
<!-- start tips -->
Please check the following:
1. Make sure you are targeting the `main` branch, pull requests on release branches are only allowed for backports.
2. Make sure you have read contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md .
3. Describe what your pull request does and which issue you're targeting (if any).
4. It is recommended to enable "Allow edits by maintainers", so maintainers can help more easily.
5. Your input here will be included in the commit message when this PR has been merged. If you don't want some content to be included, please separate them with a line like `---`.
6. Delete all these tips before posting.
3. For documentations contribution, please go to https://gitea.com/gitea/docs
4. Describe what your pull request does and which issue you're targeting (if any).
5. It is recommended to enable "Allow edits by maintainers", so maintainers can help more easily.
6. Your input here will be included in the commit message when this PR has been merged. If you don't want some content to be included, please separate them with a line like `---`.
7. Delete all these tips before posting.
<!-- end tips -->

View File

@ -11,14 +11,19 @@ jobs:
if: github.repository == 'go-gitea/gitea'
steps:
- uses: actions/checkout@v4
- name: download from crowdin
uses: docker://jonasfranz/crowdin
- uses: crowdin/github-action@v1
with:
upload_sources: true
upload_translations: false
download_sources: false
download_translations: true
push_translations: false
push_sources: false
create_pull_request: false
config: crowdin.yml
env:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
PLUGIN_DOWNLOAD: true
PLUGIN_EXPORT_DIR: options/locale/
PLUGIN_IGNORE_BRANCH: true
PLUGIN_PROJECT_IDENTIFIER: gitea
- name: update locales
run: ./build/update-locales.sh
- name: push translations to repo
@ -31,19 +36,3 @@ jobs:
commit_message: "[skip ci] Updated translations via Crowdin"
remote: "git@github.com:go-gitea/gitea.git"
ssh_key: ${{ secrets.DEPLOY_KEY }}
crowdin-push:
runs-on: ubuntu-latest
if: github.repository == 'go-gitea/gitea'
steps:
- uses: actions/checkout@v4
- name: push translations to crowdin
uses: docker://jonasfranz/crowdin
env:
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
PLUGIN_UPLOAD: true
PLUGIN_EXPORT_DIR: options/locale/
PLUGIN_IGNORE_BRANCH: true
PLUGIN_PROJECT_IDENTIFIER: gitea
PLUGIN_FILES: |
locale_en-US.ini: options/locale/locale_en-US.ini
PLUGIN_BRANCH: main

View File

@ -1,25 +0,0 @@
name: disk-clean
on:
workflow_call:
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
with:
# this might remove tools that are actually needed,
# if set to "true" but frees about 6 GB
tool-cache: false
# all of these default to true, but feel free to set to
# "false" if necessary for your workflow
android: true
dotnet: true
haskell: true
large-packages: false
docker-images: false
swap-storage: true

View File

@ -58,12 +58,11 @@ jobs:
- "package-lock.json"
- "Makefile"
- ".eslintrc.yaml"
- ".stylelintrc.yaml"
- "stylelint.config.js"
- ".npmrc"
docs:
- "**/*.md"
- "docs/**"
- ".markdownlint.yaml"
- "package.json"
- "package-lock.json"
@ -73,6 +72,7 @@ jobs:
- "Makefile"
templates:
- "tools/lint-templates-*.js"
- "templates/**/*.tmpl"
- "pyproject.toml"
- "poetry.lock"

View File

@ -35,8 +35,14 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: pip install poetry
- run: make deps-py
- run: make deps-frontend
- run: make lint-templates
lint-yaml:
@ -60,7 +66,9 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend
- run: make lint-swagger
@ -129,7 +137,9 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend
- run: make lint-frontend
- run: make checks-frontend
@ -176,10 +186,11 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend
- run: make lint-md
- run: make docs
actions:
if: needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.actions == 'true'

View File

@ -119,6 +119,10 @@ jobs:
MINIO_SECRET_KEY: 12345678
ports:
- "9000:9000"
devstoreaccount1.azurite.local: # https://github.com/Azure/Azurite/issues/1583
image: mcr.microsoft.com/azure-storage/azurite:latest
ports:
- 10000:10000
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
@ -126,7 +130,7 @@ jobs:
go-version-file: go.mod
check-latest: true
- name: Add hosts to /etc/hosts
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts'
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 minio devstoreaccount1.azurite.local mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts'
- run: make deps-backend
- run: make backend
env:
@ -150,12 +154,15 @@ jobs:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
# the bitnami mysql image has more options than the official one, it's easier to customize
image: bitnami/mysql:8.0
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: testgitea
ports:
- "3306:3306"
options: >-
--mount type=tmpfs,destination=/bitnami/mysql/data
elasticsearch:
image: elasticsearch:7.5.0
env:
@ -184,7 +191,8 @@ jobs:
- name: run migration tests
run: make test-mysql-migration
- name: run tests
run: make integration-test-coverage
# run: make integration-test-coverage (at the moment, no coverage is really handled)
run: make test-mysql
env:
TAGS: bindata
RACE_ENABLED: true
@ -194,7 +202,9 @@ jobs:
test-mssql:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
# specifying the version of ubuntu in use as mssql fails on newer kernels
# pending resolution from vendor
runs-on: ubuntu-20.04
services:
mssql:
image: mcr.microsoft.com/mssql/server:2017-latest
@ -204,6 +214,10 @@ jobs:
SA_PASSWORD: MwantsaSecurePassword1
ports:
- "1433:1433"
devstoreaccount1.azurite.local: # https://github.com/Azure/Azurite/issues/1583
image: mcr.microsoft.com/azure-storage/azurite:latest
ports:
- 10000:10000
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
@ -211,7 +225,7 @@ jobs:
go-version-file: go.mod
check-latest: true
- name: Add hosts to /etc/hosts
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mssql" | sudo tee -a /etc/hosts'
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mssql devstoreaccount1.azurite.local" | sudo tee -a /etc/hosts'
- run: make deps-backend
- run: make backend
env:

View File

@ -23,7 +23,9 @@ jobs:
check-latest: true
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend frontend deps-backend
- run: npx playwright install --with-deps
- run: make test-e2e-sqlite

View File

@ -9,10 +9,8 @@ concurrency:
cancel-in-progress: true
jobs:
disk-clean:
uses: ./.github/workflows/disk-clean.yml
nightly-binary:
runs-on: nscloud
runs-on: namespace-profile-gitea-release-binary
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -24,7 +22,9 @@ jobs:
check-latest: true
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend deps-backend
# xgo build
- run: make release
@ -47,7 +47,7 @@ jobs:
run: |
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
echo "Cleaned name is ${REF_NAME}"
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- name: configure aws
uses: aws-actions/configure-aws-credentials@v4
with:
@ -58,7 +58,7 @@ jobs:
run: |
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
nightly-docker-rootful:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -95,7 +95,7 @@ jobs:
push: true
tags: gitea/gitea:${{ steps.clean_name.outputs.branch }}
nightly-docker-rootless:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions

View File

@ -11,7 +11,7 @@ concurrency:
jobs:
binary:
runs-on: nscloud
runs-on: namespace-profile-gitea-release-binary
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -23,7 +23,9 @@ jobs:
check-latest: true
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend deps-backend
# xgo build
- run: make release
@ -66,7 +68,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
docker-rootful:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -97,7 +99,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
docker-rootless:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions

View File

@ -13,7 +13,7 @@ concurrency:
jobs:
binary:
runs-on: nscloud
runs-on: namespace-profile-gitea-release-binary
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -25,7 +25,9 @@ jobs:
check-latest: true
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: make deps-frontend deps-backend
# xgo build
- run: make release
@ -68,7 +70,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
docker-rootful:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -103,7 +105,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
docker-rootless:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions

8
.gitignore vendored
View File

@ -28,6 +28,7 @@ _testmain.go
*.exe
*.test
*.prof
*.tsbuildinfo
*coverage.out
coverage.all
@ -77,7 +78,6 @@ cpu.out
/public/assets/css
/public/assets/fonts
/public/assets/licenses.txt
/public/assets/img/webpack
/vendor
/web_src/fomantic/node_modules
/web_src/fomantic/build/*
@ -95,6 +95,9 @@ cpu.out
/.air
/.go-licenses
# Files and folders that were previously generated
/public/assets/img/webpack
# Snapcraft
/gitea_a*.txt
snap/.snapcraft/
@ -106,6 +109,9 @@ prime/
*_source.tar.bz2
.DS_Store
# nix-direnv generated files
.direnv/
# Make evidence files
/.make_evidence

View File

@ -43,7 +43,7 @@ vscode:
- Vue.volar
- ms-azuretools.vscode-docker
- vitest.explorer
- qwtel.sqlite-viewer
- cweijan.vscode-database-client2
- GitHub.vscode-pull-request-github
ports:

View File

@ -1,13 +1,14 @@
linters:
enable-all: false
disable-all: true
fast: false
enable:
- bidichk
# - deadcode # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- depguard
- dupl
- errcheck
- forbidigo
- gocritic
# - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- gofumpt
- gosimple
@ -17,25 +18,28 @@ linters:
- nolintlint
- revive
- staticcheck
# - structcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- stylecheck
- tenv
- testifylint
- typecheck
- unconvert
- unused
# - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- unparam
- wastedassign
enable-all: false
disable-all: true
fast: false
run:
timeout: 10m
skip-dirs:
- node_modules
- public
- web_src
output:
sort-results: true
sort-order: [file]
show-stats: true
linters-settings:
testifylint:
disable:
- go-require
- require-error
stylecheck:
checks: ["all", "-ST1005", "-ST1003"]
nakedret:
@ -45,33 +49,39 @@ linters-settings:
- ifElseChain
- singleCaseSwitch # Every time this occurred in the code, there was no other way.
revive:
ignore-generated-header: false
severity: warning
confidence: 0.8
errorCode: 1
warningCode: 1
severity: error
rules:
- name: atomic
- name: bare-return
- name: blank-imports
- name: constant-logical-expr
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: duplicated-imports
- name: empty-lines
- name: error-naming
- name: error-return
- name: error-strings
- name: error-naming
- name: errorf
- name: exported
- name: identical-branches
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: indent-error-flow
- name: modifies-value-receiver
- name: package-comments
- name: range
- name: receiver-naming
- name: redefines-builtin-id
- name: string-of-int
- name: superfluous-else
- name: time-naming
- name: unconditional-recursion
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: duplicated-imports
- name: modifies-value-receiver
- name: unreachable-code
- name: var-declaration
- name: var-naming
gofumpt:
extra-rules: true
depguard:
@ -90,12 +100,15 @@ linters-settings:
desc: do not use the internal package, use AddXxx function instead
- pkg: gopkg.in/ini.v1
desc: do not use the ini package, use gitea's config system instead
- pkg: gitea.com/go-chi/cache
desc: do not use the go-chi cache package, use gitea's cache system
issues:
max-issues-per-linter: 0
max-same-issues: 0
exclude-dirs: [node_modules, public, web_src]
exclude-case-sensitive: true
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gocyclo
@ -113,19 +126,19 @@ issues:
- path: cmd
linters:
- forbidigo
- linters:
- text: "webhook"
linters:
- dupl
text: "webhook"
- linters:
- text: "`ID' should not be capitalized"
linters:
- gocritic
text: "`ID' should not be capitalized"
- linters:
- text: "swagger"
linters:
- unused
- deadcode
text: "swagger"
- linters:
- text: "argument x is overwritten before first use"
linters:
- staticcheck
text: "argument x is overwritten before first use"
- text: "commentFormatting: put a space between `//` and comment text"
linters:
- gocritic

View File

@ -4,6 +4,8 @@
/modules/options/bindata.go
/modules/public/bindata.go
/modules/templates/bindata.go
/vendor
/options/gitignore
/options/license
/public/assets
/vendor
node_modules

View File

@ -1,223 +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": always
"@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/named-grid-areas-alignment": 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: true
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: [true, ignoreAtRules: [tailwind]]
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-anb-no-unmatchable: 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]}]

5223
CHANGELOG-archived.md Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -77,7 +77,7 @@ If your issue has not been reported yet, [open an issue](https://github.com/go-g
and answer the questions so we can understand and reproduce the problematic behavior. \
Please write clear and concise instructions so that we can reproduce the behavior — even if it seems obvious. \
The more detailed and specific you are, the faster we can fix the issue. \
It is really helpful if you can reproduce your problem on a site running on the latest commits, i.e. <https://try.gitea.io>, as perhaps your problem has already been fixed on a current version. \
It is really helpful if you can reproduce your problem on a site running on the latest commits, i.e. <https://demo.gitea.com>, as perhaps your problem has already been fixed on a current version. \
Please follow the guidelines described in [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for your report.
Please be kind, remember that Gitea comes at no cost to you, and you're getting free help.
@ -358,11 +358,12 @@ $REWRITTEN_PR_SUMMARY
## Documentation
If you add a new feature or change an existing aspect of Gitea, the documentation for that feature must be created or updated in the same PR.
If you add a new feature or change an existing aspect of Gitea, the documentation for that feature must be created or updated in another PR at [https://gitea.com/gitea/docs](https://gitea.com/gitea/docs).
**The docs directory on main repository will be removed at some time. We will have a yaml file to store configuration file's meta data. After that completed, configuration documentation should be in the main repository.**
## API v1
The API is documented by [swagger](http://try.gitea.io/api/swagger) and is based on [the GitHub API](https://docs.github.com/en/rest).
The API is documented by [swagger](https://gitea.com/api/swagger) and is based on [the GitHub API](https://docs.github.com/en/rest).
### GitHub API compatibility

View File

@ -1,12 +1,12 @@
# Build stage
FROM docker.io/library/golang:1.22-alpine3.19 AS build-env
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}
ENV GOPROXY=${GOPROXY:-direct}
ARG GITEA_VERSION
ARG TAGS="sqlite sqlite_unlock_notify"
ENV TAGS "bindata timetzdata $TAGS"
ENV TAGS="bindata timetzdata $TAGS"
ARG CGO_EXTRA_CFLAGS
# Build deps
@ -41,7 +41,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
/go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM docker.io/library/alpine:3.19
FROM docker.io/library/alpine:3.20
LABEL maintainer="maintainers@gitea.io"
EXPOSE 22 3000
@ -72,8 +72,8 @@ RUN addgroup \
git && \
echo "git:*" | chpasswd -e
ENV USER git
ENV GITEA_CUSTOM /data/gitea
ENV USER=git
ENV GITEA_CUSTOM=/data/gitea
VOLUME ["/data"]

View File

@ -1,12 +1,12 @@
# Build stage
FROM docker.io/library/golang:1.22-alpine3.19 AS build-env
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}
ENV GOPROXY=${GOPROXY:-direct}
ARG GITEA_VERSION
ARG TAGS="sqlite sqlite_unlock_notify"
ENV TAGS "bindata timetzdata $TAGS"
ENV TAGS="bindata timetzdata $TAGS"
ARG CGO_EXTRA_CFLAGS
#Build deps
@ -39,7 +39,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
/go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM docker.io/library/alpine:3.19
FROM docker.io/library/alpine:3.20
LABEL maintainer="maintainers@gitea.io"
EXPOSE 2222 3000
@ -75,14 +75,14 @@ COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_au
# git:git
USER 1000:1000
ENV GITEA_WORK_DIR /var/lib/gitea
ENV GITEA_CUSTOM /var/lib/gitea/custom
ENV GITEA_TEMP /tmp/gitea
ENV TMPDIR /tmp/gitea
ENV GITEA_WORK_DIR=/var/lib/gitea
ENV GITEA_CUSTOM=/var/lib/gitea/custom
ENV GITEA_TEMP=/tmp/gitea
ENV TMPDIR=/tmp/gitea
# TODO add to docs the ability to define the ini to load (useful to test and revert a config)
ENV GITEA_APP_INI /etc/gitea/app.ini
ENV HOME "/var/lib/gitea/git"
ENV GITEA_APP_INI=/etc/gitea/app.ini
ENV HOME="/var/lib/gitea/git"
VOLUME ["/var/lib/gitea", "/etc/gitea"]
WORKDIR /var/lib/gitea

View File

@ -46,7 +46,6 @@ Wim <wim@42.be> (@42wim)
Jason Song <i@wolfogre.com> (@wolfogre)
Yarden Shoham <git@yardenshoham.com> (@yardenshoham)
Yu Tian <zettat123@gmail.com> (@Zettat123)
Eddie Yang <576951401@qq.com> (@yp05327)
Dong Ge <gedong_1994@163.com> (@sillyguodong)
Xinyi Gong <hestergong@gmail.com> (@HesterG)
wxiaoguang <wxiaoguang@gmail.com> (@wxiaoguang)
@ -60,3 +59,7 @@ Nanguan Lin <nanguanlin6@gmail.com> (@lng2020)
kerwin612 <kerwin612@qq.com> (@kerwin612)
Gary Wang <git@blumia.net> (@BLumia)
Tim-Niclas Oelschläger <zokki.softwareschmiede@gmail.com> (@zokkis)
Yu Liu <1240335630@qq.com> (@HEREYUA)
Kemal Zebari <kemalzebra@gmail.com> (@kemzeb)
Rowan Bohde <rowan.bohde@gmail.com> (@bohde)
hiifong <i@hiif.ong> (@hiifong)

108
Makefile
View File

@ -23,19 +23,20 @@ SHASUM ?= shasum -a 256
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
COMMA := ,
XGO_VERSION := go-1.22.x
XGO_VERSION := go-1.23.x
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.49.0
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.56.1
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.4.1
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@db51e79a0e37c572d8b59ae0c58bf2bbbbe53285
AIR_PACKAGE ?= github.com/air-verse/air@v1
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.0.3
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.12
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.0.3
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.6.26
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.17.0
DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest
@ -88,7 +89,7 @@ ifneq ($(GITHUB_REF_TYPE),branch)
GITEA_VERSION ?= $(VERSION)
else
ifneq ($(GITHUB_REF_NAME),)
VERSION ?= $(subst release/v,,$(GITHUB_REF_NAME))
VERSION ?= $(subst release/v,,$(GITHUB_REF_NAME))-nightly
else
VERSION ?= main
endif
@ -110,7 +111,6 @@ LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(G
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/))
GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/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/))
MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...)
@ -119,7 +119,7 @@ FOMANTIC_WORK_DIR := web_src/fomantic
WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
WEBPACK_CONFIGS := webpack.config.js tailwind.config.js
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_HASH := $(addsuffix .hash,$(BINDATA_DEST))
@ -137,16 +137,16 @@ TAGS ?=
TAGS_SPLIT := $(subst $(COMMA), ,$(TAGS))
TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags
TEST_TAGS ?= sqlite sqlite_unlock_notify
TEST_TAGS ?= $(TAGS_SPLIT) sqlite sqlite_unlock_notify
TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMANTIC_WORK_DIR)/node_modules $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR) $(GO_LICENSE_TMP_DIR)
GO_DIRS := build cmd models modules routers services tests
WEB_DIRS := web_src/js web_src/css
ESLINT_FILES := web_src/js tools *.config.js tests/e2e
ESLINT_FILES := web_src/js tools *.js *.ts 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) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.js *.md *.yml *.yaml *.toml))
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
GO_SOURCES := $(wildcard *.go)
@ -179,6 +179,7 @@ TEST_PGSQL_DBNAME ?= testgitea
TEST_PGSQL_USERNAME ?= postgres
TEST_PGSQL_PASSWORD ?= postgres
TEST_PGSQL_SCHEMA ?= gtestschema
TEST_MINIO_ENDPOINT ?= minio:9000
TEST_MSSQL_HOST ?= mssql:1433
TEST_MSSQL_DBNAME ?= gitea
TEST_MSSQL_USERNAME ?= sa
@ -214,6 +215,7 @@ help:
@echo " - lint-go lint go files"
@echo " - lint-go-fix lint go files and fix issues"
@echo " - lint-go-vet lint go files with vet"
@echo " - lint-go-gopls lint go files with gopls"
@echo " - lint-js lint js files"
@echo " - lint-js-fix lint js files and fix issues"
@echo " - lint-css lint css files"
@ -295,7 +297,7 @@ clean:
.PHONY: fmt
fmt:
GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
@GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
@# whitespace before it
@ -367,18 +369,20 @@ lint-frontend: lint-js lint-css
lint-frontend-fix: lint-js-fix lint-css-fix
.PHONY: lint-backend
lint-backend: lint-go lint-go-vet lint-editorconfig
lint-backend: lint-go lint-go-vet lint-go-gopls lint-editorconfig
.PHONY: lint-backend-fix
lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig
.PHONY: lint-js
lint-js: node_modules
npx eslint --color --max-warnings=0 --ext js,vue $(ESLINT_FILES)
npx eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES)
npx vue-tsc
.PHONY: lint-js-fix
lint-js-fix: node_modules
npx eslint --color --max-warnings=0 --ext js,vue $(ESLINT_FILES) --fix
npx eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) --fix
npx vue-tsc
.PHONY: lint-css
lint-css: node_modules
@ -394,15 +398,15 @@ lint-swagger: node_modules
.PHONY: lint-md
lint-md: node_modules
npx markdownlint docs *.md
npx markdownlint *.md
.PHONY: lint-spell
lint-spell:
@go run $(MISSPELL_PACKAGE) -error $(SPELLCHECK_FILES)
@go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -error $(SPELLCHECK_FILES)
.PHONY: lint-spell-fix
lint-spell-fix:
@go run $(MISSPELL_PACKAGE) -w $(SPELLCHECK_FILES)
@go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -w $(SPELLCHECK_FILES)
.PHONY: lint-go
lint-go:
@ -423,7 +427,12 @@ lint-go-windows:
lint-go-vet:
@echo "Running go vet..."
@GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet
@$(GO) vet -vettool=gitea-vet $(GO_PACKAGES)
@$(GO) vet -vettool=gitea-vet ./...
.PHONY: lint-go-gopls
lint-go-gopls:
@echo "Running gopls check..."
@GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES_NO_BINDATA)
.PHONY: lint-editorconfig
lint-editorconfig:
@ -434,7 +443,8 @@ lint-actions:
$(GO) run $(ACTIONLINT_PACKAGE)
.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')
.PHONY: lint-yaml
@ -565,6 +575,7 @@ generate-ini-pgsql:
-e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
-e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \
-e 's|{{TEST_MINIO_ENDPOINT}}|${TEST_MINIO_ENDPOINT}|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' \
@ -778,7 +789,7 @@ generate-backend: $(TAGS_PREREQ) generate-go
.PHONY: generate-go
generate-go: $(TAGS_PREREQ)
@echo "Running go generate..."
@CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' $(GO_PACKAGES)
@CC= GOOS= GOARCH= CGO_ENABLED=0 $(GO) generate -tags '$(TAGS)' ./...
.PHONY: security-check
security-check:
@ -788,7 +799,7 @@ $(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
.PHONY: release
release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-docs release-check
release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-check
$(DIST_DIRS):
mkdir -p $(DIST_DIRS)
@ -834,10 +845,6 @@ release-sources: | $(DIST_DIRS)
tar $(addprefix $(EXCL),$(TAR_EXCLUDES)) $(TRANSFORM) -czf $(DIST)/release/gitea-src-$(VERSION).tar.gz .
rm -f $(STORED_VERSION_FILE)
.PHONY: release-docs
release-docs: | $(DIST_DIRS) docs
tar -czf $(DIST)/release/gitea-docs-$(VERSION).tar.gz -C ./docs .
.PHONY: deps
deps: deps-frontend deps-backend deps-tools deps-py
@ -853,24 +860,26 @@ deps-backend:
.PHONY: deps-tools
deps-tools:
$(GO) install $(AIR_PACKAGE)
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
$(GO) install $(GOFUMPT_PACKAGE)
$(GO) install $(GOLANGCI_LINT_PACKAGE)
$(GO) install $(GXZ_PACKAGE)
$(GO) install $(MISSPELL_PACKAGE)
$(GO) install $(SWAGGER_PACKAGE)
$(GO) install $(XGO_PACKAGE)
$(GO) install $(GO_LICENSES_PACKAGE)
$(GO) install $(GOVULNCHECK_PACKAGE)
$(GO) install $(ACTIONLINT_PACKAGE)
$(GO) install $(AIR_PACKAGE) & \
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \
$(GO) install $(GOFUMPT_PACKAGE) & \
$(GO) install $(GOLANGCI_LINT_PACKAGE) & \
$(GO) install $(GXZ_PACKAGE) & \
$(GO) install $(MISSPELL_PACKAGE) & \
$(GO) install $(SWAGGER_PACKAGE) & \
$(GO) install $(XGO_PACKAGE) & \
$(GO) install $(GO_LICENSES_PACKAGE) & \
$(GO) install $(GOVULNCHECK_PACKAGE) & \
$(GO) install $(ACTIONLINT_PACKAGE) & \
$(GO) install $(GOPLS_PACKAGE) & \
wait
node_modules: package-lock.json
npm install --no-save
@touch node_modules
.venv: poetry.lock
poetry install --no-root
poetry install
@touch .venv
.PHONY: update
@ -881,13 +890,15 @@ update-js: node-check | node_modules
npx updates -u -f package.json
rm -rf node_modules package-lock.json
npm install --package-lock
npx nolyfill install
npm install --package-lock
@touch node_modules
.PHONY: update-py
update-py: node-check | node_modules
npx updates -u -f pyproject.toml
rm -rf .venv poetry.lock
poetry install --no-root
poetry install
@touch .venv
.PHONY: fomantic
@ -908,8 +919,9 @@ webpack: $(WEBPACK_DEST)
$(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json
@$(MAKE) -s node-check node_modules
rm -rf $(WEBPACK_DEST_ENTRIES)
npx webpack
@rm -rf $(WEBPACK_DEST_ENTRIES)
@echo "Running webpack..."
@BROWSERSLIST_IGNORE_OLD_DATA=true npx webpack
@touch $(WEBPACK_DEST)
.PHONY: svg
@ -958,7 +970,7 @@ generate-gitignore:
.PHONY: generate-images
generate-images: | node_modules
npm install --no-save fabric@6.0.0-beta19 imagemin-zopfli@7
npm install --no-save fabric@6 imagemin-zopfli@7
node tools/generate-images.js $(TAGS)
.PHONY: generate-manpage

View File

@ -8,9 +8,8 @@
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
[![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
[![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT")
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea "Crowdin")
[![](https://badgen.net/https/api.tickgit.com/badgen/github.com/go-gitea/gitea/main)](https://www.tickgit.com/browse?repo=github.com/go-gitea/gitea&branch=main "TODOs")
[View this document in Chinese](./README_ZH.md)
@ -26,7 +25,7 @@ This project has been
[forked](https://blog.gitea.com/welcome-to-gitea/) from
[Gogs](https://gogs.io) since November of 2016, but a lot has changed.
For online demonstrations, you can visit [try.gitea.io](https://try.gitea.io).
For online demonstrations, you can visit [demo.gitea.com](https://demo.gitea.com).
For accessing free Gitea service (with a limited number of repositories), you can visit [gitea.com](https://gitea.com/user/login).
@ -56,7 +55,7 @@ More info: https://docs.gitea.com/installation/install-from-source
./gitea web
> [!NOTE]
> If you're interested in using our APIs, we have experimental support with [documentation](https://try.gitea.io/api/swagger).
> If you're interested in using our APIs, we have experimental support with [documentation](https://docs.gitea.com/api).
## Contributing
@ -80,7 +79,7 @@ https://docs.gitea.com/contributing/localization
## Further information
For more information and instructions about how to install Gitea, please look at our [documentation](https://docs.gitea.com/).
If you have questions that are not covered by the documentation, you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://discourse.gitea.io/).
If you have questions that are not covered by the documentation, you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://forum.gitea.com/).
We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea).

View File

@ -8,9 +8,8 @@
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
[![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
[![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT")
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea "Crowdin")
[![](https://badgen.net/https/api.tickgit.com/badgen/github.com/go-gitea/gitea/main)](https://www.tickgit.com/browse?repo=github.com/go-gitea/gitea&branch=main "TODOs")
[View this document in English](./README.md)
@ -18,7 +17,7 @@
Gitea 的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用 Go 作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了 x86amd64还包括 ARM 和 PowerPC。
如果你想试用在线演示,请访问 [try.gitea.io](https://try.gitea.io/)。
如果你想试用在线演示和报告问题,请访问 [demo.gitea.com](https://demo.gitea.com/)。
如果你想使用免费的 Gitea 服务(有仓库数量限制),请访问 [gitea.com](https://gitea.com/user/login)。

View File

@ -14,12 +14,12 @@ Please **DO NOT** file a public issue, instead send your report privately to `se
Due to the sensitive nature of security information, you can use the below GPG public key to encrypt your mail body.
The PGP key is valid until June 24, 2024.
The PGP key is valid until July 9, 2025.
```
Key ID: 6FCD2D5B
Key Type: RSA
Expires: 6/24/2024
Expires: 7/9/2025
Key Size: 4096/4096
Fingerprint: 3DE0 3D1E 144A 7F06 9359 99DC AAFD 2381 6FCD 2D5B
```
@ -40,20 +40,20 @@ q+pHZl24JYR0Kf3T/ZiOC0cGd2QJqpJtg5J6S/OqfX9NH6MsCczO8pUC1N/aHH2X
CTme2nF56izORqDWKoiICteL3GpYsCV9nyCidcCmoQsS+DKvE86YhIhVIVWGRY2F
lzpAjnN9/KLtQroutrm+Ft0mdjDiJUeFVl1cOHDhoyfCsQh62HumoyZoZvqzQd6e
AbN11nq6aViMe2Q3je1AbiBnRnQSHxt1Tc8X4IshO3MQK1Sk7oPI6LA5oQARAQAB
tCJHaXRlYSBTZWN1cml0eSA8c2VjdXJpdHlAZ2l0ZWEuaW8+iQJXBBMBCABBFiEE
PeA9HhRKfwaTWZncqv0jgW/NLVsFAmK1Z/4CGwMFCQPCZwAFCwkIBwICIgIGFQoJ
CAsCBBYCAwECHgcCF4AACgkQqv0jgW/NLVvnyxAAhxyNnWzw/rQO2qhzqicmZM94
njSbOg+U2qMBvCdaqCQQeC+uaMmMzkDPanUUmLcyCkWqfCjPNjeSXAkE9npepVJI
4HtmgxZQ94OU/h3CLbft+9GVRzUkVI29TSYGdvNtV2/BkNGoFFnKWQr119um0o6A
bgha2Uy5uY8o3ZIoiKkiHRaEoWIjjeBxJxYAojsZY4YElUmsQ3ik2joG6rhFesTa
ofVt/bL8G2xzpOG26WGIxBbqf2qjV6OtZ0hu/vtTPHeIWMLq0Mz0V3PEDQWfkGPE
i2RYxxYDs2xzJhSQWqTNVLSq0m5xTJnbHhQPfdCX4C2jvFKgLdfmytQq49S7jiJb
Z03HVOZ/PsyBlQfH9xJi06R5yQCMEA8h8Z5r3/NXW09kQ6OFRe6xshoTcxZGRPTo
srhwr3uPbmCRh+YEl7qBLU6+BC5k8IRTZXqhrj/aPJu3MxgbgwV8u3vLoFSXM2lb
a61FgeCQ0O7lkgVswwF0RppCaH9Ul3ZDapet/vCRg4NVwm9zOI/8q/Vj0FKA1GDR
JhRu8+Ce8zlFL65D34t+PprAzSeTlbv9um3x/ZIjCco7EEKSBylt+AZj/VyA6+e5
kjOQwRRc6dFJWBcorsSI2dG+H+QMF7ZabzmeCcz1v9HjLOPzYHoZAHhCmSppWTvX
AJy6+lhfW2OUTqQeYSi5Ag0EYrVn/gEQALrFLQjCR3GjuHSindz0rd3Fnx/t7Sen
tCJHaXRlYSBTZWN1cml0eSA8c2VjdXJpdHlAZ2l0ZWEuaW8+iQJXBBMBCABBAhsD
BQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAFiEEPeA9HhRKfwaTWZncqv0jgW/N
LVsFAmaMse0FCQW4fW8ACgkQqv0jgW/NLVtXLg/+PF4G9Jhlui15BTNlEBJAV2P/
1QlAV2krk0fP7tykn0FR9RfGIfVV/kwC1f+ouosYPQDDevl9LWdUIM+g94DtNo2o
7ACpcL3morvt5lVGpIZHL8TbX0qmFRXL/pB/cB+K6IwYvh2mrbp2zH+r4SCRyFYq
BjgXYFTI1MylJ1ShAjU6Z+m3oJ+2xs5LzHS0X6zkTjzA2Zl4zQzciQ9T+wJcE7Zi
HXdM1+YMF8KGNP8J9Rpug5oNDJ98lgZirRY7c3A/1xmYBiPnULwuuymdqEZO7l70
SeAlE1RWYX8kbOBnBb/KY4XwE3Vic1oEzc9DiPWVH1ElX86WNNsFzuyULiwoBoWg
pqZGhL9x1p5+46RGQSDczsHM7YGVtfYOiDo2PAVrmwsT0BnXnK8Oe3YIkvmUPEJu
OkLt0Z6A5n8pz8zhQzuApwBsK4ncJ8zTCpvz/pfKKqZC/Vnoh3gKGhDGvOZ+b5IJ
0kUTe2JsbnwFixDUMDtacQ1op8XOyLoLVmgqLn0+Pws4XPBlMof2bioFir3yHKnP
gNchsF1agrlSIo5GA8u4ga+IlCSfvFIKrl7+cxacKcJYt/vbOU5KcvVJI5EtHKCG
xfHjHY2ah1Qww7SxW6IXiRZZzPpsL2mBM2CD7N3qh9bV2s27wxYCdUodsIZbiyHe
oWPzfBnkmiAN8KlZxHm5Ag0EYrVn/gEQALrFLQjCR3GjuHSindz0rd3Fnx/t7Sen
T+p07yCSSoSlmnJHCQmwh4vfg1blyz0zZ4vkIhtpHsEgc+ZAG+WQXSsJ2iRz+eSN
GwoOQl4XC3n+QWkc1ws+btr48+6UqXIQU+F8TPQyx/PIgi2nZXJB7f5+mjCqsk46
XvH4nTr4kJjuqMSR/++wvre2qNQRa/q/dTsK0OaN/mJsdX6Oi+aGNaQJUhIG7F+E
@ -64,20 +64,20 @@ qoExANj5lUTZPe8M50lI182FrcjAN7dClO3QI6pg7wy0erMxfFly3j8UQ91ysS9T
s+GsP9I3cmWWQcKYxWHtE8xTXnNCVPFZQj2nwhJzae8ypfOtulBRA3dUKWGKuDH/
axFENhUsT397aOU3qkP/od4a64JyNIEo4CTTSPVeWd7njsGqli2U3A4xL2CcyYvt
D/MWcMBGEoLSNTswwKdom4FaJpn5KThnK/T0bQcmJblJhoCtppXisbexZnCpuS0x
Zdlm2T14KJ3LABEBAAGJAjwEGAEIACYWIQQ94D0eFEp/BpNZmdyq/SOBb80tWwUC
YrVn/gIbDAUJA8JnAAAKCRCq/SOBb80tWyTBD/9AGpW6QoDF7zYjHAozH9S5RGCA
Y7E82dG/0xmFUwPprAG0BKmmgU6TiipyVGmKIXGYYYU92pMnbvXkYQMoa+WJNncN
D3fY52UeXeffTf4cFpStlzi9xgYtOLhFamzYu/4xhkjOX+xhOSXscCiFRyT8cF3B
O6c5BHU+Zj0/rGPgOyPUbx7l7B9MubB/41nNX35k08e+8T3wtWDb4XF+15HnRfva
6fblO8wgU25Orv2Rm1jnKGa9DxJ8nE40IMrqDapENtDuL+zKJsvR0+ptWvEyL56U
GtJJG5un6mXiLKuRQT0DEv4MdZRHDgDstDnqcbEiazVEbUuvhZZob6lRY2A19m1+
7zfnDxkhqCA1RCnv4fdvcPdCMMFHwLpdhjgW0aI/uwgwrvsEz5+JRlnLvdQHlPAg
q7l2fGcBSpz9U0ayyfRPjPntsNCtZl1UDxGLeciPkZhyG84zEWQbk/j52ZpRN+Ik
ALpRLa8RBFmFSmXDUmwQrmm1EmARyQXwweKU31hf8ZGbCp2lPuRYm1LuGiirXSVP
GysjRAJgW+VRpBKOzFQoUAUbReVWSaCwT8s17THzf71DdDb6CTj31jMLLYWwBpA/
i73DgobDZMIGEZZC1EKqza8eh11xfyHFzGec03tbh+lIen+5IiRtWiEWkDS9ll0G
zgS/ZdziCvdAutqnGA==
=gZWO
Zdlm2T14KJ3LABEBAAGJAjwEGAEIACYCGwwWIQQ94D0eFEp/BpNZmdyq/SOBb80t
WwUCZoyyjQUJBbh+DwAKCRCq/SOBb80tW18XD/9MXztmf01MT+1kZdBouZ/7Rp/7
9kuqo//B1G+RXau4oFtPqb67kNe2WaIc3u5B73PUHsMf3i6z4ib2KbMhZZerLn0O
dRglcuPeNWmsASY3dH/XVG0cT0zvvWegagd12TJEl3Vs+7XNrOw4cwDj9L1+GH9m
kSt4uaANWn/6a3RvMRhiVEYuNwhAzcKaactPmYqrLJgoVLbRSDkgyHaMQ2jKgLxk
ifS/fvluGV0ub2Po6DJiqfRpd1tDvPhe9y1+r1WFDZsOcvTcZUfSt/7dXMGfqGu0
2daVFlfeSXSALrDE5uc0UxodHCpP3sqRYDZevGLBRaaTkIjYXG/+N898+7K5WJF4
xXOLWxM2cwGkG7eC9pugcDnBp9XlF7O+GBiZ05JUe5flXDQFZ+h3exjopu6KHF1B
RnzNy8LC0UKb+AuvRIOLV92a9Q9wGWU/jaVDu6nZ0umAeuSzxiHoDsonm0Fl9QAz
2/xCokebuoeLrEK7R2af3X86mqq3sVO4ax+HPYChzOaVQBiHUW/TAldWcldYYphR
/e2WsbmQfvCRtz/bZfo+aUVnrHNjzVMtF2SszdVmA/04Y8pS28MqtuRqhm5DPOOd
g1YeUywK5jRZ1twyo1kzJEFPLaoeaXaycsR1PMVBW0Urik5mrR/pOWq7PPoZoKb2
lXYLE8bwkuQTmsyL1g==
=9i7d
-----END PGP PUBLIC KEY BLOCK-----
```

226
assets/go-licenses.json generated

File diff suppressed because one or more lines are too long

View File

@ -69,6 +69,7 @@ func newFileCollector(fileFilter string, batchSize int) (*fileCollector, error)
co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`.*\bbindata\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`\.pb\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/gitea-repositories-meta`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/integration/migration-test`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`modules/git/tests`))
@ -203,17 +204,6 @@ Example:
`, "file-batch-exec")
}
func getGoVersion() string {
goModFile, err := os.ReadFile("go.mod")
if err != nil {
log.Fatalf(`Faild to read "go.mod": %v`, err)
os.Exit(1)
}
goModVersionRegex := regexp.MustCompile(`go \d+\.\d+`)
goModVersionLine := goModVersionRegex.Find(goModFile)
return string(goModVersionLine[3:])
}
func newFileCollectorFromMainOptions(mainOptions map[string]string) (fc *fileCollector, err error) {
fileFilter := mainOptions["file-filter"]
if fileFilter == "" {
@ -278,7 +268,8 @@ func main() {
log.Print("the -d option is not supported by gitea-fmt")
}
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-w")))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", getGoVersion()}, substArgs...)))
cmdErrors = append(cmdErrors, passThroughCmd("gofmt", append([]string{"-w", "-r", "interface{} -> any"}, substArgs...)))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra"}, substArgs...)))
default:
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
}

View File

@ -53,8 +53,6 @@ func (e Emoji) MarshalJSON() ([]byte, error) {
}
func main() {
var err error
flag.Parse()
// generate data
@ -83,8 +81,6 @@ var replacer = strings.NewReplacer(
var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`)
func generate() ([]byte, error) {
var err error
// load gemoji data
res, err := http.Get(gemojiURL)
if err != nil {

View File

@ -1,3 +1,6 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
package main
@ -5,6 +8,8 @@ package main
import (
"archive/tar"
"compress/gzip"
"crypto/md5"
"encoding/hex"
"flag"
"fmt"
"io"
@ -15,6 +20,8 @@ import (
"path/filepath"
"strings"
"code.gitea.io/gitea/build/license"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/util"
)
@ -77,7 +84,7 @@ func main() {
}
tr := tar.NewReader(gz)
aliasesFiles := make(map[string][]string)
for {
hdr, err := tr.Next()
@ -97,26 +104,73 @@ func main() {
continue
}
if strings.HasPrefix(filepath.Base(hdr.Name), "README") {
fileBaseName := filepath.Base(hdr.Name)
licenseName := strings.TrimSuffix(fileBaseName, ".txt")
if strings.HasPrefix(fileBaseName, "README") {
continue
}
if strings.HasPrefix(filepath.Base(hdr.Name), "deprecated_") {
if strings.HasPrefix(fileBaseName, "deprecated_") {
continue
}
out, err := os.Create(path.Join(destination, strings.TrimSuffix(filepath.Base(hdr.Name), ".txt")))
out, err := os.Create(path.Join(destination, licenseName))
if err != nil {
log.Fatalf("Failed to create new file. %s", err)
}
defer out.Close()
if _, err := io.Copy(out, tr); err != nil {
// some license files have same content, so we need to detect these files and create a convert map into a json file
// Later we use this convert map to avoid adding same license content with different license name
h := md5.New()
// calculate md5 and write file in the same time
r := io.TeeReader(tr, h)
if _, err := io.Copy(out, r); err != nil {
log.Fatalf("Failed to write new file. %s", err)
} else {
fmt.Printf("Written %s\n", out.Name())
md5 := hex.EncodeToString(h.Sum(nil))
aliasesFiles[md5] = append(aliasesFiles[md5], licenseName)
}
}
// generate convert license name map
licenseAliases := make(map[string]string)
for _, fileNames := range aliasesFiles {
if len(fileNames) > 1 {
licenseName := license.GetLicenseNameFromAliases(fileNames)
if licenseName == "" {
// license name should not be empty as expected
// if it is empty, we need to rewrite the logic of GetLicenseNameFromAliases
log.Fatalf("GetLicenseNameFromAliases: license name is empty")
}
for _, fileName := range fileNames {
licenseAliases[fileName] = licenseName
}
}
}
// save convert license name map to file
b, err := json.Marshal(licenseAliases)
if err != nil {
log.Fatalf("Failed to create json bytes. %s", err)
}
licenseAliasesDestination := filepath.Join(destination, "etc", "license-aliases.json")
if err := os.MkdirAll(filepath.Dir(licenseAliasesDestination), 0o755); err != nil {
log.Fatalf("Failed to create directory for license aliases json file. %s", err)
}
f, err := os.Create(licenseAliasesDestination)
if err != nil {
log.Fatalf("Failed to create license aliases json file. %s", err)
}
defer f.Close()
if _, err = f.Write(b); err != nil {
log.Fatalf("Failed to write license aliases json file. %s", err)
}
fmt.Println("Done")
}

View File

@ -0,0 +1,41 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package license
import "strings"
func GetLicenseNameFromAliases(fnl []string) string {
if len(fnl) == 0 {
return ""
}
shortestItem := func(list []string) string {
s := list[0]
for _, l := range list[1:] {
if len(l) < len(s) {
s = l
}
}
return s
}
allHasPrefix := func(list []string, s string) bool {
for _, l := range list {
if !strings.HasPrefix(l, s) {
return false
}
}
return true
}
sl := shortestItem(fnl)
slv := strings.Split(sl, "-")
var result string
for i := len(slv); i >= 0; i-- {
result = strings.Join(slv[:i], "-")
if allHasPrefix(fnl, result) {
return result
}
}
return ""
}

View File

@ -0,0 +1,39 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package license
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetLicenseNameFromAliases(t *testing.T) {
tests := []struct {
target string
inputs []string
}{
{
// real case which you can find in license-aliases.json
target: "AGPL-1.0",
inputs: []string{
"AGPL-1.0-only",
"AGPL-1.0-or-late",
},
},
{
target: "",
inputs: []string{
"APSL-1.0",
"AGPL-1.0-only",
"AGPL-1.0-or-late",
},
},
}
for _, tt := range tests {
result := GetLicenseNameFromAliases(tt.inputs)
assert.Equal(t, result, tt.target)
}
}

View File

@ -4,6 +4,7 @@
package cmd
import (
"errors"
"fmt"
"os"
"text/tabwriter"
@ -91,7 +92,7 @@ func runListAuth(c *cli.Context) error {
func runDeleteAuth(c *cli.Context) error {
if !c.IsSet("id") {
return fmt.Errorf("--id flag is missing")
return errors.New("--id flag is missing")
}
ctx, cancel := installSignals()

View File

@ -386,7 +386,7 @@ func (a *authService) addLdapSimpleAuth(c *cli.Context) error {
return a.createAuthSource(ctx, authSource)
}
// updateLdapBindDn updates a new LDAP (simple auth) authentication source.
// updateLdapSimpleAuth updates a new LDAP (simple auth) authentication source.
func (a *authService) updateLdapSimpleAuth(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()

View File

@ -4,6 +4,7 @@
package cmd
import (
"errors"
"fmt"
"net/url"
@ -193,7 +194,7 @@ func runAddOauth(c *cli.Context) error {
func runUpdateOauth(c *cli.Context) error {
if !c.IsSet("id") {
return fmt.Errorf("--id flag is missing")
return errors.New("--id flag is missing")
}
ctx, cancel := installSignals()

View File

@ -5,7 +5,6 @@ package cmd
import (
"errors"
"fmt"
"strings"
auth_model "code.gitea.io/gitea/models/auth"
@ -166,7 +165,7 @@ func runAddSMTP(c *cli.Context) error {
func runUpdateSMTP(c *cli.Context) error {
if !c.IsSet("id") {
return fmt.Errorf("--id flag is missing")
return errors.New("--id flag is missing")
}
ctx, cancel := installSignals()

View File

@ -35,7 +35,8 @@ var microcmdUserChangePassword = &cli.Command{
},
&cli.BoolFlag{
Name: "must-change-password",
Usage: "User must change password",
Usage: "User must change password (can be disabled by --must-change-password=false)",
Value: true,
},
},
}
@ -57,23 +58,18 @@ func runChangePassword(c *cli.Context) error {
return err
}
var mustChangePassword optional.Option[bool]
if c.IsSet("must-change-password") {
mustChangePassword = optional.Some(c.Bool("must-change-password"))
}
opts := &user_service.UpdateAuthOptions{
Password: optional.Some(c.String("password")),
MustChangePassword: mustChangePassword,
MustChangePassword: optional.Some(c.Bool("must-change-password")),
}
if err := user_service.UpdateAuth(ctx, user, opts); err != nil {
switch {
case errors.Is(err, password.ErrMinLength):
return fmt.Errorf("Password is not long enough. Needs to be at least %d", setting.MinPasswordLength)
return fmt.Errorf("password is not long enough, needs to be at least %d characters", setting.MinPasswordLength)
case errors.Is(err, password.ErrComplexity):
return errors.New("Password does not meet complexity requirements")
return errors.New("password does not meet complexity requirements")
case errors.Is(err, password.ErrIsPwned):
return errors.New("The password you chose is on a list of stolen passwords previously exposed in public data breaches. Please try again with a different password.\nFor more details, see https://haveibeenpwned.com/Passwords")
return errors.New("the password is in a list of stolen passwords previously exposed in public data breaches, please try again with a different password, to see more details: https://haveibeenpwned.com/Passwords")
default:
return err
}

View File

@ -4,10 +4,12 @@
package cmd
import (
"context"
"errors"
"fmt"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
pwd "code.gitea.io/gitea/modules/auth/password"
"code.gitea.io/gitea/modules/optional"
@ -46,8 +48,9 @@ var microcmdUserCreate = &cli.Command{
Usage: "Generate a random password for the user",
},
&cli.BoolFlag{
Name: "must-change-password",
Usage: "Set this option to false to prevent forcing the user to change their password after initial login, (Default: true)",
Name: "must-change-password",
Usage: "User must change password after initial login, defaults to true for all users except the first one (can be disabled by --must-change-password=false)",
DisableDefaultText: true,
},
&cli.IntFlag{
Name: "random-password-length",
@ -71,10 +74,10 @@ func runCreateUser(c *cli.Context) error {
}
if c.IsSet("name") && c.IsSet("username") {
return errors.New("Cannot set both --name and --username flags")
return errors.New("cannot set both --name and --username flags")
}
if !c.IsSet("name") && !c.IsSet("username") {
return errors.New("One of --name or --username flags must be set")
return errors.New("one of --name or --username flags must be set")
}
if c.IsSet("password") && c.IsSet("random-password") {
@ -89,11 +92,16 @@ func runCreateUser(c *cli.Context) error {
_, _ = fmt.Fprintf(c.App.ErrWriter, "--name flag is deprecated. Use --username instead.\n")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
ctx := c.Context
if !setting.IsInTesting {
// FIXME: need to refactor the "installSignals/initDB" related code later
// it doesn't make sense to call it in (almost) every command action function
var cancel context.CancelFunc
ctx, cancel = installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
}
var password string
@ -110,17 +118,21 @@ func runCreateUser(c *cli.Context) error {
return errors.New("must set either password or random-password flag")
}
// always default to true
changePassword := true
// If this is the first user being created.
// Take it as the admin and don't force a password update.
if n := user_model.CountUsers(ctx, nil); n == 0 {
changePassword = false
}
isAdmin := c.Bool("admin")
mustChangePassword := true // always default to true
if c.IsSet("must-change-password") {
changePassword = c.Bool("must-change-password")
// if the flag is set, use the value provided by the user
mustChangePassword = c.Bool("must-change-password")
} else {
// check whether there are users in the database
hasUserRecord, err := db.IsTableNotEmpty(&user_model.User{})
if err != nil {
return fmt.Errorf("IsTableNotEmpty: %w", err)
}
if !hasUserRecord {
// if this is the first one being created, don't force to change password (keep the old behavior)
mustChangePassword = false
}
}
restricted := optional.None[bool]()
@ -136,8 +148,8 @@ func runCreateUser(c *cli.Context) error {
Name: username,
Email: c.String("email"),
Passwd: password,
IsAdmin: c.Bool("admin"),
MustChangePassword: changePassword,
IsAdmin: isAdmin,
MustChangePassword: mustChangePassword,
Visibility: visibility,
}
@ -146,7 +158,7 @@ func runCreateUser(c *cli.Context) error {
IsRestricted: restricted,
}
if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil {
if err := user_model.CreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil {
return fmt.Errorf("CreateUser: %w", err)
}

View File

@ -0,0 +1,44 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"strings"
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
func TestAdminUserCreate(t *testing.T) {
app := NewMainApp(AppVersion{})
reset := func() {
assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{}))
}
type createCheck struct{ IsAdmin, MustChangePassword bool }
createUser := func(name, args string) createCheck {
assert.NoError(t, app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %s@gitea.local %s --password foobar", name, name, args))))
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: name})
return createCheck{u.IsAdmin, u.MustChangePassword}
}
reset()
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u", ""), "first non-admin user doesn't need to change password")
reset()
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u", "--admin"), "first admin user doesn't need to change password")
reset()
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u", "--admin --must-change-password"))
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u2", "--admin"))
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u3", "--admin --must-change-password=false"))
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: true}, createUser("u4", ""))
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u5", "--must-change-password=false"))
}

View File

@ -4,6 +4,7 @@
package cmd
import (
"errors"
"fmt"
"strings"
@ -42,7 +43,7 @@ var microcmdUserDelete = &cli.Command{
func runDeleteUser(c *cli.Context) error {
if !c.IsSet("id") && !c.IsSet("username") && !c.IsSet("email") {
return fmt.Errorf("You must provide the id, username or email of a user to delete")
return errors.New("You must provide the id, username or email of a user to delete")
}
ctx, cancel := installSignals()

View File

@ -4,6 +4,7 @@
package cmd
import (
"errors"
"fmt"
auth_model "code.gitea.io/gitea/models/auth"
@ -42,7 +43,7 @@ var microcmdUserGenerateAccessToken = &cli.Command{
func runGenerateAccessToken(c *cli.Context) error {
if !c.IsSet("username") {
return fmt.Errorf("You must provide a username to generate a token for")
return errors.New("You must provide a username to generate a token for")
}
ctx, cancel := installSignals()
@ -68,7 +69,7 @@ func runGenerateAccessToken(c *cli.Context) error {
return err
}
if exist {
return fmt.Errorf("access token name has been used already")
return errors.New("access token name has been used already")
}
// make sure the scopes are valid

View File

@ -6,14 +6,13 @@ package cmd
import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/dump"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@ -25,89 +24,17 @@ import (
"github.com/urfave/cli/v2"
)
func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error {
if verbose {
log.Info("Adding file %s", customName)
}
return w.Write(archiver.File{
FileInfo: archiver.FileInfo{
FileInfo: info,
CustomName: customName,
},
ReadCloser: r,
})
}
func addFile(w archiver.Writer, filePath, absPath string, verbose bool) error {
file, err := os.Open(absPath)
if err != nil {
return err
}
defer file.Close()
fileInfo, err := file.Stat()
if err != nil {
return err
}
return addReader(w, file, fileInfo, filePath, verbose)
}
func isSubdir(upper, lower string) (bool, error) {
if relPath, err := filepath.Rel(upper, lower); err != nil {
return false, err
} else if relPath == "." || !strings.HasPrefix(relPath, ".") {
return true, nil
}
return false, nil
}
type outputType struct {
Enum []string
Default string
selected string
}
func (o outputType) Join() string {
return strings.Join(o.Enum, ", ")
}
func (o *outputType) Set(value string) error {
for _, enum := range o.Enum {
if enum == value {
o.selected = value
return nil
}
}
return fmt.Errorf("allowed values are %s", o.Join())
}
func (o outputType) String() string {
if o.selected == "" {
return o.Default
}
return o.selected
}
var outputTypeEnum = &outputType{
Enum: []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4", "tar.zst"},
Default: "zip",
}
// CmdDump represents the available dump sub-command.
var CmdDump = &cli.Command{
Name: "dump",
Usage: "Dump Gitea files and database",
Description: `Dump compresses all related files and database into zip file.
It can be used for backup and capture Gitea server image to send to maintainer`,
Action: runDump,
Name: "dump",
Usage: "Dump Gitea files and database",
Description: `Dump compresses all related files and database into zip file. It can be used for backup and capture Gitea server image to send to maintainer`,
Action: runDump,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "file",
Aliases: []string{"f"},
Value: fmt.Sprintf("gitea-dump-%d.zip", time.Now().Unix()),
Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.",
Usage: `Name of the dump file which will be created, default to "gitea-dump-{time}.zip". Supply '-' for stdout. See type for available types.`,
},
&cli.BoolFlag{
Name: "verbose",
@ -160,64 +87,56 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
Name: "skip-index",
Usage: "Skip bleve index data",
},
&cli.GenericFlag{
&cli.BoolFlag{
Name: "skip-db",
Usage: "Skip database",
},
&cli.StringFlag{
Name: "type",
Value: outputTypeEnum,
Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()),
Usage: fmt.Sprintf(`Dump output format, default to "zip", supported types: %s`, strings.Join(dump.SupportedOutputTypes, ", ")),
},
},
}
func fatal(format string, args ...any) {
fmt.Fprintf(os.Stderr, format+"\n", args...)
log.Fatal(format, args...)
}
func runDump(ctx *cli.Context) error {
var file *os.File
fileName := ctx.String("file")
outType := ctx.String("type")
if fileName == "-" {
file = os.Stdout
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
} else {
for _, suffix := range outputTypeEnum.Enum {
if strings.HasSuffix(fileName, "."+suffix) {
fileName = strings.TrimSuffix(fileName, "."+suffix)
break
}
}
fileName += "." + outType
}
setting.MustInstalled()
// make sure we are logging to the console no matter what the configuration tells us do to
// FIXME: don't use CfgProvider directly
if _, err := setting.CfgProvider.Section("log").NewKey("MODE", "console"); err != nil {
fatal("Setting logging mode to console failed: %v", err)
}
if _, err := setting.CfgProvider.Section("log.console").NewKey("STDERR", "true"); err != nil {
fatal("Setting console logger to stderr failed: %v", err)
}
// Set loglevel to Warn if quiet-mode is requested
if ctx.Bool("quiet") {
if _, err := setting.CfgProvider.Section("log.console").NewKey("LEVEL", "Warn"); err != nil {
fatal("Setting console log-level failed: %v", err)
}
}
if !setting.InstallLock {
log.Error("Is '%s' really the right config path?\n", setting.CustomConf)
return fmt.Errorf("gitea is not initialized")
}
setting.LoadSettings() // cannot access session settings otherwise
quite := ctx.Bool("quiet")
verbose := ctx.Bool("verbose")
if verbose && ctx.Bool("quiet") {
return fmt.Errorf("--quiet and --verbose cannot both be set")
if verbose && quite {
fatal("Option --quiet and --verbose cannot both be set")
}
// outFileName is either "-" or a file name (will be made absolute)
outFileName, outType := dump.PrepareFileNameAndType(ctx.String("file"), ctx.String("type"))
if outType == "" {
fatal("Invalid output type")
}
outFile := os.Stdout
if outFileName != "-" {
var err error
if outFileName, err = filepath.Abs(outFileName); err != nil {
fatal("Unable to get absolute path of dump file: %v", err)
}
if exist, _ := util.IsExist(outFileName); exist {
fatal("Dump file %q exists", outFileName)
}
if outFile, err = os.Create(outFileName); err != nil {
fatal("Unable to create dump file %q: %v", outFileName, err)
}
defer outFile.Close()
}
setupConsoleLogger(util.Iif(quite, log.WARN, log.INFO), log.CanColorStderr, os.Stderr)
setting.DisableLoggerInit()
setting.LoadSettings() // cannot access session settings otherwise
stdCtx, cancel := installSignals()
defer cancel()
@ -226,44 +145,32 @@ func runDump(ctx *cli.Context) error {
return err
}
if err := storage.Init(); err != nil {
if err = storage.Init(); err != nil {
return err
}
if file == nil {
file, err = os.Create(fileName)
if err != nil {
fatal("Unable to open %s: %v", fileName, err)
}
}
defer file.Close()
absFileName, err := filepath.Abs(fileName)
if err != nil {
return err
}
var iface any
if fileName == "-" {
iface, err = archiver.ByExtension(fmt.Sprintf(".%s", outType))
} else {
iface, err = archiver.ByExtension(fileName)
}
archiverGeneric, err := archiver.ByExtension("." + outType)
if err != nil {
fatal("Unable to get archiver for extension: %v", err)
}
w, _ := iface.(archiver.Writer)
if err := w.Create(file); err != nil {
archiverWriter := archiverGeneric.(archiver.Writer)
if err := archiverWriter.Create(outFile); err != nil {
fatal("Creating archiver.Writer failed: %v", err)
}
defer w.Close()
defer archiverWriter.Close()
dumper := &dump.Dumper{
Writer: archiverWriter,
Verbose: verbose,
}
dumper.GlobalExcludeAbsPath(outFileName)
if ctx.IsSet("skip-repository") && ctx.Bool("skip-repository") {
log.Info("Skip dumping local repositories")
} else {
log.Info("Dumping local repositories... %s", setting.RepoRootPath)
if err := addRecursiveExclude(w, "repos", setting.RepoRootPath, []string{absFileName}, verbose); err != nil {
if err := dumper.AddRecursiveExclude("repos", setting.RepoRootPath, nil); err != nil {
fatal("Failed to include repositories: %v", err)
}
@ -276,49 +183,52 @@ func runDump(ctx *cli.Context) error {
if err != nil {
return err
}
return addReader(w, object, info, path.Join("data", "lfs", objPath), verbose)
return dumper.AddReader(object, info, path.Join("data", "lfs", objPath))
}); err != nil {
fatal("Failed to dump LFS objects: %v", err)
}
}
tmpDir := ctx.String("tempdir")
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
fatal("Path does not exist: %s", tmpDir)
}
dbDump, err := os.CreateTemp(tmpDir, "gitea-db.sql")
if err != nil {
fatal("Failed to create tmp file: %v", err)
}
defer func() {
_ = dbDump.Close()
if err := util.Remove(dbDump.Name()); err != nil {
log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err)
}
}()
targetDBType := ctx.String("database")
if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() {
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
if ctx.Bool("skip-db") {
// Ensure that we don't dump the database file that may reside in setting.AppDataPath or elsewhere.
dumper.GlobalExcludeAbsPath(setting.Database.Path)
log.Info("Skipping database")
} else {
log.Info("Dumping database...")
}
if err := db.DumpDatabase(dbDump.Name(), targetDBType); err != nil {
fatal("Failed to dump database: %v", err)
}
if err := addFile(w, "gitea-db.sql", dbDump.Name(), verbose); err != nil {
fatal("Failed to include gitea-db.sql: %v", err)
}
if len(setting.CustomConf) > 0 {
log.Info("Adding custom configuration file from %s", setting.CustomConf)
if err := addFile(w, "app.ini", setting.CustomConf, verbose); err != nil {
fatal("Failed to include specified app.ini: %v", err)
tmpDir := ctx.String("tempdir")
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
fatal("Path does not exist: %s", tmpDir)
}
dbDump, err := os.CreateTemp(tmpDir, "gitea-db.sql")
if err != nil {
fatal("Failed to create tmp file: %v", err)
}
defer func() {
_ = dbDump.Close()
if err := util.Remove(dbDump.Name()); err != nil {
log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err)
}
}()
targetDBType := ctx.String("database")
if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() {
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
} else {
log.Info("Dumping database...")
}
if err := db.DumpDatabase(dbDump.Name(), targetDBType); err != nil {
fatal("Failed to dump database: %v", err)
}
if err = dumper.AddFile("gitea-db.sql", dbDump.Name()); err != nil {
fatal("Failed to include gitea-db.sql: %v", err)
}
}
log.Info("Adding custom configuration file from %s", setting.CustomConf)
if err = dumper.AddFile("app.ini", setting.CustomConf); err != nil {
fatal("Failed to include specified app.ini: %v", err)
}
if ctx.IsSet("skip-custom-dir") && ctx.Bool("skip-custom-dir") {
@ -326,8 +236,8 @@ func runDump(ctx *cli.Context) error {
} else {
customDir, err := os.Stat(setting.CustomPath)
if err == nil && customDir.IsDir() {
if is, _ := isSubdir(setting.AppDataPath, setting.CustomPath); !is {
if err := addRecursiveExclude(w, "custom", setting.CustomPath, []string{absFileName}, verbose); err != nil {
if is, _ := dump.IsSubdir(setting.AppDataPath, setting.CustomPath); !is {
if err := dumper.AddRecursiveExclude("custom", setting.CustomPath, nil); err != nil {
fatal("Failed to include custom: %v", err)
}
} else {
@ -364,8 +274,7 @@ func runDump(ctx *cli.Context) error {
excludes = append(excludes, setting.Attachment.Storage.Path)
excludes = append(excludes, setting.Packages.Storage.Path)
excludes = append(excludes, setting.Log.RootPath)
excludes = append(excludes, absFileName)
if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil {
if err := dumper.AddRecursiveExclude("data", setting.AppDataPath, excludes); err != nil {
fatal("Failed to include data directory: %v", err)
}
}
@ -377,8 +286,7 @@ func runDump(ctx *cli.Context) error {
if err != nil {
return err
}
return addReader(w, object, info, path.Join("data", "attachments", objPath), verbose)
return dumper.AddReader(object, info, path.Join("data", "attachments", objPath))
}); err != nil {
fatal("Failed to dump attachments: %v", err)
}
@ -392,8 +300,7 @@ func runDump(ctx *cli.Context) error {
if err != nil {
return err
}
return addReader(w, object, info, path.Join("data", "packages", objPath), verbose)
return dumper.AddReader(object, info, path.Join("data", "packages", objPath))
}); err != nil {
fatal("Failed to dump packages: %v", err)
}
@ -409,80 +316,23 @@ func runDump(ctx *cli.Context) error {
log.Error("Unable to check if %s exists. Error: %v", setting.Log.RootPath, err)
}
if isExist {
if err := addRecursiveExclude(w, "log", setting.Log.RootPath, []string{absFileName}, verbose); err != nil {
if err := dumper.AddRecursiveExclude("log", setting.Log.RootPath, nil); err != nil {
fatal("Failed to include log: %v", err)
}
}
}
if fileName != "-" {
if err = w.Close(); err != nil {
_ = util.Remove(fileName)
fatal("Failed to save %s: %v", fileName, err)
if outFileName == "-" {
log.Info("Finish dumping to stdout")
} else {
if err = archiverWriter.Close(); err != nil {
_ = os.Remove(outFileName)
fatal("Failed to save %q: %v", outFileName, err)
}
if err := os.Chmod(fileName, 0o600); err != nil {
if err = os.Chmod(outFileName, 0o600); err != nil {
log.Info("Can't change file access permissions mask to 0600: %v", err)
}
}
if fileName != "-" {
log.Info("Finish dumping in file %s", fileName)
} else {
log.Info("Finish dumping to stdout")
}
return nil
}
// addRecursiveExclude zips absPath to specified insidePath inside writer excluding excludeAbsPath
func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeAbsPath []string, verbose bool) error {
absPath, err := filepath.Abs(absPath)
if err != nil {
return err
}
dir, err := os.Open(absPath)
if err != nil {
return err
}
defer dir.Close()
files, err := dir.Readdir(0)
if err != nil {
return err
}
for _, file := range files {
currentAbsPath := filepath.Join(absPath, file.Name())
currentInsidePath := path.Join(insidePath, file.Name())
if file.IsDir() {
if !util.SliceContainsString(excludeAbsPath, currentAbsPath) {
if err := addFile(w, currentInsidePath, currentAbsPath, false); err != nil {
return err
}
if err = addRecursiveExclude(w, currentInsidePath, currentAbsPath, excludeAbsPath, verbose); err != nil {
return err
}
}
} else {
// only copy regular files and symlink regular files, skip non-regular files like socket/pipe/...
shouldAdd := file.Mode().IsRegular()
if !shouldAdd && file.Mode()&os.ModeSymlink == os.ModeSymlink {
target, err := filepath.EvalSymlinks(currentAbsPath)
if err != nil {
return err
}
targetStat, err := os.Stat(target)
if err != nil {
return err
}
shouldAdd = targetStat.Mode().IsRegular()
}
if shouldAdd {
if err = addFile(w, currentInsidePath, currentAbsPath, verbose); err != nil {
return err
}
}
}
log.Info("Finish dumping in file %s", outFileName)
}
return nil
}

View File

@ -157,9 +157,9 @@ func runViewDo(c *cli.Context) error {
}
if len(matchedAssetFiles) == 0 {
return fmt.Errorf("no files matched the given pattern")
return errors.New("no files matched the given pattern")
} else if len(matchedAssetFiles) > 1 {
return fmt.Errorf("too many files matched the given pattern, try to be more specific")
return errors.New("too many files matched the given pattern, try to be more specific")
}
data, err := matchedAssetFiles[0].fs.ReadFile(matchedAssetFiles[0].name)
@ -180,7 +180,7 @@ func runExtractDo(c *cli.Context) error {
}
if c.NArg() == 0 {
return fmt.Errorf("a list of pattern of files to extract is mandatory (e.g. '**' for all)")
return errors.New("a list of pattern of files to extract is mandatory (e.g. '**' for all)")
}
destdir := "."

View File

@ -220,10 +220,7 @@ Gitea or set your environment appropriately.`, "")
}
}
supportProcReceive := false
if git.CheckGitVersionAtLeast("2.29") == nil {
supportProcReceive = true
}
supportProcReceive := git.DefaultFeatures().SupportProcReceive
for scanner.Scan() {
// TODO: support news feeds for wiki
@ -293,8 +290,22 @@ Gitea or set your environment appropriately.`, "")
return nil
}
// runHookUpdate avoid to do heavy operations on update hook because it will be
// invoked for every ref update which does not like pre-receive and post-receive
func runHookUpdate(c *cli.Context) error {
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
return nil
}
// Update is empty and is kept only for backwards compatibility
if len(os.Args) < 3 {
return nil
}
refName := git.RefName(os.Args[len(os.Args)-3])
if refName.IsPull() {
// ignore update to refs/pull/xxx/head, so we don't need to output any information
os.Exit(1)
}
return nil
}
@ -341,6 +352,7 @@ Gitea or set your environment appropriately.`, "")
isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki))
repoName := os.Getenv(repo_module.EnvRepoName)
pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64)
pusherName := os.Getenv(repo_module.EnvPusherName)
hookOptions := private.HookOptions{
@ -350,6 +362,8 @@ Gitea or set your environment appropriately.`, "")
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
GitPushOptions: pushOptions(),
PullRequestID: prID,
PushTrigger: repo_module.PushTrigger(os.Getenv(repo_module.EnvPushTrigger)),
}
oldCommitIDs := make([]string, hookBatchSize)
newCommitIDs := make([]string, hookBatchSize)
@ -448,23 +462,26 @@ Gitea or set your environment appropriately.`, "")
func hookPrintResults(results []private.HookPostReceiveBranchResult) {
for _, res := range results {
if !res.Message {
continue
}
fmt.Fprintln(os.Stderr, "")
if res.Create {
fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", res.Branch)
fmt.Fprintf(os.Stderr, " %s\n", res.URL)
} else {
fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
fmt.Fprintf(os.Stderr, " %s\n", res.URL)
}
fmt.Fprintln(os.Stderr, "")
os.Stderr.Sync()
hookPrintResult(res.Message, res.Create, res.Branch, res.URL)
}
}
func hookPrintResult(output, isCreate bool, branch, url string) {
if !output {
return
}
fmt.Fprintln(os.Stderr, "")
if isCreate {
fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch)
fmt.Fprintf(os.Stderr, " %s\n", url)
} else {
fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
fmt.Fprintf(os.Stderr, " %s\n", url)
}
fmt.Fprintln(os.Stderr, "")
_ = os.Stderr.Sync()
}
func pushOptions() map[string]string {
opts := make(map[string]string)
if pushCount, err := strconv.Atoi(os.Getenv(private.GitPushOptionCount)); err == nil {
@ -494,7 +511,7 @@ Gitea or set your environment appropriately.`, "")
return nil
}
if git.CheckGitVersionAtLeast("2.29") != nil {
if !git.DefaultFeatures().SupportProcReceive {
return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.")
}
@ -525,14 +542,14 @@ Gitea or set your environment appropriately.`, "")
index := bytes.IndexByte(rs.Data, byte(0))
if index >= len(rs.Data) {
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
return fail(ctx, "Protocol: format error", "pkt-line: format error %s", rs.Data)
}
if index < 0 {
if len(rs.Data) == 10 && rs.Data[9] == '\n' {
index = 9
} else {
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
return fail(ctx, "Protocol: format error", "pkt-line: format error %s", rs.Data)
}
}
@ -574,8 +591,9 @@ Gitea or set your environment appropriately.`, "")
// S: ... ...
// S: flush-pkt
hookOptions := private.HookOptions{
UserName: pusherName,
UserID: pusherID,
UserName: pusherName,
UserID: pusherID,
GitPushOptions: make(map[string]string),
}
hookOptions.OldCommitIDs = make([]string, 0, hookBatchSize)
hookOptions.NewCommitIDs = make([]string, 0, hookBatchSize)
@ -600,8 +618,6 @@ Gitea or set your environment appropriately.`, "")
hookOptions.RefFullNames = append(hookOptions.RefFullNames, git.RefName(t[2]))
}
hookOptions.GitPushOptions = make(map[string]string)
if hasPushOptions {
for {
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
@ -612,11 +628,7 @@ Gitea or set your environment appropriately.`, "")
if rs.Type == pktLineTypeFlush {
break
}
kv := strings.SplitN(string(rs.Data), "=", 2)
if len(kv) == 2 {
hookOptions.GitPushOptions[kv[0]] = kv[1]
}
hookOptions.GitPushOptions.AddFromKeyValue(string(rs.Data))
}
}
@ -691,6 +703,12 @@ Gitea or set your environment appropriately.`, "")
}
err = writeFlushPktLine(ctx, os.Stdout)
if err == nil {
for _, res := range resp.Results {
hookPrintResult(res.ShouldShowMessage, res.IsCreatePR, res.HeadBranch, res.URL)
}
}
return err
}

View File

@ -112,13 +112,18 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context)
}
}
func NewMainApp(version, versionExtra string) *cli.App {
type AppVersion struct {
Version string
Extra string
}
func NewMainApp(appVer AppVersion) *cli.App {
app := cli.NewApp()
app.Name = "Gitea"
app.HelpName = "gitea"
app.Usage = "A painless self-hosted Git service"
app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.`
app.Version = version + versionExtra
app.Version = appVer.Version + appVer.Extra
app.EnableBashCompletion = true
// these sub-commands need to use config file

View File

@ -28,7 +28,7 @@ func makePathOutput(workPath, customPath, customConf string) string {
}
func newTestApp(testCmdAction func(ctx *cli.Context) error) *cli.App {
app := NewMainApp("version", "version-extra")
app := NewMainApp(AppVersion{})
testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
prepareSubcommandWithConfig(testCmd, appGlobalFlags())
app.Commands = append(app.Commands, testCmd)

View File

@ -4,6 +4,7 @@
package cmd
import (
"errors"
"fmt"
"os"
@ -249,7 +250,7 @@ func runAddFileLogger(c *cli.Context) error {
if c.IsSet("filename") {
vals["filename"] = c.String("filename")
} else {
return fmt.Errorf("filename must be set when creating a file logger")
return errors.New("filename must be set when creating a file logger")
}
if c.IsSet("rotate") {
vals["rotate"] = c.Bool("rotate")

View File

@ -5,7 +5,9 @@ package cmd
import (
"context"
"errors"
"fmt"
"io/fs"
"strings"
actions_model "code.gitea.io/gitea/models/actions"
@ -34,13 +36,13 @@ var CmdMigrateStorage = &cli.Command{
Name: "type",
Aliases: []string{"t"},
Value: "",
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log'",
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts",
},
&cli.StringFlag{
Name: "storage",
Aliases: []string{"s"},
Value: "",
Usage: "New storage type: local (default) or minio",
Usage: "New storage type: local (default), minio or azureblob",
},
&cli.StringFlag{
Name: "path",
@ -48,6 +50,7 @@ var CmdMigrateStorage = &cli.Command{
Value: "",
Usage: "New storage placement if store is local (leave blank for default)",
},
// Minio Storage special configurations
&cli.StringFlag{
Name: "minio-endpoint",
Value: "",
@ -91,6 +94,37 @@ var CmdMigrateStorage = &cli.Command{
Value: "",
Usage: "Minio checksum algorithm (default/md5)",
},
&cli.StringFlag{
Name: "minio-bucket-lookup-type",
Value: "",
Usage: "Minio bucket lookup type",
},
// Azure Blob Storage special configurations
&cli.StringFlag{
Name: "azureblob-endpoint",
Value: "",
Usage: "Azure Blob storage endpoint",
},
&cli.StringFlag{
Name: "azureblob-account-name",
Value: "",
Usage: "Azure Blob storage account name",
},
&cli.StringFlag{
Name: "azureblob-account-key",
Value: "",
Usage: "Azure Blob storage account key",
},
&cli.StringFlag{
Name: "azureblob-container",
Value: "",
Usage: "Azure Blob storage container",
},
&cli.StringFlag{
Name: "azureblob-base-path",
Value: "",
Usage: "Azure Blob storage base path",
},
},
}
@ -160,6 +194,25 @@ func migrateActionsLog(ctx context.Context, dstStorage storage.ObjectStorage) er
})
}
func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.Iterate(ctx, nil, func(ctx context.Context, artifact *actions_model.ActionArtifact) error {
if artifact.Status == int64(actions_model.ArtifactStatusExpired) {
return nil
}
_, err := storage.Copy(dstStorage, artifact.StoragePath, storage.ActionsArtifacts, artifact.StoragePath)
if err != nil {
// ignore files that do not exist
if errors.Is(err, fs.ErrNotExist) {
return nil
}
return err
}
return nil
})
}
func runMigrateStorage(ctx *cli.Context) error {
stdCtx, cancel := installSignals()
defer cancel()
@ -213,6 +266,19 @@ func runMigrateStorage(ctx *cli.Context) error {
UseSSL: ctx.Bool("minio-use-ssl"),
InsecureSkipVerify: ctx.Bool("minio-insecure-skip-verify"),
ChecksumAlgorithm: ctx.String("minio-checksum-algorithm"),
BucketLookUpType: ctx.String("minio-bucket-lookup-type"),
},
})
case string(setting.AzureBlobStorageType):
dstStorage, err = storage.NewAzureBlobStorage(
stdCtx,
&setting.Storage{
AzureBlobConfig: setting.AzureBlobStorageConfig{
Endpoint: ctx.String("azureblob-endpoint"),
AccountName: ctx.String("azureblob-account-name"),
AccountKey: ctx.String("azureblob-account-key"),
Container: ctx.String("azureblob-container"),
BasePath: ctx.String("azureblob-base-path"),
},
})
default:
@ -223,13 +289,14 @@ func runMigrateStorage(ctx *cli.Context) error {
}
migratedMethods := map[string]func(context.Context, storage.ObjectStorage) error{
"attachments": migrateAttachments,
"lfs": migrateLFS,
"avatars": migrateAvatars,
"repo-avatars": migrateRepoAvatars,
"repo-archivers": migrateRepoArchivers,
"packages": migratePackages,
"actions-log": migrateActionsLog,
"attachments": migrateAttachments,
"lfs": migrateLFS,
"avatars": migrateAvatars,
"repo-avatars": migrateRepoAvatars,
"repo-archivers": migrateRepoArchivers,
"packages": migratePackages,
"actions-log": migrateActionsLog,
"actions-artifacts": migrateActionsArtifacts,
}
tp := strings.ToLower(ctx.String("type"))

View File

@ -20,8 +20,10 @@ import (
asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfstransfer"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/pprof"
"code.gitea.io/gitea/modules/private"
@ -36,7 +38,11 @@ import (
)
const (
lfsAuthenticateVerb = "git-lfs-authenticate"
verbUploadPack = "git-upload-pack"
verbUploadArchive = "git-upload-archive"
verbReceivePack = "git-receive-pack"
verbLfsAuthenticate = "git-lfs-authenticate"
verbLfsTransfer = "git-lfs-transfer"
)
// CmdServ represents the available serv sub-command.
@ -73,12 +79,18 @@ func setup(ctx context.Context, debug bool) {
}
var (
allowedCommands = map[string]perm.AccessMode{
"git-upload-pack": perm.AccessModeRead,
"git-upload-archive": perm.AccessModeRead,
"git-receive-pack": perm.AccessModeWrite,
lfsAuthenticateVerb: perm.AccessModeNone,
}
// keep getAccessMode() in sync
allowedCommands = container.SetOf(
verbUploadPack,
verbUploadArchive,
verbReceivePack,
verbLfsAuthenticate,
verbLfsTransfer,
)
allowedCommandsLfs = container.SetOf(
verbLfsAuthenticate,
verbLfsTransfer,
)
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)
@ -99,12 +111,10 @@ func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error
if !setting.IsProd {
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", logMsg)
}
if userMessage != "" {
if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
logMsg = userMessage + " " + logMsg
} else {
logMsg = userMessage + ". " + logMsg
}
if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
logMsg = userMessage + " " + logMsg
} else {
logMsg = userMessage + ". " + logMsg
}
_ = private.SSHLog(ctx, true, logMsg)
}
@ -124,6 +134,45 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
return nil
}
func getAccessMode(verb, lfsVerb string) perm.AccessMode {
switch verb {
case verbUploadPack, verbUploadArchive:
return perm.AccessModeRead
case verbReceivePack:
return perm.AccessModeWrite
case verbLfsAuthenticate, verbLfsTransfer:
switch lfsVerb {
case "upload":
return perm.AccessModeWrite
case "download":
return perm.AccessModeRead
}
}
// should be unreachable
return perm.AccessModeNone
}
func getLFSAuthToken(ctx context.Context, lfsVerb string, results *private.ServCommandResults) (string, error) {
now := time.Now()
claims := lfs.Claims{
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(now.Add(setting.LFS.HTTPAuthExpiry)),
NotBefore: jwt.NewNumericDate(now),
},
RepoID: results.RepoID,
Op: lfsVerb,
UserID: results.UserID,
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Sign and get the complete encoded token as a string using the secret
tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
if err != nil {
return "", fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
}
return fmt.Sprintf("Bearer %s", tokenString), nil
}
func runServ(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
@ -143,6 +192,12 @@ func runServ(c *cli.Context) error {
return nil
}
defer func() {
if err := recover(); err != nil {
_ = fail(ctx, "Internal Server Error", "Panic: %v\n%s", err, log.Stack(2))
}
}()
keys := strings.Split(c.Args().First(), "-")
if len(keys) != 2 || keys[0] != "key" {
return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args().First())
@ -178,7 +233,7 @@ func runServ(c *cli.Context) error {
}
if len(words) < 2 {
if git.CheckGitVersionAtLeast("2.29") == nil {
if git.DefaultFeatures().SupportProcReceive {
// for AGit Flow
if cmd == "ssh_info" {
fmt.Print(`{"type":"gitea","version":1}`)
@ -189,21 +244,9 @@ func runServ(c *cli.Context) error {
}
verb := words[0]
repoPath := words[1]
if repoPath[0] == '/' {
repoPath = repoPath[1:]
}
repoPath := strings.TrimPrefix(words[1], "/")
var lfsVerb string
if verb == lfsAuthenticateVerb {
if !setting.LFS.StartServer {
return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
}
if len(words) > 2 {
lfsVerb = words[2]
}
}
rr := strings.SplitN(repoPath, "/", 2)
if len(rr) != 2 {
@ -240,53 +283,52 @@ func runServ(c *cli.Context) error {
}()
}
requestedMode, has := allowedCommands[verb]
if !has {
if allowedCommands.Contains(verb) {
if allowedCommandsLfs.Contains(verb) {
if !setting.LFS.StartServer {
return fail(ctx, "LFS Server is not enabled", "")
}
if verb == verbLfsTransfer && !setting.LFS.AllowPureSSH {
return fail(ctx, "LFS SSH transfer is not enabled", "")
}
if len(words) > 2 {
lfsVerb = words[2]
}
}
} else {
return fail(ctx, "Unknown git command", "Unknown git command %s", verb)
}
if verb == lfsAuthenticateVerb {
if lfsVerb == "upload" {
requestedMode = perm.AccessModeWrite
} else if lfsVerb == "download" {
requestedMode = perm.AccessModeRead
} else {
return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
}
}
requestedMode := getAccessMode(verb, lfsVerb)
results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error)
}
// LFS SSH protocol
if verb == verbLfsTransfer {
token, err := getLFSAuthToken(ctx, lfsVerb, results)
if err != nil {
return err
}
return lfstransfer.Main(ctx, repoPath, lfsVerb, token)
}
// LFS token authentication
if verb == lfsAuthenticateVerb {
if verb == verbLfsAuthenticate {
url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))
now := time.Now()
claims := lfs.Claims{
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(now.Add(setting.LFS.HTTPAuthExpiry)),
NotBefore: jwt.NewNumericDate(now),
},
RepoID: results.RepoID,
Op: lfsVerb,
UserID: results.UserID,
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Sign and get the complete encoded token as a string using the secret
tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
token, err := getLFSAuthToken(ctx, lfsVerb, results)
if err != nil {
return fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
return err
}
tokenAuthentication := &git_model.LFSTokenResponse{
Header: make(map[string]string),
Href: url,
}
tokenAuthentication.Header["Authorization"] = fmt.Sprintf("Bearer %s", tokenString)
tokenAuthentication.Header["Authorization"] = token
enc := json.NewEncoder(os.Stdout)
err = enc.Encode(tokenAuthentication)

View File

@ -114,7 +114,7 @@ func showWebStartupMessage(msg string) {
log.Info("* WorkPath: %s", setting.AppWorkPath)
log.Info("* CustomPath: %s", setting.CustomPath)
log.Info("* ConfigFile: %s", setting.CustomConf)
log.Info("%s", msg)
log.Info("%s", msg) // show startup message
}
func serveInstall(ctx *cli.Context) error {

View File

@ -17,7 +17,7 @@ import (
"strings"
"syscall"
"github.com/google/go-github/v57/github"
"github.com/google/go-github/v61/github"
"github.com/urfave/cli/v2"
"gopkg.in/yaml.v3"
)
@ -64,6 +64,11 @@ func main() {
Value: "",
Usage: "Forked user name on Github",
},
&cli.StringFlag{
Name: "gh-access-token",
Value: "",
Usage: "Access token for GitHub api request",
},
&cli.BoolFlag{
Name: "no-fetch",
Usage: "Set this flag to prevent fetch of remote branches",
@ -169,9 +174,10 @@ func runBackport(c *cli.Context) error {
fmt.Printf("* Backporting %s to %s as %s\n", pr, localReleaseBranch, backportBranch)
sha := c.String("cherry-pick")
accessToken := c.String("gh-access-token")
if sha == "" {
var err error
sha, err = determineSHAforPR(ctx, pr)
sha, err = determineSHAforPR(ctx, pr, accessToken)
if err != nil {
return err
}
@ -427,13 +433,16 @@ func readVersion() string {
return strings.Join(split[:2], ".")
}
func determineSHAforPR(ctx context.Context, prStr string) (string, error) {
func determineSHAforPR(ctx context.Context, prStr, accessToken string) (string, error) {
prNum, err := strconv.Atoi(prStr)
if err != nil {
return "", err
}
client := github.NewClient(http.DefaultClient)
if accessToken != "" {
client = client.WithAuthToken(accessToken)
}
pr, _, err := client.PullRequests.Get(ctx, "go-gitea", "gitea", prNum)
if err != nil {

View File

@ -1,80 +0,0 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//nolint:forbidigo
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/unittest"
)
// To generate derivative fixtures, execute the following from Gitea's repository base dir:
// go run -tags 'sqlite sqlite_unlock_notify' contrib/fixtures/fixture_generation.go [fixture...]
var (
generators = []struct {
gen func(ctx context.Context) (string, error)
name string
}{
{
models.GetYamlFixturesAccess, "access",
},
}
fixturesDir string
)
func main() {
pathToGiteaRoot := "."
fixturesDir = filepath.Join(pathToGiteaRoot, "models", "fixtures")
if err := unittest.CreateTestEngine(unittest.FixturesOptions{
Dir: fixturesDir,
}); err != nil {
fmt.Printf("CreateTestEngine: %+v", err)
os.Exit(1)
}
if err := unittest.PrepareTestDatabase(); err != nil {
fmt.Printf("PrepareTestDatabase: %+v\n", err)
os.Exit(1)
}
ctx := context.Background()
if len(os.Args) == 0 {
for _, r := range os.Args {
if err := generate(ctx, r); err != nil {
fmt.Printf("generate '%s': %+v\n", r, err)
os.Exit(1)
}
}
} else {
for _, g := range generators {
if err := generate(ctx, g.name); err != nil {
fmt.Printf("generate '%s': %+v\n", g.name, err)
os.Exit(1)
}
}
}
}
func generate(ctx context.Context, name string) error {
for _, g := range generators {
if g.name == name {
data, err := g.gen(ctx)
if err != nil {
return err
}
path := filepath.Join(fixturesDir, name+".yml")
if err := os.WriteFile(path, []byte(data), 0o644); err != nil {
return fmt.Errorf("%s: %+v", path, err)
}
fmt.Printf("%s created.\n", path)
return nil
}
}
return fmt.Errorf("generator not found")
}

12
crowdin.yml Normal file
View File

@ -0,0 +1,12 @@
project_id_env: CROWDIN_PROJECT_ID
api_token_env: CROWDIN_KEY
base_path: "."
base_url: "https://api.crowdin.com"
preserve_hierarchy: true
files:
- source: "/options/locale/locale_en-US.ini"
translation: "/options/locale/locale_%locale%.ini"
type: "ini"
skip_untranslated_strings: true
export_only_approved: true
update_option: "update_as_unapproved"

View File

@ -81,6 +81,10 @@ RUN_USER = ; git
;; Overwrite the automatically generated public URL. Necessary for proxies and docker.
;ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
;;
;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy.
;; DO NOT USE IT IN PRODUCTION!!!
;USE_SUB_URL_PATH = false
;;
;; when STATIC_URL_PREFIX is empty it will follow ROOT_URL
;STATIC_URL_PREFIX =
;;
@ -302,6 +306,8 @@ RUN_USER = ; git
;; Enables git-lfs support. true or false, default is false.
;LFS_START_SERVER = false
;;
;; Enables git-lfs SSH protocol support. true or false, default is false.
;LFS_ALLOW_PURE_SSH = false
;;
;; LFS authentication secret, change this yourself
;LFS_JWT_SECRET =
@ -318,6 +324,10 @@ RUN_USER = ; git
;; Maximum number of locks returned per page
;LFS_LOCKS_PAGING_NUM = 50
;;
;; When clients make lfs batch requests, reject them if there are more pointers than this number
;; zero means 'unlimited'
;LFS_MAX_BATCH_SIZE = 0
;;
;; Allow graceful restarts using SIGHUP to fork
;ALLOW_GRACEFUL_RESTARTS = true
;;
@ -441,7 +451,7 @@ 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)
;LOGIN_REMEMBER_DAYS = 7
;LOGIN_REMEMBER_DAYS = 31
;;
;; Name of the cookie used to store the current username.
;COOKIE_USERNAME = gitea_awesome
@ -503,6 +513,9 @@ INTERNAL_TOKEN =
;; stemming from cached/logged plain-text API tokens.
;; In future releases, this will become the default behavior
;DISABLE_QUERY_AUTH_TOKEN = false
;;
;; On user registration, record the IP address and user agent of the user to help identify potential abuse.
;; RECORD_USER_SIGNUP_METADATA = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -519,7 +532,8 @@ INTERNAL_TOKEN =
;; HMAC to encode urls with, it **is required** if camo is enabled.
;HMAC_KEY =
;; Set to true to use camo for https too lese only non https urls are proxyed
;ALLWAYS = false
;; ALLWAYS is deprecated and will be removed in the future
;ALWAYS = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -770,6 +784,10 @@ LEVEL = Info
;; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token
;ENABLE_BASIC_AUTHENTICATION = true
;;
;; Show the password sign-in form (for password-based login), otherwise, only show OAuth2 login methods.
;; If you set it to false, maybe it also needs to set ENABLE_BASIC_AUTHENTICATION to false to completely disable password-based authentication.
;ENABLE_PASSWORD_SIGNIN_FORM = true
;;
;; More detail: https://github.com/gogits/gogs/issues/165
;ENABLE_REVERSE_PROXY_AUTHENTICATION = false
; Enable this to allow reverse proxy authentication for API requests, the reverse proxy is responsible for ensuring that no CSRF is possible.
@ -897,6 +915,24 @@ LEVEL = Info
;; Valid site url schemes for user profiles
;VALID_SITE_URL_SCHEMES=http,https
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[service.explore]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Only allow signed in users to view the explore pages.
;REQUIRE_SIGNIN_VIEW = false
;;
;; Disable the users explore page.
;DISABLE_USERS_PAGE = false
;;
;; Disable the organizations explore page.
;DISABLE_ORGANIZATIONS_PAGE = false
;;
;; Disable the code explore page.
;DISABLE_CODE_PAGE = false
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -975,6 +1011,14 @@ LEVEL = Info
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
;DEFAULT_FORK_REPO_UNITS = repo.code,repo.pulls
;;
;; Comma separated list of default mirror repo units.
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
;DEFAULT_MIRROR_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.wiki,repo.projects,repo.packages
;;
;; Comma separated list of default template repo units.
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
;DEFAULT_TEMPLATE_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages
;;
;; Prefix archive files by placing them in a directory named after the repository
;PREFIX_ARCHIVE_FILES = true
;;
@ -996,9 +1040,13 @@ LEVEL = Info
;; Don't allow download source archive files from UI
;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false
;; Allow fork repositories without maximum number limit
;; Allow to fork repositories without maximum number limit
;ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT = true
;; Allow to fork repositories into the same owner (user or organization)
;; This feature is experimental, not fully tested, and may be changed in the future
;ALLOW_FORK_INTO_SAME_OWNER = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository.editor]
@ -1231,7 +1279,8 @@ LEVEL = Info
;DEFAULT_THEME = gitea-auto
;;
;; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`.
;THEMES = gitea-auto,gitea-light,gitea-dark
;; Leave it empty to allow users to select any theme from "{CustomPath}/public/assets/css/theme-*.css"
;THEMES =
;;
;; All available reactions users can choose on issues/prs and comments.
;; Values can be emoji alias (:smile:) or a unicode emoji.
@ -1333,6 +1382,9 @@ LEVEL = Info
;;
;; Maximum allowed file size in bytes to render CSV files as table. (Set to 0 for no limit).
;MAX_FILE_SIZE = 524288
;;
;; Maximum allowed rows to render CSV files. (Set to 0 for no limit)
;MAX_ROWS = 2500
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1455,7 +1507,7 @@ LEVEL = Info
;; Batch size to send for batched queues
;BATCH_LENGTH = 20
;;
;; Connection string for redis queues this will store the redis or redis-cluster connection string.
;; Connection string for redis queues this will store the redis (or Redis cluster) connection string.
;; When `TYPE` is `persistable-channel`, this provides a directory for the underlying leveldb
;; or additional options of the form `leveldb://path/to/db?option=value&....`, and will override `DATADIR`.
;CONN_STR = "redis://127.0.0.1:6379/0"
@ -1480,11 +1532,22 @@ LEVEL = Info
;;
;; Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled
;DEFAULT_EMAIL_NOTIFICATIONS = enabled
;; Disabled features for users, could be "deletion", "manage_ssh_keys","manage_gpg_keys" more features can be disabled in future
;; Disabled features for users could be "deletion", "manage_ssh_keys", "manage_gpg_keys", "manage_mfa", "manage_credentials" more features can be disabled in future
;; - 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
;; - manage_mfa: a user cannot configure mfa devices
;; - manage_credentials: a user cannot configure emails, passwords, or openid
;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", "manage_mfa", "manage_credentials". 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
;; - manage_mfa: a user cannot configure mfa devices
;; - manage_credentials: a user cannot configure emails, passwords, or openid
;; - change_username: a user cannot change their username
;; - change_full_name: a user cannot change their full name
;;EXTERNAL_USER_DISABLE_FEATURES =
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1548,11 +1611,12 @@ LEVEL = Info
;; The source of the username for new oauth2 accounts:
;; userid = use the userid / sub attribute
;; nickname = use the nickname attribute
;; preferred_username = use the preferred_username attribute
;; email = use the username part of the email attribute
;; Note: `nickname` and `email` options will normalize input strings using the following criteria:
;; Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria:
;; - diacritics are removed
;; - the characters in the set `['´\x60]` are removed
;; - the characters in the set `[\s~+]` are replaced with `-`
;; - the characters in the set ['´`] are removed
;; - the characters in the set [\s~+] are replaced with "-"
;USERNAME = nickname
;;
;; Update avatar if available from oauth2 provider.
@ -1658,6 +1722,10 @@ LEVEL = Info
;; Sometimes it is helpful to use a different address on the envelope. Set this to use ENVELOPE_FROM as the from on the envelope. Set to `<>` to send an empty address.
;ENVELOPE_FROM =
;;
;; If gitea sends mails on behave of users, it will just use the name also displayed in the WebUI. If you want e.g. `Mister X (by CodeIt) <gitea@codeit.net>`,
;; set it to `{{ .DisplayName }} (by {{ .AppName }})`. Available Variables: `.DisplayName`, `.AppName` and `.Domain`.
;FROM_DISPLAY_NAME_FORMAT = {{ .DisplayName }}
;;
;; Mailer user name and password, if required by provider.
;USER =
;;
@ -1680,6 +1748,16 @@ LEVEL = Info
;; convert \r\n to \n for Sendmail
;SENDMAIL_CONVERT_CRLF = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[mailer.override_header]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; This is empty by default, use it only if you know what you need it for.
;Reply-To = test@example.com, test2@example.com
;Content-Type = text/html; charset=utf-8
;In-Reply-To =
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[email.incoming]
@ -1733,9 +1811,8 @@ LEVEL = Info
;; For "memory" only, GC interval in seconds, default is 60
;INTERVAL = 60
;;
;; For "redis", "redis-cluster" and "memcache", connection host address
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
;; redis-cluster: `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
;; For "redis" and "memcache", connection host address
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` (or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for a Redis cluster)
;; memcache: `127.0.0.1:11211`
;; twoqueue: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000`
;HOST =
@ -1765,15 +1842,14 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Either "memory", "file", "redis", "redis-cluster", "db", "mysql", "couchbase", "memcache" or "postgres"
;; Either "memory", "file", "redis", "db", "mysql", "couchbase", "memcache" or "postgres"
;; Default is "memory". "db" will reuse the configuration in [database]
;PROVIDER = memory
;;
;; Provider config options
;; memory: doesn't have any config yet
;; file: session file path, e.g. `data/sessions`
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
;; redis-cluster: `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` (or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for a Redis cluster)
;; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table`
;PROVIDER_CONFIG = data/sessions ; Relative paths will be made absolute against _`AppWorkPath`_.
;;
@ -1844,7 +1920,7 @@ LEVEL = Info
;ENABLED = true
;;
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
;ALLOWED_TYPES = .csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip
;ALLOWED_TYPES = .avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip
;;
;; Max size of each file. Defaults to 2048MB
;MAX_SIZE = 2048
@ -1857,7 +1933,7 @@ LEVEL = Info
;STORAGE_TYPE = local
;;
;; Allows the storage driver to redirect to authenticated URLs to serve files directly
;; Currently, only `minio` is supported.
;; Currently, only `minio` and `azureblob` is supported.
;SERVE_DIRECT = false
;;
;; Path for attachments. Defaults to `attachments`. Only available when STORAGE_TYPE is `local`
@ -1867,12 +1943,22 @@ LEVEL = Info
;; Minio endpoint to connect only available when STORAGE_TYPE is `minio`
;MINIO_ENDPOINT = localhost:9000
;;
;; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`
;; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`.
;; If not provided and STORAGE_TYPE is `minio`, will search for credentials in known
;; environment variables (MINIO_ACCESS_KEY_ID, AWS_ACCESS_KEY_ID), credentials files
;; (~/.mc/config.json, ~/.aws/credentials), and EC2 instance metadata.
;MINIO_ACCESS_KEY_ID =
;;
;; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio`
;MINIO_SECRET_ACCESS_KEY =
;;
;; Preferred IAM Endpoint to override Minio's default IAM Endpoint resolution only available when STORAGE_TYPE is `minio`.
;; If not provided and STORAGE_TYPE is `minio`, will search for and derive endpoint from known environment variables
;; (AWS_CONTAINER_AUTHORIZATION_TOKEN, AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE, AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,
;; AWS_CONTAINER_CREDENTIALS_FULL_URI, AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARN, AWS_ROLE_SESSION_NAME, AWS_REGION),
;; or the DefaultIAMRoleEndpoint if not provided otherwise.
;MINIO_IAM_ENDPOINT =
;;
;; Minio bucket to store the attachments only available when STORAGE_TYPE is `minio`
;MINIO_BUCKET = gitea
;;
@ -1890,6 +1976,24 @@ LEVEL = Info
;;
;; Minio checksum algorithm: default (for MinIO or AWS S3) or md5 (for Cloudflare or Backblaze)
;MINIO_CHECKSUM_ALGORITHM = default
;;
;; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
;MINIO_BUCKET_LOOKUP_TYPE = auto
;; Azure Blob endpoint to connect only available when STORAGE_TYPE is `azureblob`,
;; e.g. https://accountname.blob.core.windows.net or http://127.0.0.1:10000/devstoreaccount1
;AZURE_BLOB_ENDPOINT =
;;
;; Azure Blob account name to connect only available when STORAGE_TYPE is `azureblob`
;AZURE_BLOB_ACCOUNT_NAME =
;;
;; Azure Blob account key to connect only available when STORAGE_TYPE is `azureblob`
;AZURE_BLOB_ACCOUNT_KEY =
;;
;; Azure Blob container to store the attachments only available when STORAGE_TYPE is `azureblob`
;AZURE_BLOB_CONTAINER = gitea
;;
;; override the azure blob base path if storage type is azureblob
;AZURE_BLOB_BASE_PATH = attachments/
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2028,6 +2132,17 @@ LEVEL = Info
;; or only create new users if UPDATE_EXISTING is set to false
;UPDATE_EXISTING = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Cleanup expired actions assets
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.cleanup_actions]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = true
;RUN_AT_START = true
;SCHEDULE = @midnight
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Clean-up deleted branches
@ -2310,6 +2425,8 @@ LEVEL = Info
;SHOW_FOOTER_VERSION = true
;; Show template execution time in the footer
;SHOW_FOOTER_TEMPLATE_LOAD_TIME = true
;; Show the "powered by" text in the footer
;SHOW_FOOTER_POWERED_BY = true
;; Generate sitemap. Defaults to `true`.
;ENABLE_SITEMAP = true
;; Enable/Disable RSS/Atom feed
@ -2369,22 +2486,6 @@ LEVEL = Info
;; Enable issue by repository metrics; default is false
;ENABLED_ISSUE_BY_REPOSITORY = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[task]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Task queue type, could be `channel` or `redis`.
;QUEUE_TYPE = channel
;;
;; Task queue length, available only when `QUEUE_TYPE` is `channel`.
;QUEUE_LENGTH = 1000
;;
;; Task queue connection string, available only when `QUEUE_TYPE` is `redis`.
;; If there is a password of redis, use `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for `redis-clsuter`.
;QUEUE_CONN_STR = "redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[migrations]
@ -2452,6 +2553,11 @@ LEVEL = Info
;STORAGE_TYPE = local
;; override the minio base path if storage type is minio
;MINIO_BASE_PATH = packages/
;; override the azure blob base path if storage type is azureblob
;AZURE_BLOB_BASE_PATH = packages/
;; Allows the storage driver to redirect to authenticated URLs to serve files directly
;; Currently, only `minio` and `azureblob` is supported.
;SERVE_DIRECT = false
;;
;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload`
;CHUNKED_UPLOAD_PATH = tmp/package-upload
@ -2502,7 +2608,8 @@ LEVEL = Info
;LIMIT_SIZE_SWIFT = -1
;; Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_VAGRANT = -1
;; Enable RPM re-signing by default. (It will overwrite the old signature ,using v4 format, not compatible with CentOS 6 or older)
;DEFAULT_RPM_SIGN_ENABLED = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; default storage for attachments, lfs and avatars
@ -2525,6 +2632,8 @@ LEVEL = Info
;;
;; override the minio base path if storage type is minio
;MINIO_BASE_PATH = repo-archive/
;; override the azure blob base path if storage type is azureblob
;AZURE_BLOB_BASE_PATH = repo-archive/
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2546,8 +2655,25 @@ LEVEL = Info
;; Where your lfs files reside, default is data/lfs.
;PATH = data/lfs
;;
;; Allows the storage driver to redirect to authenticated URLs to serve files directly
;; Currently, only `minio` and `azureblob` is supported.
;SERVE_DIRECT = false
;;
;; override the minio base path if storage type is minio
;MINIO_BASE_PATH = lfs/
;;
;; override the azure blob base path if storage type is azureblob
;AZURE_BLOB_BASE_PATH = lfs/
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; settings for Gitea's LFS client (eg: mirroring an upstream lfs endpoint)
;;
;[lfs_client]
;; Limit the number of pointers in each batch request to this number
;BATCH_SIZE = 20
;; Limit the number of concurrent upload/download operations within a batch
;BATCH_OPERATION_CONCURRENCY = 8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2562,18 +2688,28 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; customize storage
;[storage.my_minio]
;[storage.minio]
;STORAGE_TYPE = minio
;;
;; Minio endpoint to connect only available when STORAGE_TYPE is `minio`
;MINIO_ENDPOINT = localhost:9000
;;
;; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`
;; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`.
;; If not provided and STORAGE_TYPE is `minio`, will search for credentials in known
;; environment variables (MINIO_ACCESS_KEY_ID, AWS_ACCESS_KEY_ID), credentials files
;; (~/.mc/config.json, ~/.aws/credentials), and EC2 instance metadata.
;MINIO_ACCESS_KEY_ID =
;;
;; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio`
;MINIO_SECRET_ACCESS_KEY =
;;
;; Preferred IAM Endpoint to override Minio's default IAM Endpoint resolution only available when STORAGE_TYPE is `minio`.
;; If not provided and STORAGE_TYPE is `minio`, will search for and derive endpoint from known environment variables
;; (AWS_CONTAINER_AUTHORIZATION_TOKEN, AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE, AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,
;; AWS_CONTAINER_CREDENTIALS_FULL_URI, AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARN, AWS_ROLE_SESSION_NAME, AWS_REGION),
;; or the DefaultIAMRoleEndpoint if not provided otherwise.
;MINIO_IAM_ENDPOINT =
;;
;; Minio bucket to store the attachments only available when STORAGE_TYPE is `minio`
;MINIO_BUCKET = gitea
;;
@ -2585,6 +2721,25 @@ LEVEL = Info
;;
;; Minio skip SSL verification available when STORAGE_TYPE is `minio`
;MINIO_INSECURE_SKIP_VERIFY = false
;;
;; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio`
;MINIO_BUCKET_LOOKUP_TYPE = auto
;[storage.azureblob]
;STORAGE_TYPE = azureblob
;;
;; Azure Blob endpoint to connect only available when STORAGE_TYPE is `azureblob`,
;; e.g. https://accountname.blob.core.windows.net or http://127.0.0.1:10000/devstoreaccount1
;AZURE_BLOB_ENDPOINT =
;;
;; Azure Blob account name to connect only available when STORAGE_TYPE is `azureblob`
;AZURE_BLOB_ACCOUNT_NAME =
;;
;; Azure Blob account key to connect only available when STORAGE_TYPE is `azureblob`
;AZURE_BLOB_ACCOUNT_KEY =
;;
;; Azure Blob container to store the attachments only available when STORAGE_TYPE is `azureblob`
;AZURE_BLOB_CONTAINER = gitea
;[proxy]
;; Enable the proxy, all requests to external via HTTP will be affected
@ -2600,6 +2755,14 @@ LEVEL = Info
;;
;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
;DEFAULT_ACTIONS_URL = github
;; Logs retention time in days. Old logs will be deleted after this period.
;LOG_RETENTION_DAYS = 365
;; Log compression type, `none` for no compression, `zstd` for zstd compression.
;; Other compression types like `gzip` are NOT supported, since seekable stream is required for log view.
;; It's always recommended to use compression when using local disk as log storage if CPU or memory is not a bottleneck.
;; And for object storage services like S3, which is billed for requests, it would cause extra 2 times of get requests for each log view.
;; But it will save storage space and network bandwidth, so it's still recommended to use compression.
;LOG_COMPRESSION = zstd
;; Default artifact retention time in days. Artifacts could have their own retention periods by setting the `retention-days` option in `actions/upload-artifact` step.
;ARTIFACT_RETENTION_DAYS = 90
;; Timeout to stop the task which have running status, but haven't been updated for a long time
@ -2620,3 +2783,9 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; storage type
;STORAGE_TYPE = local
;[global_lock]
;; Lock service type, could be memory or redis
;SERVICE_TYPE = memory
;; Ignored for the "memory" type. For "redis" use something like `redis://127.0.0.1:6379/0`
;SERVICE_CONN_STR =

View File

@ -1,7 +1,7 @@
# Gitea - Docker
Dockerfile is found in root of repository.
Dockerfile is found in the root of the repository.
Docker image can be found on [docker hub](https://hub.docker.com/r/gitea/gitea)
Docker image can be found on [docker hub](https://hub.docker.com/r/gitea/gitea).
Documentation on using docker image can be found on [Gitea Docs site](https://docs.gitea.com/installation/install-with-docker-rootless)
Documentation on using docker image can be found on [Gitea Docs site](https://docs.gitea.com/installation/install-with-docker-rootless).

7
docs/.gitignore vendored
View File

@ -1,7 +0,0 @@
public/
templates/swagger/v1_json.tmpl
themes/
resources/
# Temporary lock file while building
/.hugo_build.lock

View File

@ -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.

View File

@ -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>
```

View File

@ -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>
```

View File

@ -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"
---

View File

@ -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"
---

View File

@ -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"
---

View File

@ -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.

View File

@ -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 以查看更改。

View File

@ -1,160 +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/data/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.
If you still have issues, consider running `./gitea doctor check` to inspect possible errors (or run with `--fix`).
### 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
```

View File

@ -1,154 +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压缩文件。该压缩文件可以被用来进行数据恢复。
## 备份一致性
为了确保 Gitea 实例的一致性,在备份期间必须关闭它。
Gitea 包括数据库、文件和 Git 仓库,当它被使用时所有这些都会发生变化。例如,当迁移正在进行时,在数据库中创建一个事务,而 Git 仓库正在被复制。如果备份发生在迁移的中间Git 仓库可能是不完整的,尽管数据库声称它是完整的,因为它是在之后被转储的。避免这种竞争条件的唯一方法是在备份期间停止 Gitea 实例。
## 备份命令 (`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` 文件将会包含如下内容:
* `app.ini` - 如果原先存储在默认的 custom/ 目录之外,则是配置文件的可选副本
* `custom/` - 所有保存在 `custom/` 目录下的配置和自定义的文件。
* `data/` - 数据目录APP_DATA_PATH如果使用文件会话则不包括会话。该目录包括 `attachments`、`avatars`、`lfs`、`indexers`、如果使用 SQLite 则包括 SQLite 文件。
* `repos/` - 仓库目录的完整副本。
* `gitea-db.sql` - 数据库dump出来的 SQL。
* `log/` - Logs文件如果用作迁移不是必须的。
中间备份文件将会在临时目录进行创建,如果您要重新指定临时目录,可以用 `--tempdir` 参数,或者用 `TMPDIR` 环境变量。
## 备份数据库
`gitea dump` 创建的 SQL 转储使用 XORMGitea 管理员可能更喜欢使用本地的 MySQL 和 PostgreSQL 转储工具。使用 XORM 转储数据库时仍然存在一些问题,可能会导致在尝试恢复时出现问题。
```sh
# mysql
mysqldump -u$USER -p$PASS --database $DATABASE > gitea-db.sql
# postgres
pg_dump -U $USER $DATABASE > gitea-db.sql
```
### 使用Docker `dump`
在使用 Docker 时,使用 `dump` 命令有一些注意事项。
必须以 `gitea/conf/app.ini` 中指定的 `RUN_USER = <OS_USERNAME>` 执行该命令;并且,为了让备份文件夹的压缩过程能够顺利执行,`docker exec` 命令必须在 `--tempdir` 内部执行。
示例:
```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>'
```
\*注意:`--tempdir` 指的是 Gitea 使用的 Docker 环境的临时目录;如果您没有指定自定义的 `--tempdir`,那么 Gitea 将使用 `/tmp` 或 Docker 容器的 `TMPDIR` 环境变量。对于 `--tempdir`,请相应调整您的 `docker exec` 命令选项。
结果应该是一个文件,存储在指定的 `--tempdir` 中,类似于:`gitea-dump-1482906742.zip`
## 恢复命令 (`restore`)
当前还没有恢复命令,恢复需要人工进行。主要是把文件和数据库进行恢复。
例如:
```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
```
如果安装方式发生了变化(例如 二进制 -> Docker或者 Gitea 安装到了与之前安装不同的目录,则需要重新生成仓库 Git 钩子。
在 Gitea 运行时,并从 Gitea 二进制文件所在的目录执行:`./gitea admin regenerate hooks`
这样可以确保仓库 Git 钩子中的应用程序和配置文件路径与当前安装一致。如果这些路径没有更新,仓库的 `push` 操作将失败。
### 使用 Docker (`restore`)
在基于 Docker 的 Gitea 实例中,也没有恢复命令的支持。恢复过程与前面描述的步骤相同,但路径不同。
示例:
```sh
# 在容器中打开 bash 会话
docker exec --user git -it 2a83b293548e bash
# 在容器内解压您的备份文件
unzip gitea-dump-1610949662.zip
cd gitea-dump-1610949662
# 恢复 Gitea 数据
mv data/* /data/gitea
# 恢复仓库本身
mv repos/* /data/git/gitea-repositories/
# 调整文件权限
chown -R git:git /data
# 重新生成 Git 钩子
/usr/local/bin/gitea -c '/data/gitea/conf/app.ini' admin regenerate hooks
```
Gitea 容器中的默认用户是 `git`1000:1000。请用您的 Gitea 容器 ID 或名称替换 `2a83b293548e`
### 使用 Docker-rootless (`restore`)
在 Docker-rootless 容器中的恢复工作流程只是要使用的目录不同:
```sh
# 在容器中打开 bash 会话
docker exec --user git -it 2a83b293548e bash
# 在容器内解压您的备份文件
unzip gitea-dump-1610949662.zip
cd gitea-dump-1610949662
# 恢复 app.ini
mv data/conf/app.ini /etc/gitea/app.ini
# 恢复 Gitea 数据
mv data/* /var/lib/gitea
# 恢复仓库本身
mv repos/* /var/lib/gitea/git/gitea-repositories
# 调整文件权限
chown -R git:git /etc/gitea/app.ini /var/lib/gitea
# 重新生成 Git 钩子
/usr/local/bin/gitea -c '/etc/gitea/app.ini' admin regenerate hooks
```

View File

@ -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
```

View File

@ -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/assets/img` 目录下的所有文件:`public/assets/img/**`
不要忘记为模式使用引号,因为空格、`*` 和其他字符可能对命令行解释器有特殊含义。
如果未提供模式,则列出所有文件。
### 示例:列出所有嵌入文件
列出所有路径中包含 `openid` 的嵌入文件:
```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
```
## 提取资源
要提取嵌入在 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
```

View File

@ -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 users LDAP record containing the user name.
- `--firstname-attribute value`: The attribute of the users LDAP record containing the users first name.
- `--surname-attribute value`: The attribute of the users LDAP record containing the users surname.
- `--email-attribute value`: The attribute of the users LDAP record containing the users email address. Required.
- `--public-ssh-key-attribute value`: The attribute of the users LDAP record containing the users public ssh key.
- `--avatar-attribute value`: The attribute of the users LDAP record containing the users 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 users LDAP record containing the user name.
- `--firstname-attribute value`: The attribute of the users LDAP record containing the users first name.
- `--surname-attribute value`: The attribute of the users LDAP record containing the users surname.
- `--email-attribute value`: The attribute of the users LDAP record containing the users email address.
- `--public-ssh-key-attribute value`: The attribute of the users LDAP record containing the users public ssh key.
- `--avatar-attribute value`: The attribute of the users LDAP record containing the users 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 users LDAP record containing the user name.
- `--firstname-attribute value`: The attribute of the users LDAP record containing the users first name.
- `--surname-attribute value`: The attribute of the users LDAP record containing the users surname.
- `--email-attribute value`: The attribute of the users LDAP record containing the users email address. Required.
- `--public-ssh-key-attribute value`: The attribute of the users LDAP record containing the users public ssh key.
- `--avatar-attribute value`: The attribute of the users LDAP record containing the users avatar.
- `--user-dn value`: The users 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 users LDAP record containing the user name.
- `--firstname-attribute value`: The attribute of the users LDAP record containing the users first name.
- `--surname-attribute value`: The attribute of the users LDAP record containing the users surname.
- `--email-attribute value`: The attribute of the users LDAP record containing the users email address.
- `--public-ssh-key-attribute value`: The attribute of the users LDAP record containing the users public ssh key.
- `--avatar-attribute value`: The attribute of the users LDAP record containing the users avatar.
- `--user-dn value`: The users 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
```

View File

@ -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`:客户端 IDKey
- `--secret`:客户端密钥。
- `--auto-discover-url`OpenID Connect 自动发现 URL仅在使用 OpenID Connect 作为提供程序时需要)。
- `--use-custom-urls`:在 GitLab/GitHub OAuth 端点上使用自定义 URL。
- `--custom-tenant-id`:在 OAuth 端点上使用自定义租户 ID。
- `--custom-auth-url`:使用自定义授权 URLGitLab/GitHub 的选项)。
- `--custom-token-url`:使用自定义令牌 URLGitLab/GitHub 的选项)。
- `--custom-profile-url`:使用自定义配置文件 URLGitLab/GitHub 的选项)。
- `--custom-email-url`:使用自定义电子邮件 URLGitHub 的选项)。
- `--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`:客户端 IDKey
- `--secret`:客户端密钥。
- `--auto-discover-url`OpenID Connect 自动发现 URL仅在使用 OpenID Connect 作为提供程序时需要)。
- `--use-custom-urls`:在 GitLab/GitHub OAuth 端点上使用自定义 URL。
- `--custom-tenant-id`:在 OAuth 端点上使用自定义租户 ID。
- `--custom-auth-url`:使用自定义授权 URLGitLab/GitHub 的选项)。
- `--custom-token-url`:使用自定义令牌 URLGitLab/GitHub 的选项)。
- `--custom-profile-url`:使用自定义配置文件 URLGitLab/GitHub 的选项)。
- `--custom-email-url`:使用自定义电子邮件 URLGitHub 的选项)。
- `--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

View File

@ -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;
}
```

View File

@ -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 脚本。
## 自定义 gitignoreslabels licenses locales 以及 readmes
将自定义文件放在 `custom/options` 下相应子的文件夹中即可
## 更改 Gitea 外观
内置主题是“gitea-light”、“gitea-dark”和“gitea-auto”自动适应操作系统设置
默认主题可以通过 `app.ini` 的 [ui](administration/config-cheat-sheet.md#ui-ui) 部分中的 `DEFAULT_THEME` 进行更改。

View File

@ -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.

View File

@ -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 帐户密码。

View File

@ -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.

View File

@ -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 的形式运行。

View File

@ -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" />
```

View File

@ -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 样式应用到特定的外部渲染器,使其具有所需的样式效果。

View File

@ -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
```

View File

@ -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)

View File

@ -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

View File

@ -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 StorageLFS
要使用 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 以上版本。

View File

@ -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 establish 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.

View File

@ -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 上。

View File

@ -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`.

Some files were not shown because too many files have changed in this diff Show More