mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-15 12:33:45 +09:00
Compare commits
48 Commits
v1.20.4
...
v1.19.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1edb57eda9 | ||
|
|
a2a9b0f977 | ||
|
|
ff96f804b6 | ||
|
|
a926994bfe | ||
|
|
83903535e3 | ||
|
|
8142408d3a | ||
|
|
a4158d1904 | ||
|
|
781019216c | ||
|
|
1322cd7a58 | ||
|
|
464bbd747e | ||
|
|
574182e1eb | ||
|
|
ef8209a953 | ||
|
|
9309098eab | ||
|
|
790a79b04c | ||
|
|
f8a40dafb9 | ||
|
|
9843a0b741 | ||
|
|
085a4debd5 | ||
|
|
4c1e24864f | ||
|
|
5d5f907e7f | ||
|
|
39178b5756 | ||
|
|
3d8412dd51 | ||
|
|
ff7057a46d | ||
|
|
bb8ef28913 | ||
|
|
13918ad344 | ||
|
|
7528ce60e7 | ||
|
|
6c6a7e7d97 | ||
|
|
111c509287 | ||
|
|
9d7ef0ad63 | ||
|
|
9aae54c81f | ||
|
|
1bc4ffc337 | ||
|
|
27879bc45e | ||
|
|
a3694b6989 | ||
|
|
28625fba5b | ||
|
|
7c3196ceac | ||
|
|
80c1264f4b | ||
|
|
f0340c28f1 | ||
|
|
5beb29ad35 | ||
|
|
27e307142b | ||
|
|
e02e752f68 | ||
|
|
5ddf67a9c2 | ||
|
|
4d3e2b23b8 | ||
|
|
ddf61373f6 | ||
|
|
b4ed3f07e4 | ||
|
|
ced94f2e0d | ||
|
|
aff432b197 | ||
|
|
0ac3be1482 | ||
|
|
75eaf99076 | ||
|
|
e67d60d336 |
@@ -2,12 +2,9 @@ root = "."
|
|||||||
tmp_dir = ".air"
|
tmp_dir = ".air"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
cmd = "make --no-print-directory backend"
|
cmd = "make backend"
|
||||||
bin = "gitea"
|
bin = "gitea"
|
||||||
delay = 1000
|
|
||||||
include_ext = ["go", "tmpl"]
|
include_ext = ["go", "tmpl"]
|
||||||
include_file = ["main.go"]
|
|
||||||
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
|
|
||||||
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"]
|
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"]
|
||||||
|
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
|
||||||
exclude_regex = ["_test.go$", "_gen.go$"]
|
exclude_regex = ["_test.go$", "_gen.go$"]
|
||||||
stop_on_error = true
|
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ cpu.out
|
|||||||
/yarn-error.log
|
/yarn-error.log
|
||||||
/npm-debug.log*
|
/npm-debug.log*
|
||||||
/public/js
|
/public/js
|
||||||
|
/public/serviceworker.js
|
||||||
/public/css
|
/public/css
|
||||||
/public/fonts
|
/public/fonts
|
||||||
/public/img/webpack
|
/public/img/webpack
|
||||||
|
|||||||
1358
.drone.yml
1358
.drone.yml
File diff suppressed because it is too large
Load Diff
252
.eslintrc.yaml
252
.eslintrc.yaml
@@ -9,17 +9,10 @@ parserOptions:
|
|||||||
ecmaVersion: latest
|
ecmaVersion: latest
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
- "@eslint-community/eslint-plugin-eslint-comments"
|
- eslint-plugin-unicorn
|
||||||
- eslint-plugin-array-func
|
|
||||||
- eslint-plugin-custom-elements
|
|
||||||
- eslint-plugin-import
|
- eslint-plugin-import
|
||||||
- eslint-plugin-jquery
|
- eslint-plugin-jquery
|
||||||
- eslint-plugin-no-jquery
|
|
||||||
- eslint-plugin-no-use-extend-native
|
|
||||||
- eslint-plugin-regexp
|
|
||||||
- eslint-plugin-sonarjs
|
- eslint-plugin-sonarjs
|
||||||
- eslint-plugin-unicorn
|
|
||||||
- eslint-plugin-wc
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
es2022: true
|
es2022: true
|
||||||
@@ -29,11 +22,11 @@ globals:
|
|||||||
__webpack_public_path__: true
|
__webpack_public_path__: true
|
||||||
|
|
||||||
overrides:
|
overrides:
|
||||||
- files: ["web_src/**/*", "docs/**/*"]
|
- files: ["web_src/**/*.js", "docs/**/*.js"]
|
||||||
env:
|
env:
|
||||||
browser: true
|
browser: true
|
||||||
node: false
|
node: false
|
||||||
- files: ["web_src/**/*worker.*"]
|
- files: ["web_src/**/*worker.js"]
|
||||||
env:
|
env:
|
||||||
worker: true
|
worker: true
|
||||||
rules:
|
rules:
|
||||||
@@ -42,31 +35,16 @@ overrides:
|
|||||||
rules:
|
rules:
|
||||||
import/no-unresolved: [0]
|
import/no-unresolved: [0]
|
||||||
import/no-extraneous-dependencies: [0]
|
import/no-extraneous-dependencies: [0]
|
||||||
- files: ["*.config.*"]
|
- files: ["*.config.js"]
|
||||||
rules:
|
rules:
|
||||||
import/no-unused-modules: [0]
|
import/no-unused-modules: [0]
|
||||||
|
|
||||||
rules:
|
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]
|
|
||||||
accessor-pairs: [2]
|
accessor-pairs: [2]
|
||||||
array-bracket-newline: [0]
|
array-bracket-newline: [0]
|
||||||
array-bracket-spacing: [2, never]
|
array-bracket-spacing: [2, never]
|
||||||
array-callback-return: [2, {checkForEach: true}]
|
array-callback-return: [2, {checkForEach: true}]
|
||||||
array-element-newline: [0]
|
array-element-newline: [0]
|
||||||
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]
|
arrow-body-style: [0]
|
||||||
arrow-parens: [2, always]
|
arrow-parens: [2, always]
|
||||||
arrow-spacing: [2, {before: true, after: true}]
|
arrow-spacing: [2, {before: true, after: true}]
|
||||||
@@ -84,19 +62,6 @@ rules:
|
|||||||
consistent-this: [0]
|
consistent-this: [0]
|
||||||
constructor-super: [2]
|
constructor-super: [2]
|
||||||
curly: [0]
|
curly: [0]
|
||||||
custom-elements/expose-class-on-global: [0]
|
|
||||||
custom-elements/extends-correct-class: [2]
|
|
||||||
custom-elements/file-name-matches-element: [2]
|
|
||||||
custom-elements/no-constructor: [2]
|
|
||||||
custom-elements/no-customized-built-in-elements: [2]
|
|
||||||
custom-elements/no-dom-traversal-in-attributechangedcallback: [2]
|
|
||||||
custom-elements/no-dom-traversal-in-connectedcallback: [2]
|
|
||||||
custom-elements/no-exports-with-element: [2]
|
|
||||||
custom-elements/no-method-prefixed-with-on: [2]
|
|
||||||
custom-elements/no-unchecked-define: [0]
|
|
||||||
custom-elements/one-element-per-file: [0]
|
|
||||||
custom-elements/tag-name-matches-class: [2]
|
|
||||||
custom-elements/valid-tag-name: [2]
|
|
||||||
default-case-last: [2]
|
default-case-last: [2]
|
||||||
default-case: [0]
|
default-case: [0]
|
||||||
default-param-last: [0]
|
default-param-last: [0]
|
||||||
@@ -132,9 +97,9 @@ rules:
|
|||||||
import/namespace: [0]
|
import/namespace: [0]
|
||||||
import/newline-after-import: [0]
|
import/newline-after-import: [0]
|
||||||
import/no-absolute-path: [0]
|
import/no-absolute-path: [0]
|
||||||
import/no-amd: [2]
|
import/no-amd: [0]
|
||||||
import/no-anonymous-default-export: [0]
|
import/no-anonymous-default-export: [0]
|
||||||
import/no-commonjs: [2]
|
import/no-commonjs: [0]
|
||||||
import/no-cycle: [2, {ignoreExternal: true, maxDepth: 1}]
|
import/no-cycle: [2, {ignoreExternal: true, maxDepth: 1}]
|
||||||
import/no-default-export: [0]
|
import/no-default-export: [0]
|
||||||
import/no-deprecated: [0]
|
import/no-deprecated: [0]
|
||||||
@@ -199,7 +164,7 @@ rules:
|
|||||||
jquery/no-parse-html: [2]
|
jquery/no-parse-html: [2]
|
||||||
jquery/no-prop: [0]
|
jquery/no-prop: [0]
|
||||||
jquery/no-proxy: [2]
|
jquery/no-proxy: [2]
|
||||||
jquery/no-ready: [2]
|
jquery/no-ready: [0]
|
||||||
jquery/no-serialize: [2]
|
jquery/no-serialize: [2]
|
||||||
jquery/no-show: [2]
|
jquery/no-show: [2]
|
||||||
jquery/no-size: [2]
|
jquery/no-size: [2]
|
||||||
@@ -291,99 +256,6 @@ rules:
|
|||||||
no-invalid-this: [0]
|
no-invalid-this: [0]
|
||||||
no-irregular-whitespace: [2]
|
no-irregular-whitespace: [2]
|
||||||
no-iterator: [2]
|
no-iterator: [2]
|
||||||
no-jquery/no-ajax-events: [2]
|
|
||||||
no-jquery/no-ajax: [0]
|
|
||||||
no-jquery/no-and-self: [2]
|
|
||||||
no-jquery/no-animate-toggle: [2]
|
|
||||||
no-jquery/no-animate: [2]
|
|
||||||
no-jquery/no-append-html: [0]
|
|
||||||
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: [0]
|
|
||||||
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: [0]
|
|
||||||
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: [0]
|
|
||||||
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: [0]
|
|
||||||
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: [0]
|
|
||||||
no-label-var: [2]
|
no-label-var: [2]
|
||||||
no-labels: [0] # handled by no-restricted-syntax
|
no-labels: [0] # handled by no-restricted-syntax
|
||||||
no-lone-blocks: [2]
|
no-lone-blocks: [2]
|
||||||
@@ -452,7 +324,6 @@ rules:
|
|||||||
no-unused-private-class-members: [2]
|
no-unused-private-class-members: [2]
|
||||||
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}]
|
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-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-backreference: [2]
|
||||||
no-useless-call: [2]
|
no-useless-call: [2]
|
||||||
no-useless-catch: [2]
|
no-useless-catch: [2]
|
||||||
@@ -493,80 +364,6 @@ rules:
|
|||||||
quote-props: [0]
|
quote-props: [0]
|
||||||
quotes: [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
|
quotes: [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
|
||||||
radix: [2, as-needed]
|
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-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-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-star-quantifier: [2]
|
|
||||||
regexp/prefer-unicode-codepoint-escapes: [2]
|
|
||||||
regexp/prefer-w: [0]
|
|
||||||
regexp/require-unicode-regexp: [0]
|
|
||||||
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-atomic-updates: [0]
|
||||||
require-await: [0]
|
require-await: [0]
|
||||||
require-unicode-regexp: [0]
|
require-unicode-regexp: [0]
|
||||||
@@ -596,7 +393,7 @@ rules:
|
|||||||
sonarjs/no-nested-template-literals: [0]
|
sonarjs/no-nested-template-literals: [0]
|
||||||
sonarjs/no-one-iteration-loop: [2]
|
sonarjs/no-one-iteration-loop: [2]
|
||||||
sonarjs/no-redundant-boolean: [2]
|
sonarjs/no-redundant-boolean: [2]
|
||||||
sonarjs/no-redundant-jump: [2]
|
sonarjs/no-redundant-jump: [0]
|
||||||
sonarjs/no-same-line-conditional: [2]
|
sonarjs/no-same-line-conditional: [2]
|
||||||
sonarjs/no-small-switch: [0]
|
sonarjs/no-small-switch: [0]
|
||||||
sonarjs/no-unused-collection: [2]
|
sonarjs/no-unused-collection: [2]
|
||||||
@@ -636,18 +433,17 @@ rules:
|
|||||||
unicorn/import-style: [0]
|
unicorn/import-style: [0]
|
||||||
unicorn/new-for-builtins: [2]
|
unicorn/new-for-builtins: [2]
|
||||||
unicorn/no-abusive-eslint-disable: [0]
|
unicorn/no-abusive-eslint-disable: [0]
|
||||||
unicorn/no-array-callback-reference: [0]
|
|
||||||
unicorn/no-array-for-each: [2]
|
unicorn/no-array-for-each: [2]
|
||||||
|
unicorn/no-array-instanceof: [0]
|
||||||
unicorn/no-array-method-this-argument: [2]
|
unicorn/no-array-method-this-argument: [2]
|
||||||
unicorn/no-array-push-push: [2]
|
unicorn/no-array-push-push: [2]
|
||||||
unicorn/no-array-reduce: [2]
|
|
||||||
unicorn/no-await-expression-member: [0]
|
unicorn/no-await-expression-member: [0]
|
||||||
unicorn/no-console-spaces: [0]
|
unicorn/no-console-spaces: [0]
|
||||||
unicorn/no-document-cookie: [2]
|
unicorn/no-document-cookie: [2]
|
||||||
unicorn/no-empty-file: [2]
|
unicorn/no-empty-file: [2]
|
||||||
|
unicorn/no-fn-reference-in-iterator: [0]
|
||||||
unicorn/no-for-loop: [0]
|
unicorn/no-for-loop: [0]
|
||||||
unicorn/no-hex-escape: [0]
|
unicorn/no-hex-escape: [0]
|
||||||
unicorn/no-instanceof-array: [0]
|
|
||||||
unicorn/no-invalid-remove-event-listener: [2]
|
unicorn/no-invalid-remove-event-listener: [2]
|
||||||
unicorn/no-keyword-prefix: [0]
|
unicorn/no-keyword-prefix: [0]
|
||||||
unicorn/no-lonely-if: [2]
|
unicorn/no-lonely-if: [2]
|
||||||
@@ -658,6 +454,7 @@ rules:
|
|||||||
unicorn/no-null: [0]
|
unicorn/no-null: [0]
|
||||||
unicorn/no-object-as-default-parameter: [0]
|
unicorn/no-object-as-default-parameter: [0]
|
||||||
unicorn/no-process-exit: [0]
|
unicorn/no-process-exit: [0]
|
||||||
|
unicorn/no-reduce: [2]
|
||||||
unicorn/no-static-only-class: [2]
|
unicorn/no-static-only-class: [2]
|
||||||
unicorn/no-thenable: [2]
|
unicorn/no-thenable: [2]
|
||||||
unicorn/no-this-assignment: [2]
|
unicorn/no-this-assignment: [2]
|
||||||
@@ -683,19 +480,15 @@ rules:
|
|||||||
unicorn/prefer-array-index-of: [2]
|
unicorn/prefer-array-index-of: [2]
|
||||||
unicorn/prefer-array-some: [2]
|
unicorn/prefer-array-some: [2]
|
||||||
unicorn/prefer-at: [0]
|
unicorn/prefer-at: [0]
|
||||||
unicorn/prefer-blob-reading-methods: [2]
|
|
||||||
unicorn/prefer-code-point: [0]
|
unicorn/prefer-code-point: [0]
|
||||||
|
unicorn/prefer-dataset: [2]
|
||||||
unicorn/prefer-date-now: [2]
|
unicorn/prefer-date-now: [2]
|
||||||
unicorn/prefer-default-parameters: [0]
|
unicorn/prefer-default-parameters: [0]
|
||||||
unicorn/prefer-dom-node-append: [2]
|
unicorn/prefer-event-key: [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-event-target: [2]
|
||||||
unicorn/prefer-export-from: [2, {ignoreUsedVariables: true}]
|
unicorn/prefer-export-from: [2]
|
||||||
unicorn/prefer-includes: [2]
|
unicorn/prefer-includes: [2]
|
||||||
unicorn/prefer-json-parse-buffer: [0]
|
unicorn/prefer-json-parse-buffer: [0]
|
||||||
unicorn/prefer-keyboard-event-key: [2]
|
|
||||||
unicorn/prefer-logical-operator-over-ternary: [2]
|
unicorn/prefer-logical-operator-over-ternary: [2]
|
||||||
unicorn/prefer-math-trunc: [2]
|
unicorn/prefer-math-trunc: [2]
|
||||||
unicorn/prefer-modern-dom-apis: [0]
|
unicorn/prefer-modern-dom-apis: [0]
|
||||||
@@ -703,7 +496,9 @@ rules:
|
|||||||
unicorn/prefer-module: [2]
|
unicorn/prefer-module: [2]
|
||||||
unicorn/prefer-native-coercion-functions: [2]
|
unicorn/prefer-native-coercion-functions: [2]
|
||||||
unicorn/prefer-negative-index: [2]
|
unicorn/prefer-negative-index: [2]
|
||||||
|
unicorn/prefer-node-append: [0]
|
||||||
unicorn/prefer-node-protocol: [2]
|
unicorn/prefer-node-protocol: [2]
|
||||||
|
unicorn/prefer-node-remove: [0]
|
||||||
unicorn/prefer-number-properties: [0]
|
unicorn/prefer-number-properties: [0]
|
||||||
unicorn/prefer-object-from-entries: [2]
|
unicorn/prefer-object-from-entries: [2]
|
||||||
unicorn/prefer-object-has-own: [0]
|
unicorn/prefer-object-has-own: [0]
|
||||||
@@ -712,17 +507,17 @@ rules:
|
|||||||
unicorn/prefer-query-selector: [0]
|
unicorn/prefer-query-selector: [0]
|
||||||
unicorn/prefer-reflect-apply: [0]
|
unicorn/prefer-reflect-apply: [0]
|
||||||
unicorn/prefer-regexp-test: [2]
|
unicorn/prefer-regexp-test: [2]
|
||||||
|
unicorn/prefer-replace-all: [0]
|
||||||
unicorn/prefer-set-has: [0]
|
unicorn/prefer-set-has: [0]
|
||||||
unicorn/prefer-set-size: [2]
|
unicorn/prefer-set-size: [2]
|
||||||
unicorn/prefer-spread: [0]
|
unicorn/prefer-spread: [0]
|
||||||
unicorn/prefer-string-replace-all: [0]
|
unicorn/prefer-starts-ends-with: [2]
|
||||||
unicorn/prefer-string-slice: [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-switch: [0]
|
||||||
unicorn/prefer-ternary: [0]
|
unicorn/prefer-ternary: [0]
|
||||||
unicorn/prefer-text-content: [2]
|
unicorn/prefer-text-content: [2]
|
||||||
unicorn/prefer-top-level-await: [0]
|
unicorn/prefer-top-level-await: [0]
|
||||||
|
unicorn/prefer-trim-start-end: [2]
|
||||||
unicorn/prefer-type-error: [0]
|
unicorn/prefer-type-error: [0]
|
||||||
unicorn/prevent-abbreviations: [0]
|
unicorn/prevent-abbreviations: [0]
|
||||||
unicorn/relative-url-style: [2]
|
unicorn/relative-url-style: [2]
|
||||||
@@ -737,15 +532,6 @@ rules:
|
|||||||
use-isnan: [2]
|
use-isnan: [2]
|
||||||
valid-typeof: [2, {requireStringLiterals: true}]
|
valid-typeof: [2, {requireStringLiterals: true}]
|
||||||
vars-on-top: [0]
|
vars-on-top: [0]
|
||||||
wc/attach-shadow-constructor: [2]
|
|
||||||
wc/guard-super-call: [2]
|
|
||||||
wc/no-closed-shadow-root: [2]
|
|
||||||
wc/no-constructor-attributes: [2]
|
|
||||||
wc/no-constructor-params: [2]
|
|
||||||
wc/no-invalid-element-name: [0] # covered by custom-elements/valid-tag-name
|
|
||||||
wc/no-self-class: [2]
|
|
||||||
wc/no-typos: [2]
|
|
||||||
wc/require-listener-teardown: [2]
|
|
||||||
wrap-iife: [2, inside]
|
wrap-iife: [2, inside]
|
||||||
wrap-regex: [0]
|
wrap-regex: [0]
|
||||||
yield-star-spacing: [2, after]
|
yield-star-spacing: [2, after]
|
||||||
|
|||||||
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -1,10 +1,8 @@
|
|||||||
* text=auto eol=lf
|
* text=auto eol=lf
|
||||||
*.tmpl linguist-language=Handlebars
|
*.tmpl linguist-language=Handlebars
|
||||||
/assets/*.json linguist-generated
|
/assets/*.json linguist-generated
|
||||||
/public/img/svg/*.svg linguist-generated
|
/public/vendor/** -text -eol linguist-vendored
|
||||||
/templates/swagger/v1_json.tmpl linguist-generated
|
|
||||||
/vendor/** -text -eol linguist-vendored
|
/vendor/** -text -eol linguist-vendored
|
||||||
/web_src/fomantic/build/** linguist-generated
|
/web_src/fomantic/build/** linguist-generated
|
||||||
/web_src/fomantic/_site/globals/site.variables linguist-language=Less
|
|
||||||
/web_src/js/vendor/** -text -eol linguist-vendored
|
/web_src/js/vendor/** -text -eol linguist-vendored
|
||||||
Dockerfile.* linguist-language=Dockerfile
|
Dockerfile.* linguist-language=Dockerfile
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
2. Please ask questions or configuration/deploy problems on our Discord
|
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://discourse.gitea.io).
|
||||||
3. Please take a moment to check that your issue doesn't already exist.
|
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)
|
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.io/en-us/faq)
|
||||||
5. Please give all relevant information below for bug reports, because
|
5. Please give all relevant information below for bug reports, because
|
||||||
incomplete details will be handled as an invalid report.
|
incomplete details will be handled as an invalid report.
|
||||||
-->
|
-->
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
- [ ] No
|
- [ ] No
|
||||||
- Log gist:
|
- Log gist:
|
||||||
<!-- It really is important to provide pertinent logs -->
|
<!-- It really is important to provide pertinent logs -->
|
||||||
<!-- Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help -->
|
<!-- Please read https://docs.gitea.io/en-us/logging-configuration/#debugging-problems -->
|
||||||
<!-- In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini -->
|
<!-- In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini -->
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|||||||
13
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
13
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
@@ -1,6 +1,6 @@
|
|||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: Found something you weren't expecting? Report it here!
|
description: Found something you weren't expecting? Report it here!
|
||||||
labels: ["kind/bug"]
|
labels: kind/bug
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
@@ -14,9 +14,12 @@ body:
|
|||||||
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
|
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
|
||||||
3. Make sure you are using the latest release and
|
3. Make sure you are using the latest release and
|
||||||
take a moment to check that your issue hasn't been reported before.
|
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)
|
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.io/en-us/faq)
|
||||||
5. It's really important to provide pertinent details and logs (https://docs.gitea.com/help/support),
|
5. Please give all relevant information below for bug reports, because
|
||||||
incomplete details will be handled as an invalid report.
|
incomplete details will be handled as an invalid report.
|
||||||
|
6. In particular it's really important to provide pertinent logs. You must give us DEBUG level logs.
|
||||||
|
Please read https://docs.gitea.io/en-us/logging-configuration/#debugging-problems
|
||||||
|
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description
|
id: description
|
||||||
attributes:
|
attributes:
|
||||||
@@ -47,7 +50,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
It's really important to provide pertinent logs
|
It's really important to provide pertinent logs
|
||||||
Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help
|
Please read https://docs.gitea.io/en-us/logging-configuration/#debugging-problems
|
||||||
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
|
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
|
||||||
- type: input
|
- type: input
|
||||||
id: logs
|
id: logs
|
||||||
@@ -86,6 +89,6 @@ body:
|
|||||||
description: What database system are you running?
|
description: What database system are you running?
|
||||||
options:
|
options:
|
||||||
- PostgreSQL
|
- PostgreSQL
|
||||||
- MySQL/MariaDB
|
- MySQL
|
||||||
- MSSQL
|
- MSSQL
|
||||||
- SQLite
|
- SQLite
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -10,7 +10,7 @@ contact_links:
|
|||||||
url: https://discourse.gitea.io
|
url: https://discourse.gitea.io
|
||||||
about: Questions and configuration or deployment problems can also be discussed on our forum.
|
about: Questions and configuration or deployment problems can also be discussed on our forum.
|
||||||
- name: Frequently Asked Questions
|
- name: Frequently Asked Questions
|
||||||
url: https://docs.gitea.com/help/faq
|
url: https://docs.gitea.io/en-us/faq
|
||||||
about: Please check if your question isn't mentioned here.
|
about: Please check if your question isn't mentioned here.
|
||||||
- name: Crowdin Translations
|
- name: Crowdin Translations
|
||||||
url: https://crowdin.com/project/gitea
|
url: https://crowdin.com/project/gitea
|
||||||
|
|||||||
4
.github/ISSUE_TEMPLATE/ui.bug-report.yaml
vendored
4
.github/ISSUE_TEMPLATE/ui.bug-report.yaml
vendored
@@ -13,12 +13,12 @@ body:
|
|||||||
2. Please ask questions or configuration/deploy problems on our Discord
|
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://discourse.gitea.io).
|
||||||
3. Please take a moment to check that your issue doesn't already exist.
|
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)
|
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.io/en-us/faq)
|
||||||
5. Please give all relevant information below for bug reports, because
|
5. Please give all relevant information below for bug reports, because
|
||||||
incomplete details will be handled as an invalid report.
|
incomplete details will be handled as an invalid report.
|
||||||
6. In particular it's really important to provide pertinent logs. If you are certain that this is a javascript
|
6. In particular it's really important to provide pertinent logs. If you are certain that this is a javascript
|
||||||
error, show us the javascript console. If the error appears to relate to Gitea the server you must also give us
|
error, show us the javascript console. If the error appears to relate to Gitea the server you must also give us
|
||||||
DEBUG level logs. (See https://docs.gitea.com/administration/logging-config#collecting-logs-for-help)
|
DEBUG level logs. (See https://docs.gitea.io/en-us/logging-configuration/#debugging-problems)
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description
|
id: description
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
23
.github/lock.yml
vendored
Normal file
23
.github/lock.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app
|
||||||
|
|
||||||
|
# Number of days of inactivity before a closed issue or pull request is locked
|
||||||
|
daysUntilLock: 60
|
||||||
|
|
||||||
|
# Skip issues and pull requests created before a given timestamp. Timestamp must
|
||||||
|
# follow ISO 8601 (`YYYY-MM-DD`). `false` is disabled
|
||||||
|
skipCreatedBefore: false
|
||||||
|
|
||||||
|
# Issues and pull requests with these labels will be ignored.
|
||||||
|
exemptLabels: []
|
||||||
|
|
||||||
|
# Label to add before locking, such as `outdated`. `false` is disabled
|
||||||
|
lockLabel: false
|
||||||
|
|
||||||
|
# Comment to post before locking.
|
||||||
|
lockComment: >
|
||||||
|
This thread has been automatically locked since there has not been
|
||||||
|
any recent activity after it was closed. Please open a new issue for
|
||||||
|
related bugs and link to relevant comments in this thread.
|
||||||
|
|
||||||
|
# Assign `resolved` as the reason for locking. Set to `false` to disable
|
||||||
|
setLockReason: true
|
||||||
28
.github/workflows/cron-licenses.yml
vendored
28
.github/workflows/cron-licenses.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
name: cron-licenses
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "7 0 * * 1" # every Monday at 00:07 UTC
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cron-licenses:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository == 'go-gitea/gitea'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20.1"
|
|
||||||
- run: make generate-license generate-gitignore
|
|
||||||
timeout-minutes: 40
|
|
||||||
- name: push translations to repo
|
|
||||||
uses: appleboy/git-push-action@v0.0.2
|
|
||||||
with:
|
|
||||||
author_email: "teabot@gitea.io"
|
|
||||||
author_name: GiteaBot
|
|
||||||
branch: main
|
|
||||||
commit: true
|
|
||||||
commit_message: "[skip ci] Updated licenses and gitignores"
|
|
||||||
remote: "git@github.com:go-gitea/gitea.git"
|
|
||||||
ssh_key: ${{ secrets.DEPLOY_KEY }}
|
|
||||||
22
.github/workflows/cron-lock.yml
vendored
22
.github/workflows/cron-lock.yml
vendored
@@ -1,22 +0,0 @@
|
|||||||
name: cron-lock
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * *" # every day at 00:00 UTC
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: lock
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
action:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository == 'go-gitea/gitea'
|
|
||||||
steps:
|
|
||||||
- uses: dessant/lock-threads@v4
|
|
||||||
with:
|
|
||||||
issue-inactive-days: 45
|
|
||||||
49
.github/workflows/cron-translations.yml
vendored
49
.github/workflows/cron-translations.yml
vendored
@@ -1,49 +0,0 @@
|
|||||||
name: cron-translations
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "7 0 * * *" # every day at 00:07 UTC
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
crowdin-pull:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository == 'go-gitea/gitea'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: download from crowdin
|
|
||||||
uses: docker://jonasfranz/crowdin
|
|
||||||
env:
|
|
||||||
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
|
|
||||||
uses: appleboy/git-push-action@v0.0.2
|
|
||||||
with:
|
|
||||||
author_email: "teabot@gitea.io"
|
|
||||||
author_name: GiteaBot
|
|
||||||
branch: main
|
|
||||||
commit: true
|
|
||||||
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@v3
|
|
||||||
- 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
|
|
||||||
53
.github/workflows/files-changed.yml
vendored
53
.github/workflows/files-changed.yml
vendored
@@ -1,53 +0,0 @@
|
|||||||
name: files-changed
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
outputs:
|
|
||||||
backend:
|
|
||||||
description: "whether backend files changed"
|
|
||||||
value: ${{ jobs.detect.outputs.backend }}
|
|
||||||
frontend:
|
|
||||||
description: "whether frontend files changed"
|
|
||||||
value: ${{ jobs.detect.outputs.frontend }}
|
|
||||||
docs:
|
|
||||||
description: "whether docs files changed"
|
|
||||||
value: ${{ jobs.detect.outputs.docs }}
|
|
||||||
actions:
|
|
||||||
description: "whether actions files changed"
|
|
||||||
value: ${{ jobs.detect.outputs.actions }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
detect:
|
|
||||||
name: detect which files changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 3
|
|
||||||
# Map a step output to a job output
|
|
||||||
outputs:
|
|
||||||
backend: ${{ steps.changes.outputs.backend }}
|
|
||||||
frontend: ${{ steps.changes.outputs.frontend }}
|
|
||||||
docs: ${{ steps.changes.outputs.docs }}
|
|
||||||
actions: ${{ steps.changes.outputs.actions }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: dorny/paths-filter@v2
|
|
||||||
id: changes
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
backend:
|
|
||||||
- "**/*.go"
|
|
||||||
- "**/*.tmpl"
|
|
||||||
- "go.mod"
|
|
||||||
- "go.sum"
|
|
||||||
|
|
||||||
frontend:
|
|
||||||
- "**/*.js"
|
|
||||||
- "web_src/**"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
|
|
||||||
docs:
|
|
||||||
- "**/*.md"
|
|
||||||
- "docs/**"
|
|
||||||
|
|
||||||
actions:
|
|
||||||
- ".github/workflows/*"
|
|
||||||
140
.github/workflows/pull-compliance.yml
vendored
140
.github/workflows/pull-compliance.yml
vendored
@@ -1,140 +0,0 @@
|
|||||||
name: compliance
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
files-changed:
|
|
||||||
uses: ./.github/workflows/files-changed.yml
|
|
||||||
|
|
||||||
lint-backend:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20"
|
|
||||||
check-latest: true
|
|
||||||
- run: make deps-backend deps-tools
|
|
||||||
- run: make lint-backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
|
||||||
|
|
||||||
lint-go-windows:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20"
|
|
||||||
check-latest: true
|
|
||||||
- run: make deps-backend deps-tools
|
|
||||||
- run: make lint-go-windows lint-go-vet
|
|
||||||
env:
|
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
|
||||||
GOOS: windows
|
|
||||||
GOARCH: amd64
|
|
||||||
|
|
||||||
lint-go-gogit:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20"
|
|
||||||
check-latest: true
|
|
||||||
- run: make deps-backend deps-tools
|
|
||||||
- run: make lint-go
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
|
||||||
|
|
||||||
checks-backend:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20"
|
|
||||||
check-latest: true
|
|
||||||
- run: make deps-backend deps-tools
|
|
||||||
- run: make --always-make checks-backend # ensure the "go-licenses" make target runs
|
|
||||||
|
|
||||||
frontend:
|
|
||||||
if: needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend
|
|
||||||
- run: make lint-frontend
|
|
||||||
- run: make checks-frontend
|
|
||||||
- run: make frontend
|
|
||||||
|
|
||||||
backend:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20"
|
|
||||||
check-latest: true
|
|
||||||
# no frontend build here as backend should be able to build
|
|
||||||
# even without any frontend files
|
|
||||||
- run: make deps-backend deps-tools
|
|
||||||
- run: go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
|
|
||||||
- name: build-backend-arm64
|
|
||||||
run: make backend # test cross compile
|
|
||||||
env:
|
|
||||||
GOOS: linux
|
|
||||||
GOARCH: arm64
|
|
||||||
TAGS: bindata gogit
|
|
||||||
- name: build-backend-windows
|
|
||||||
run: go build -o gitea_windows
|
|
||||||
env:
|
|
||||||
GOOS: windows
|
|
||||||
GOARCH: amd64
|
|
||||||
TAGS: bindata gogit
|
|
||||||
- name: build-backend-386
|
|
||||||
run: go build -o gitea_linux_386 # test if compatible with 32 bit
|
|
||||||
env:
|
|
||||||
GOOS: linux
|
|
||||||
GOARCH: 386
|
|
||||||
|
|
||||||
docs:
|
|
||||||
if: needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend
|
|
||||||
- run: make lint-md
|
|
||||||
- run: make docs # test if build could succeed
|
|
||||||
|
|
||||||
actions:
|
|
||||||
if: needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
- run: make lint-actions
|
|
||||||
247
.github/workflows/pull-db-tests.yml
vendored
247
.github/workflows/pull-db-tests.yml
vendored
@@ -1,247 +0,0 @@
|
|||||||
name: db-tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
files-changed:
|
|
||||||
uses: ./.github/workflows/files-changed.yml
|
|
||||||
|
|
||||||
test-pgsql:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
pgsql:
|
|
||||||
image: postgres:15
|
|
||||||
env:
|
|
||||||
POSTGRES_DB: test
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
ports:
|
|
||||||
- "5432:5432"
|
|
||||||
ldap:
|
|
||||||
image: gitea/test-openldap:latest
|
|
||||||
ports:
|
|
||||||
- "389:389"
|
|
||||||
- "636:636"
|
|
||||||
minio:
|
|
||||||
# as github actions doesn't support "entrypoint", we need to use a non-official image
|
|
||||||
# that has a custom entrypoint set to "minio server /data"
|
|
||||||
image: bitnami/minio:2021.3.17
|
|
||||||
env:
|
|
||||||
MINIO_ACCESS_KEY: 123456
|
|
||||||
MINIO_SECRET_KEY: 12345678
|
|
||||||
ports:
|
|
||||||
- "9000:9000"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20.0"
|
|
||||||
- name: Add hosts to /etc/hosts
|
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts'
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- run: make test-pgsql-migration test-pgsql
|
|
||||||
timeout-minutes: 50
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit
|
|
||||||
RACE_ENABLED: true
|
|
||||||
TEST_TAGS: gogit
|
|
||||||
TEST_LDAP: 1
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
||||||
|
|
||||||
test-sqlite:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20.0"
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
|
||||||
- run: make test-sqlite-migration test-sqlite
|
|
||||||
timeout-minutes: 50
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
|
||||||
RACE_ENABLED: true
|
|
||||||
TEST_TAGS: gogit sqlite sqlite_unlock_notify
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
||||||
|
|
||||||
test-unit:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
mysql:
|
|
||||||
image: mysql:5.7
|
|
||||||
env:
|
|
||||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
|
||||||
MYSQL_DATABASE: test
|
|
||||||
ports:
|
|
||||||
- "3306:3306"
|
|
||||||
elasticsearch:
|
|
||||||
image: elasticsearch:7.5.0
|
|
||||||
env:
|
|
||||||
discovery.type: single-node
|
|
||||||
ports:
|
|
||||||
- "9200:9200"
|
|
||||||
smtpimap:
|
|
||||||
image: tabascoterrier/docker-imap-devel:latest
|
|
||||||
ports:
|
|
||||||
- "25:25"
|
|
||||||
- "143:143"
|
|
||||||
- "587:587"
|
|
||||||
- "993:993"
|
|
||||||
redis:
|
|
||||||
image: redis
|
|
||||||
options: >- # wait until redis has started
|
|
||||||
--health-cmd "redis-cli ping"
|
|
||||||
--health-interval 5s
|
|
||||||
--health-timeout 3s
|
|
||||||
--health-retries 10
|
|
||||||
ports:
|
|
||||||
- 6379:6379
|
|
||||||
minio:
|
|
||||||
image: bitnami/minio:2021.3.17
|
|
||||||
env:
|
|
||||||
MINIO_ACCESS_KEY: 123456
|
|
||||||
MINIO_SECRET_KEY: 12345678
|
|
||||||
ports:
|
|
||||||
- "9000:9000"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20.0"
|
|
||||||
- name: Add hosts to /etc/hosts
|
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts'
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- name: unit-tests
|
|
||||||
run: make unit-test-coverage test-check
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
RACE_ENABLED: true
|
|
||||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
|
||||||
- name: unit-tests-gogit
|
|
||||||
run: make unit-test-coverage test-check
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit
|
|
||||||
RACE_ENABLED: true
|
|
||||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
|
||||||
|
|
||||||
test-mysql5:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
mysql:
|
|
||||||
image: mysql:5.7
|
|
||||||
env:
|
|
||||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
|
||||||
MYSQL_DATABASE: test
|
|
||||||
ports:
|
|
||||||
- "3306:3306"
|
|
||||||
elasticsearch:
|
|
||||||
image: elasticsearch:7.5.0
|
|
||||||
env:
|
|
||||||
discovery.type: single-node
|
|
||||||
ports:
|
|
||||||
- "9200:9200"
|
|
||||||
smtpimap:
|
|
||||||
image: tabascoterrier/docker-imap-devel:latest
|
|
||||||
ports:
|
|
||||||
- "25:25"
|
|
||||||
- "143:143"
|
|
||||||
- "587:587"
|
|
||||||
- "993:993"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20.0"
|
|
||||||
- name: Add hosts to /etc/hosts
|
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts'
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- name: run tests
|
|
||||||
run: make test-mysql-migration integration-test-coverage
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
RACE_ENABLED: true
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
||||||
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
|
|
||||||
|
|
||||||
test-mysql8:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
mysql8:
|
|
||||||
image: mysql:8
|
|
||||||
env:
|
|
||||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
|
||||||
MYSQL_DATABASE: testgitea
|
|
||||||
ports:
|
|
||||||
- "3306:3306"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20.0"
|
|
||||||
- name: Add hosts to /etc/hosts
|
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql8" | sudo tee -a /etc/hosts'
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- run: make test-mysql8-migration test-mysql8
|
|
||||||
timeout-minutes: 50
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
||||||
|
|
||||||
test-mssql:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
mssql:
|
|
||||||
image: mcr.microsoft.com/mssql/server:latest
|
|
||||||
env:
|
|
||||||
ACCEPT_EULA: Y
|
|
||||||
MSSQL_PID: Standard
|
|
||||||
SA_PASSWORD: MwantsaSecurePassword1
|
|
||||||
ports:
|
|
||||||
- "1433:1433"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20.0"
|
|
||||||
- name: Add hosts to /etc/hosts
|
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mssql" | sudo tee -a /etc/hosts'
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- run: make test-mssql-migration test-mssql
|
|
||||||
timeout-minutes: 50
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
||||||
23
.github/workflows/pull-docker-dryrun.yml
vendored
23
.github/workflows/pull-docker-dryrun.yml
vendored
@@ -1,23 +0,0 @@
|
|||||||
name: docker-dryrun
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
files-changed:
|
|
||||||
uses: ./.github/workflows/files-changed.yml
|
|
||||||
|
|
||||||
docker-dryrun:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: docker/setup-buildx-action@v2
|
|
||||||
- uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
push: false
|
|
||||||
tags: gitea/gitea:linux-amd64
|
|
||||||
32
.github/workflows/pull-e2e-tests.yml
vendored
32
.github/workflows/pull-e2e-tests.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
name: e2e-tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
files-changed:
|
|
||||||
uses: ./.github/workflows/files-changed.yml
|
|
||||||
|
|
||||||
test-e2e:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20"
|
|
||||||
check-latest: true
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend frontend deps-backend
|
|
||||||
- run: npx playwright install --with-deps
|
|
||||||
- run: make test-e2e-sqlite
|
|
||||||
timeout-minutes: 40
|
|
||||||
env:
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
||||||
92
.github/workflows/release-nightly.yml
vendored
92
.github/workflows/release-nightly.yml
vendored
@@ -1,92 +0,0 @@
|
|||||||
name: release-nightly-assets
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ main, release/v* ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
nightly-binary:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
|
||||||
- run: git fetch --unshallow --quiet --tags --force
|
|
||||||
- uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: ">=1.20"
|
|
||||||
check-latest: true
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend deps-backend
|
|
||||||
# xgo build
|
|
||||||
- run: make release
|
|
||||||
env:
|
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
|
||||||
- name: import gpg key
|
|
||||||
id: import_gpg
|
|
||||||
uses: crazy-max/ghaction-import-gpg@v5
|
|
||||||
with:
|
|
||||||
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
|
||||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
|
||||||
- name: sign binaries
|
|
||||||
run: |
|
|
||||||
for f in dist/release/*; do
|
|
||||||
echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f"
|
|
||||||
done
|
|
||||||
# clean branch name to get the folder name in S3
|
|
||||||
- name: Get cleaned branch name
|
|
||||||
id: clean_name
|
|
||||||
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"
|
|
||||||
- name: upload binaries to s3
|
|
||||||
uses: jakejarvis/s3-sync-action@master
|
|
||||||
env:
|
|
||||||
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
AWS_REGION: ${{ secrets.AWS_REGION }}
|
|
||||||
SOURCE_DIR: dist/release
|
|
||||||
DEST_DIR: gitea/${{ steps.clean_name.outputs.branch }}
|
|
||||||
nightly-docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
|
||||||
- run: git fetch --unshallow --quiet --tags --force
|
|
||||||
- uses: docker/setup-qemu-action@v2
|
|
||||||
- uses: docker/setup-buildx-action@v2
|
|
||||||
- name: Get cleaned branch name
|
|
||||||
id: clean_name
|
|
||||||
run: |
|
|
||||||
# if main then say nightly otherwise cleanup name
|
|
||||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
|
||||||
echo "branch=nightly" >> "$GITHUB_OUTPUT"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
|
|
||||||
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: build rootful docker image
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: gitea/gitea:${{ steps.clean_name.outputs.branch }}
|
|
||||||
- name: build rootless docker image
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
file: Dockerfile.rootless
|
|
||||||
tags: gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless
|
|
||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -16,6 +16,10 @@ _test
|
|||||||
.vscode
|
.vscode
|
||||||
__debug_bin
|
__debug_bin
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
*.cgo1.go
|
*.cgo1.go
|
||||||
*.cgo2.c
|
*.cgo2.c
|
||||||
_cgo_defun.c
|
_cgo_defun.c
|
||||||
@@ -43,7 +47,6 @@ cpu.out
|
|||||||
|
|
||||||
*.db
|
*.db
|
||||||
*.log
|
*.log
|
||||||
*.log.*.gz
|
|
||||||
|
|
||||||
/gitea
|
/gitea
|
||||||
/gitea-vet
|
/gitea-vet
|
||||||
@@ -53,6 +56,8 @@ cpu.out
|
|||||||
/bin
|
/bin
|
||||||
/dist
|
/dist
|
||||||
/custom/*
|
/custom/*
|
||||||
|
!/custom/conf
|
||||||
|
/custom/conf/*
|
||||||
!/custom/conf/app.example.ini
|
!/custom/conf/app.example.ini
|
||||||
/data
|
/data
|
||||||
/indexers
|
/indexers
|
||||||
@@ -66,12 +71,12 @@ cpu.out
|
|||||||
/tests/e2e/test-artifacts
|
/tests/e2e/test-artifacts
|
||||||
/tests/e2e/test-snapshots
|
/tests/e2e/test-snapshots
|
||||||
/tests/*.ini
|
/tests/*.ini
|
||||||
/tests/**/*.git/**/*.sample
|
|
||||||
/node_modules
|
/node_modules
|
||||||
/yarn.lock
|
/yarn.lock
|
||||||
/yarn-error.log
|
/yarn-error.log
|
||||||
/npm-debug.log*
|
/npm-debug.log*
|
||||||
/public/js
|
/public/js
|
||||||
|
/public/serviceworker.js
|
||||||
/public/css
|
/public/css
|
||||||
/public/fonts
|
/public/fonts
|
||||||
/public/img/webpack
|
/public/img/webpack
|
||||||
|
|||||||
17
.gitpod.yml
17
.gitpod.yml
@@ -10,12 +10,9 @@ tasks:
|
|||||||
- name: Run backend
|
- name: Run backend
|
||||||
command: |
|
command: |
|
||||||
gp sync-await setup
|
gp sync-await setup
|
||||||
if [ ! -f custom/conf/app.ini ]
|
mkdir -p custom/conf/
|
||||||
then
|
echo -e "[server]\nROOT_URL=$(gp url 3000)/" > custom/conf/app.ini
|
||||||
mkdir -p custom/conf/
|
echo -e "\n[database]\nDB_TYPE = sqlite3\nPATH = $GITPOD_REPO_ROOT/data/gitea.db" >> custom/conf/app.ini
|
||||||
echo -e "[server]\nROOT_URL=$(gp url 3000)/" > custom/conf/app.ini
|
|
||||||
echo -e "\n[database]\nDB_TYPE = sqlite3\nPATH = $GITPOD_REPO_ROOT/data/gitea.db" >> custom/conf/app.ini
|
|
||||||
fi
|
|
||||||
export TAGS="sqlite sqlite_unlock_notify"
|
export TAGS="sqlite sqlite_unlock_notify"
|
||||||
make watch-backend
|
make watch-backend
|
||||||
- name: Run frontend
|
- name: Run frontend
|
||||||
@@ -23,6 +20,10 @@ tasks:
|
|||||||
gp sync-await setup
|
gp sync-await setup
|
||||||
make watch-frontend
|
make watch-frontend
|
||||||
openMode: split-right
|
openMode: split-right
|
||||||
|
- name: Run docs
|
||||||
|
before: sudo bash -c "$(grep 'https://github.com/gohugoio/hugo/releases/download' Makefile | tr -d '\')" # install hugo
|
||||||
|
command: cd docs && make clean update && hugo server -D -F --baseUrl $(gp url 1313) --liveReloadPort=443 --appendPort=false --bind=0.0.0.0
|
||||||
|
openMode: split-right
|
||||||
|
|
||||||
vscode:
|
vscode:
|
||||||
extensions:
|
extensions:
|
||||||
@@ -31,7 +32,7 @@ vscode:
|
|||||||
- golang.go
|
- golang.go
|
||||||
- stylelint.vscode-stylelint
|
- stylelint.vscode-stylelint
|
||||||
- DavidAnson.vscode-markdownlint
|
- DavidAnson.vscode-markdownlint
|
||||||
- Vue.volar
|
- johnsoncodehk.volar
|
||||||
- ms-azuretools.vscode-docker
|
- ms-azuretools.vscode-docker
|
||||||
- zixuanchen.vitest-explorer
|
- zixuanchen.vitest-explorer
|
||||||
- alexcvzz.vscode-sqlite
|
- alexcvzz.vscode-sqlite
|
||||||
@@ -39,3 +40,5 @@ vscode:
|
|||||||
ports:
|
ports:
|
||||||
- name: Gitea
|
- name: Gitea
|
||||||
port: 3000
|
port: 3000
|
||||||
|
- name: Docs
|
||||||
|
port: 1313
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ linters:
|
|||||||
- depguard
|
- depguard
|
||||||
- dupl
|
- dupl
|
||||||
- errcheck
|
- errcheck
|
||||||
- forbidigo
|
|
||||||
- gocritic
|
- gocritic
|
||||||
# - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
|
# - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
|
||||||
- gofmt
|
- gofmt
|
||||||
@@ -23,7 +22,7 @@ linters:
|
|||||||
- unconvert
|
- unconvert
|
||||||
- unused
|
- unused
|
||||||
# - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
|
# - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
|
||||||
- wastedassign
|
# - wastedassign # disabled - https://github.com/golangci/golangci-lint/issues/2649
|
||||||
enable-all: false
|
enable-all: false
|
||||||
disable-all: true
|
disable-all: true
|
||||||
fast: false
|
fast: false
|
||||||
@@ -86,7 +85,6 @@ linters-settings:
|
|||||||
- io/ioutil: "use os or io instead"
|
- io/ioutil: "use os or io instead"
|
||||||
- golang.org/x/exp: "it's experimental and unreliable."
|
- golang.org/x/exp: "it's experimental and unreliable."
|
||||||
- code.gitea.io/gitea/modules/git/internal: "do not use the internal package, use AddXxx function instead"
|
- code.gitea.io/gitea/modules/git/internal: "do not use the internal package, use AddXxx function instead"
|
||||||
- gopkg.in/ini.v1: "do not use the ini package, use gitea's config system instead"
|
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
max-issues-per-linter: 0
|
max-issues-per-linter: 0
|
||||||
@@ -107,25 +105,73 @@ issues:
|
|||||||
- errcheck
|
- errcheck
|
||||||
- dupl
|
- dupl
|
||||||
- gosec
|
- gosec
|
||||||
- path: cmd
|
|
||||||
linters:
|
|
||||||
- forbidigo
|
|
||||||
- linters:
|
- linters:
|
||||||
- dupl
|
- dupl
|
||||||
text: "webhook"
|
text: "webhook"
|
||||||
- linters:
|
- linters:
|
||||||
- gocritic
|
- gocritic
|
||||||
text: "`ID' should not be capitalized"
|
text: "`ID' should not be capitalized"
|
||||||
|
- path: modules/templates/helper.go
|
||||||
|
linters:
|
||||||
|
- gocritic
|
||||||
- linters:
|
- linters:
|
||||||
- unused
|
- unused
|
||||||
- deadcode
|
- deadcode
|
||||||
text: "swagger"
|
text: "swagger"
|
||||||
|
- path: contrib/pr/checkout.go
|
||||||
|
linters:
|
||||||
|
- errcheck
|
||||||
|
- path: models/issue.go
|
||||||
|
linters:
|
||||||
|
- errcheck
|
||||||
|
- path: models/migrations/
|
||||||
|
linters:
|
||||||
|
- errcheck
|
||||||
|
- path: modules/log/
|
||||||
|
linters:
|
||||||
|
- errcheck
|
||||||
|
- path: routers/api/v1/repo/issue_subscription.go
|
||||||
|
linters:
|
||||||
|
- dupl
|
||||||
|
- path: routers/repo/view.go
|
||||||
|
linters:
|
||||||
|
- dupl
|
||||||
|
- path: models/migrations/
|
||||||
|
linters:
|
||||||
|
- unused
|
||||||
- linters:
|
- linters:
|
||||||
- staticcheck
|
- staticcheck
|
||||||
text: "argument x is overwritten before first use"
|
text: "argument x is overwritten before first use"
|
||||||
|
- path: modules/httplib/httplib.go
|
||||||
|
linters:
|
||||||
|
- staticcheck
|
||||||
|
# Enabling this would require refactoring the methods and how they are called.
|
||||||
|
- path: models/issue_comment_list.go
|
||||||
|
linters:
|
||||||
|
- dupl
|
||||||
|
- path: models/update.go
|
||||||
|
linters:
|
||||||
|
- unused
|
||||||
|
- path: cmd/dump.go
|
||||||
|
linters:
|
||||||
|
- dupl
|
||||||
|
- path: services/webhook/webhook.go
|
||||||
|
linters:
|
||||||
|
- structcheck
|
||||||
- text: "commentFormatting: put a space between `//` and comment text"
|
- text: "commentFormatting: put a space between `//` and comment text"
|
||||||
linters:
|
linters:
|
||||||
- gocritic
|
- gocritic
|
||||||
- text: "exitAfterDefer:"
|
- text: "exitAfterDefer:"
|
||||||
linters:
|
linters:
|
||||||
- gocritic
|
- gocritic
|
||||||
|
- path: modules/graceful/manager_windows.go
|
||||||
|
linters:
|
||||||
|
- staticcheck
|
||||||
|
text: "svc.IsAnInteractiveSession is deprecated: Use IsWindowsService instead."
|
||||||
|
- path: models/user/openid.go
|
||||||
|
linters:
|
||||||
|
- golint
|
||||||
|
- path: models/user/badge.go
|
||||||
|
linters:
|
||||||
|
- revive
|
||||||
|
text: "exported: type name will be used as user.UserBadge by other packages, and that stutters; consider calling this Badge"
|
||||||
|
|||||||
2
.ignore
2
.ignore
@@ -1,8 +1,8 @@
|
|||||||
*.min.css
|
*.min.css
|
||||||
*.min.js
|
*.min.js
|
||||||
/assets/*.json
|
|
||||||
/modules/options/bindata.go
|
/modules/options/bindata.go
|
||||||
/modules/public/bindata.go
|
/modules/public/bindata.go
|
||||||
/modules/templates/bindata.go
|
/modules/templates/bindata.go
|
||||||
|
/public/vendor/plugins
|
||||||
/vendor
|
/vendor
|
||||||
node_modules
|
node_modules
|
||||||
|
|||||||
3
.lgtm
Normal file
3
.lgtm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pattern = "(?)LGTM"
|
||||||
|
self_approval_off = true
|
||||||
|
ignore_maintainers_file = true
|
||||||
1
.npmrc
1
.npmrc
@@ -3,4 +3,3 @@ fund=false
|
|||||||
update-notifier=false
|
update-notifier=false
|
||||||
package-lock=true
|
package-lock=true
|
||||||
save-exact=true
|
save-exact=true
|
||||||
lockfile-version=3
|
|
||||||
|
|||||||
@@ -1,18 +1,12 @@
|
|||||||
plugins:
|
plugins:
|
||||||
- stylelint-declaration-strict-value
|
- stylelint-declaration-strict-value
|
||||||
|
|
||||||
ignoreFiles:
|
|
||||||
- "**/*.go"
|
|
||||||
|
|
||||||
overrides:
|
overrides:
|
||||||
- files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console.css", "font_i18n.css"]
|
- files: ["**/*.less"]
|
||||||
|
customSyntax: postcss-less
|
||||||
|
- files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console/*"]
|
||||||
rules:
|
rules:
|
||||||
scale-unlimited/declaration-strict-value: null
|
scale-unlimited/declaration-strict-value: null
|
||||||
- files: ["**/chroma/*", "**/codemirror/*"]
|
|
||||||
rules:
|
|
||||||
block-no-empty: null
|
|
||||||
- files: ["**/*.vue"]
|
|
||||||
customSyntax: postcss-html
|
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
alpha-value-notation: null
|
alpha-value-notation: null
|
||||||
@@ -80,7 +74,6 @@ rules:
|
|||||||
media-feature-name-no-vendor-prefix: true
|
media-feature-name-no-vendor-prefix: true
|
||||||
media-feature-name-unit-allowed-list: null
|
media-feature-name-unit-allowed-list: null
|
||||||
media-feature-name-value-allowed-list: null
|
media-feature-name-value-allowed-list: null
|
||||||
media-feature-name-value-no-unknown: true
|
|
||||||
media-feature-range-notation: null
|
media-feature-range-notation: null
|
||||||
named-grid-areas-no-invalid: true
|
named-grid-areas-no-invalid: true
|
||||||
no-descending-specificity: null
|
no-descending-specificity: null
|
||||||
@@ -91,7 +84,6 @@ rules:
|
|||||||
no-invalid-position-at-import-rule: null
|
no-invalid-position-at-import-rule: null
|
||||||
no-irregular-whitespace: true
|
no-irregular-whitespace: true
|
||||||
no-unknown-animations: null
|
no-unknown-animations: null
|
||||||
no-unknown-custom-properties: null
|
|
||||||
number-max-precision: null
|
number-max-precision: null
|
||||||
property-allowed-list: null
|
property-allowed-list: null
|
||||||
property-disallowed-list: null
|
property-disallowed-list: null
|
||||||
@@ -99,7 +91,7 @@ rules:
|
|||||||
property-no-vendor-prefix: null
|
property-no-vendor-prefix: null
|
||||||
rule-empty-line-before: null
|
rule-empty-line-before: null
|
||||||
rule-selector-property-disallowed-list: null
|
rule-selector-property-disallowed-list: null
|
||||||
scale-unlimited/declaration-strict-value: [[color, background-color, border-color, font-weight], {ignoreValues: /^(inherit|transparent|unset|initial|currentcolor|none)$/, ignoreFunctions: false, disableFix: true}]
|
scale-unlimited/declaration-strict-value: [color, {ignoreValues: /^(inherit|transparent|unset|initial|currentcolor)$/}]
|
||||||
selector-attribute-name-disallowed-list: null
|
selector-attribute-name-disallowed-list: null
|
||||||
selector-attribute-operator-allowed-list: null
|
selector-attribute-operator-allowed-list: null
|
||||||
selector-attribute-operator-disallowed-list: null
|
selector-attribute-operator-disallowed-list: null
|
||||||
|
|||||||
33
BSDmakefile
33
BSDmakefile
@@ -1,7 +1,6 @@
|
|||||||
# GNU makefile proxy script for BSD make
|
# GNU makefile proxy script for BSD make
|
||||||
#
|
|
||||||
# Written and maintained by Mahmoud Al-Qudsi <mqudsi@neosmart.net>
|
# Written and maintained by Mahmoud Al-Qudsi <mqudsi@neosmart.net>
|
||||||
# Copyright NeoSmart Technologies <https://neosmart.net/> 2014-2019
|
# Copyright NeoSmart Technologies <https://neosmart.net/> 2014-2018
|
||||||
# Obtain updates from <https://github.com/neosmart/gmake-proxy>
|
# Obtain updates from <https://github.com/neosmart/gmake-proxy>
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# Redistribution and use in source and binary forms, with or without
|
||||||
@@ -27,32 +26,26 @@
|
|||||||
|
|
||||||
JARG =
|
JARG =
|
||||||
GMAKE = "gmake"
|
GMAKE = "gmake"
|
||||||
# When gmake is called from another make instance, -w is automatically added
|
#When gmake is called from another make instance, -w is automatically added
|
||||||
# which causes extraneous messages about directory changes to be emitted.
|
#which causes extraneous messages about directory changes to be emitted.
|
||||||
# Running with --no-print-directory silences these messages.
|
#--no-print-directory silences these messages.
|
||||||
GARGS = "--no-print-directory"
|
GARGS = "--no-print-directory"
|
||||||
|
|
||||||
.if "$(.MAKE.JOBS)" != ""
|
.if "$(.MAKE.JOBS)" != ""
|
||||||
JARG = -j$(.MAKE.JOBS)
|
JARG = -j$(.MAKE.JOBS)
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# bmake prefers out-of-source builds and tries to cd into ./obj (among others)
|
#by default bmake will cd into ./obj first
|
||||||
# where possible. GNU Make doesn't, so override that value.
|
|
||||||
.OBJDIR: ./
|
.OBJDIR: ./
|
||||||
|
|
||||||
# The GNU convention is to use the lowercased `prefix` variable/macro to
|
|
||||||
# specify the installation directory. Humor them.
|
|
||||||
GPREFIX = ""
|
|
||||||
.if defined(PREFIX) && ! defined(prefix)
|
|
||||||
GPREFIX = 'prefix = "$(PREFIX)"'
|
|
||||||
.endif
|
|
||||||
|
|
||||||
.BEGIN: .SILENT
|
|
||||||
which $(GMAKE) || printf "Error: GNU Make is required!\n\n" 1>&2 && false
|
|
||||||
|
|
||||||
.PHONY: FRC
|
.PHONY: FRC
|
||||||
$(.TARGETS): FRC
|
$(.TARGETS): FRC
|
||||||
$(GMAKE) $(GPREFIX) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
|
$(GMAKE) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
|
||||||
|
|
||||||
.DONE .DEFAULT: .SILENT
|
.DONE .DEFAULT: .SILENT
|
||||||
$(GMAKE) $(GPREFIX) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
|
$(GMAKE) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
|
||||||
|
|
||||||
|
.ERROR: .SILENT
|
||||||
|
if ! which $(GMAKE) > /dev/null; then \
|
||||||
|
echo "GNU Make is required!"; \
|
||||||
|
fi
|
||||||
|
|||||||
1809
CHANGELOG.md
1809
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -1,96 +0,0 @@
|
|||||||
# Gitea Community Code of Conduct
|
|
||||||
|
|
||||||
## About
|
|
||||||
|
|
||||||
Online communities include people from many different backgrounds. The Gitea contributors are committed to providing a friendly, safe and welcoming environment for all, regardless of gender identity and expression, sexual orientation, disabilities, neurodiversity, physical appearance, body size, ethnicity, nationality, race, age, religion, or similar personal characteristics.
|
|
||||||
|
|
||||||
The first goal of the Code of Conduct is to specify a baseline standard of behavior so that people with different social values and communication styles can talk about Gitea effectively, productively, and respectfully.
|
|
||||||
|
|
||||||
The second goal is to provide a mechanism for resolving conflicts in the community when they arise.
|
|
||||||
|
|
||||||
The third goal of the Code of Conduct is to make our community welcoming to people from different backgrounds. Diversity is critical to the project; for Gitea to be successful, it needs contributors and users from all backgrounds.
|
|
||||||
|
|
||||||
We believe that healthy debate and disagreement are essential to a healthy project and community. However, it is never ok to be disrespectful. We value diverse opinions, but we value respectful behavior more.
|
|
||||||
|
|
||||||
## Community values
|
|
||||||
|
|
||||||
These are the values to which people in the Gitea community should aspire.
|
|
||||||
|
|
||||||
- **Be friendly and welcoming.**
|
|
||||||
- **Be patient.**
|
|
||||||
- Remember that people have varying communication styles and that not everyone is using their native language. (Meaning and tone can be lost in translation.)
|
|
||||||
- **Be thoughtful.**
|
|
||||||
- Productive communication requires effort. Think about how your words will be interpreted.
|
|
||||||
- Remember that sometimes it is best to refrain entirely from commenting.
|
|
||||||
- **Be respectful.**
|
|
||||||
- In particular, respect differences of opinion.
|
|
||||||
- **Be charitable.**
|
|
||||||
- Interpret the arguments of others in good faith, do not seek to disagree.
|
|
||||||
- When we do disagree, try to understand why.
|
|
||||||
- **Be constructive.**
|
|
||||||
- Avoid derailing: stay on topic; if you want to talk about something else, start a new conversation.
|
|
||||||
- Avoid unconstructive criticism: don't merely decry the current state of affairs; offer—or at least solicit—suggestions as to how things may be improved.
|
|
||||||
- Avoid snarking (pithy, unproductive, sniping comments)
|
|
||||||
- Avoid discussing potentially offensive or sensitive issues; this all too often leads to unnecessary conflict.
|
|
||||||
- Avoid microaggressions (brief and commonplace verbal, behavioral and environmental indignities that communicate hostile, derogatory or negative slights and insults to a person or group).
|
|
||||||
- **Be responsible.**
|
|
||||||
- What you say and do matters. Take responsibility for your words and actions, including their consequences, whether intended or otherwise.
|
|
||||||
|
|
||||||
People are complicated. You should expect to be misunderstood and to misunderstand others; when this inevitably occurs, resist the urge to be defensive or assign blame. Try not to take offense where no offense was intended. Give people the benefit of the doubt. Even if the intent was to provoke, do not rise to it. It is the responsibility of all parties to de-escalate conflict when it arises.
|
|
||||||
|
|
||||||
## Code of Conduct
|
|
||||||
|
|
||||||
### Our Pledge
|
|
||||||
|
|
||||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
||||||
|
|
||||||
### Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to creating a positive environment include:
|
|
||||||
|
|
||||||
- Using welcoming and inclusive language
|
|
||||||
- Being respectful of differing viewpoints and experiences
|
|
||||||
- Gracefully accepting constructive criticism
|
|
||||||
- Focusing on what is best for the community
|
|
||||||
- Showing empathy towards other community members
|
|
||||||
|
|
||||||
Examples of unacceptable behavior by participants include:
|
|
||||||
|
|
||||||
- The use of sexualized language or imagery and unwelcome sexual attention or advances
|
|
||||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
|
||||||
- Public or private harassment
|
|
||||||
- Publishing others’ private information, such as a physical or electronic address, without explicit permission
|
|
||||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
||||||
|
|
||||||
### Our Responsibilities
|
|
||||||
|
|
||||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
|
||||||
|
|
||||||
Project maintainers have the right and responsibility to remove, edit, or reject: comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, as well as to ban (temporarily or permanently) any contributor for behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
|
||||||
|
|
||||||
### Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
|
||||||
|
|
||||||
This Code of Conduct also applies outside the project spaces when the Project Stewards have a reasonable belief that an individual’s behavior may have a negative impact on the project or its community.
|
|
||||||
|
|
||||||
### Conflict Resolution
|
|
||||||
|
|
||||||
We do not believe that all conflict is bad; healthy debate and disagreement often yield positive results. However, it is never okay to be disrespectful or to engage in behavior that violates the project’s code of conduct.
|
|
||||||
|
|
||||||
If you see someone violating the code of conduct, you are encouraged to address the behavior directly with those involved. Many issues can be resolved quickly and easily, and this gives people more control over the outcome of their dispute. If you are unable to resolve the matter for any reason, or if the behavior is threatening or harassing, report it. We are dedicated to providing an environment where participants feel welcome and safe.
|
|
||||||
|
|
||||||
Reports should be directed to the Gitea Project Stewards at conduct@gitea.com. It is the Project Stewards’ duty to receive and address reported violations of the code of conduct. They will then work with a committee consisting of representatives from the technical-oversight-committee.
|
|
||||||
|
|
||||||
We will investigate every complaint, but you may not receive a direct response. We will use our discretion in determining when and how to follow up on reported incidents, which may range from not taking action to permanent expulsion from the project and project-sponsored spaces. Under normal circumstances, we will notify the accused of the report and provide them an opportunity to discuss it before any action is taken. If there is a consensus between maintainers that such an endeavor would be useless (i.e. in case of an obvious spammer), we reserve the right to take action without notifying the accused first. The identity of the reporter will be omitted from the details of the report supplied to the accused. In potentially harmful situations, such as ongoing harassment or threats to anyone’s safety, we may take action without notice.
|
|
||||||
|
|
||||||
### Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
- Treat everyone with respect and kindness.
|
|
||||||
- Be thoughtful in how you communicate.
|
|
||||||
- Don’t be destructive or inflammatory.
|
|
||||||
- If you encounter an issue, please mail conduct@gitea.com.
|
|
||||||
658
CONTRIBUTING.md
658
CONTRIBUTING.md
@@ -1,157 +1,75 @@
|
|||||||
# Contribution Guidelines
|
# Contribution Guidelines
|
||||||
|
|
||||||
<details><summary>Table of Contents</summary>
|
## Table of Contents
|
||||||
|
|
||||||
- [Contribution Guidelines](#contribution-guidelines)
|
- [Contribution Guidelines](#contribution-guidelines)
|
||||||
|
- [Table of Contents](#table-of-contents)
|
||||||
- [Introduction](#introduction)
|
- [Introduction](#introduction)
|
||||||
- [Issues](#issues)
|
- [Bug reports](#bug-reports)
|
||||||
- [How to report issues](#how-to-report-issues)
|
- [Discuss your design](#discuss-your-design)
|
||||||
- [Types of issues](#types-of-issues)
|
- [Testing redux](#testing-redux)
|
||||||
- [Discuss your design before the implementation](#discuss-your-design-before-the-implementation)
|
- [Vendoring](#vendoring)
|
||||||
- [Building Gitea](#building-gitea)
|
|
||||||
- [Dependencies](#dependencies)
|
|
||||||
- [Backend](#backend)
|
|
||||||
- [Frontend](#frontend)
|
|
||||||
- [Design guideline](#design-guideline)
|
|
||||||
- [Styleguide](#styleguide)
|
|
||||||
- [Copyright](#copyright)
|
|
||||||
- [Testing](#testing)
|
|
||||||
- [Translation](#translation)
|
- [Translation](#translation)
|
||||||
|
- [Building Gitea](#building-gitea)
|
||||||
- [Code review](#code-review)
|
- [Code review](#code-review)
|
||||||
- [Pull request format](#pull-request-format)
|
- [Styleguide](#styleguide)
|
||||||
- [PR title and summary](#pr-title-and-summary)
|
- [Design guideline](#design-guideline)
|
||||||
- [Milestone](#milestone)
|
|
||||||
- [Labels](#labels)
|
|
||||||
- [Breaking PRs](#breaking-prs)
|
|
||||||
- [What is a breaking PR?](#what-is-a-breaking-pr)
|
|
||||||
- [How to handle breaking PRs?](#how-to-handle-breaking-prs)
|
|
||||||
- [Maintaining open PRs](#maintaining-open-prs)
|
|
||||||
- [Getting PRs merged](#getting-prs-merged)
|
|
||||||
- [Final call](#final-call)
|
|
||||||
- [Commit messages](#commit-messages)
|
|
||||||
- [PR Co-authors](#pr-co-authors)
|
|
||||||
- [PRs targeting `main`](#prs-targeting-main)
|
|
||||||
- [Backport PRs](#backport-prs)
|
|
||||||
- [Documentation](#documentation)
|
|
||||||
- [API v1](#api-v1)
|
- [API v1](#api-v1)
|
||||||
- [GitHub API compatibility](#github-api-compatibility)
|
|
||||||
- [Adding/Maintaining API routes](#addingmaintaining-api-routes)
|
|
||||||
- [When to use what HTTP method](#when-to-use-what-http-method)
|
|
||||||
- [Requirements for API routes](#requirements-for-api-routes)
|
|
||||||
- [Backports and Frontports](#backports-and-frontports)
|
|
||||||
- [What is backported?](#what-is-backported)
|
|
||||||
- [How to backport?](#how-to-backport)
|
|
||||||
- [Format of backport PRs](#format-of-backport-prs)
|
|
||||||
- [Frontports](#frontports)
|
|
||||||
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
|
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
|
||||||
- [Release Cycle](#release-cycle)
|
- [Release Cycle](#release-cycle)
|
||||||
- [Maintainers](#maintainers)
|
- [Maintainers](#maintainers)
|
||||||
- [Technical Oversight Committee (TOC)](#technical-oversight-committee-toc)
|
- [Owners](#owners)
|
||||||
- [Current TOC members](#current-toc-members)
|
|
||||||
- [Previous TOC/owners members](#previous-tocowners-members)
|
|
||||||
- [Governance Compensation](#governance-compensation)
|
|
||||||
- [TOC \& Working groups](#toc--working-groups)
|
|
||||||
- [Roadmap](#roadmap)
|
|
||||||
- [Versions](#versions)
|
- [Versions](#versions)
|
||||||
- [Releasing Gitea](#releasing-gitea)
|
- [Releasing Gitea](#releasing-gitea)
|
||||||
|
- [Copyright](#copyright)
|
||||||
</details>
|
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
This document explains how to contribute changes to the Gitea project. \
|
This document explains how to contribute changes to the Gitea project.
|
||||||
It assumes you have followed the [installation instructions](https://docs.gitea.com/category/installation). \
|
It assumes you have followed the
|
||||||
Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io).
|
[installation instructions](https://docs.gitea.io/en-us/).
|
||||||
|
Sensitive security-related issues should be reported to
|
||||||
|
[security@gitea.io](mailto:security@gitea.io).
|
||||||
|
|
||||||
For configuring IDEs for Gitea development, see the [contributed IDE configurations](contrib/ide/).
|
For configuring IDE or code editor to develop Gitea see [IDE and code editor configuration](contrib/ide/)
|
||||||
|
|
||||||
## Issues
|
## Bug reports
|
||||||
|
|
||||||
### How to report issues
|
Please search the issues on the issue tracker with a variety of keywords
|
||||||
|
to ensure your bug is not already reported.
|
||||||
|
|
||||||
Please search the issues on the issue tracker with a variety of related keywords to ensure that your issue has not already been reported.
|
If unique, [open an issue](https://github.com/go-gitea/gitea/issues/new)
|
||||||
|
and answer the questions so we can understand and reproduce the
|
||||||
|
problematic behavior.
|
||||||
|
|
||||||
If your issue has not been reported yet, [open an issue](https://github.com/go-gitea/gitea/issues/new)
|
To show us that the issue you are having is in Gitea itself, please
|
||||||
and answer the questions so we can understand and reproduce the problematic behavior. \
|
write clear, concise instructions so we can reproduce the behavior—
|
||||||
Please write clear and concise instructions so that we can reproduce the behavior — even if it seems obvious. \
|
even if it seems obvious. The more detailed and specific you are,
|
||||||
The more detailed and specific you are, the faster we can fix the issue. \
|
the faster we can fix the issue. Check out [How to Report Bugs
|
||||||
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. \
|
Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html).
|
||||||
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.
|
Please be kind, remember that Gitea comes at no cost to you, and you're
|
||||||
|
getting free help.
|
||||||
|
|
||||||
### Types of issues
|
## Discuss your design
|
||||||
|
|
||||||
Typically, issues fall in one of the following categories:
|
The project welcomes submissions. If you want to change or add something,
|
||||||
|
please let everyone know what you're working on—[file an issue](https://github.com/go-gitea/gitea/issues/new)!
|
||||||
|
Significant changes must go through the change proposal process
|
||||||
|
before they can be accepted. To create a proposal, file an issue with
|
||||||
|
your proposed changes documented, and make sure to note in the title
|
||||||
|
of the issue that it is a proposal.
|
||||||
|
|
||||||
- `bug`: Something in the frontend or backend behaves unexpectedly
|
This process gives everyone a chance to validate the design, helps
|
||||||
- `security issue`: bug that has serious implications such as leaking another users data. Please do not file such issues on the public tracker and send a mail to security@gitea.io instead
|
prevent duplication of effort, and ensures that the idea fits inside
|
||||||
- `feature`: Completely new functionality. You should describe this feature in enough detail that anyone who reads the issue can understand how it is supposed to be implemented
|
the goals for the project and tools. It also checks that the design is
|
||||||
- `enhancement`: An existing feature should get an upgrade
|
sound before code is written; the code review tool is not the place for
|
||||||
- `refactoring`: Parts of the code base don't conform with other parts and should be changed to improve Gitea's maintainability
|
high-level discussions.
|
||||||
|
|
||||||
### Discuss your design before the implementation
|
## Testing redux
|
||||||
|
|
||||||
We welcome submissions. \
|
Before submitting a pull request, run all the tests for the whole tree
|
||||||
If you want to change or add something, please let everyone know what you're working on — [file an issue](https://github.com/go-gitea/gitea/issues/new) or comment on an existing one before starting your work!
|
to make sure your changes don't cause regression elsewhere.
|
||||||
|
|
||||||
Significant changes such as new features must go through the change proposal process before they can be accepted. \
|
|
||||||
This is mainly to save yourself the trouble of implementing it, only to find out that your proposed implementation has some potential problems. \
|
|
||||||
Furthermore, this process gives everyone a chance to validate the design, helps prevent duplication of effort, and ensures that the idea fits inside
|
|
||||||
the goals for the project and tools.
|
|
||||||
|
|
||||||
Pull requests should not be the place for architecture discussions.
|
|
||||||
|
|
||||||
## Building Gitea
|
|
||||||
|
|
||||||
See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea).
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
### Backend
|
|
||||||
|
|
||||||
Go dependencies are managed using [Go Modules](https://golang.org/cmd/go/#hdr-Module_maintenance). \
|
|
||||||
You can find more details in the [go mod documentation](https://go.dev/ref/mod) and the [Go Modules Wiki](https://github.com/golang/go/wiki/Modules).
|
|
||||||
|
|
||||||
Pull requests should only modify `go.mod` and `go.sum` where it is related to your change, be it a bugfix or a new feature. \
|
|
||||||
Apart from that, these files should only be modified by Pull Requests whose only purpose is to update dependencies.
|
|
||||||
|
|
||||||
The `go.mod`, `go.sum` update needs to be justified as part of the PR description,
|
|
||||||
and must be verified by the reviewers and/or merger to always reference
|
|
||||||
an existing upstream commit.
|
|
||||||
|
|
||||||
### Frontend
|
|
||||||
|
|
||||||
For the frontend, we use [npm](https://www.npmjs.com/).
|
|
||||||
|
|
||||||
The same restrictions apply for frontend dependencies as for backend dependencies, with the exceptions that the files for it are `package.json` and `package-lock.json`, and that new versions must always reference an existing version.
|
|
||||||
|
|
||||||
## Design guideline
|
|
||||||
|
|
||||||
Depending on your change, please read the
|
|
||||||
|
|
||||||
- [backend development guideline](https://docs.gitea.com/contributing/guidelines-backend)
|
|
||||||
- [frontend development guideline](https://docs.gitea.com/contributing/guidelines-frontend)
|
|
||||||
- [refactoring guideline](https://docs.gitea.com/contributing/guidelines-refactoring)
|
|
||||||
|
|
||||||
## Styleguide
|
|
||||||
|
|
||||||
You should always run `make fmt` before committing to conform to Gitea's styleguide.
|
|
||||||
|
|
||||||
## Copyright
|
|
||||||
|
|
||||||
New code files that you contribute should use the standard copyright header:
|
|
||||||
|
|
||||||
```
|
|
||||||
// Copyright <current year> The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
```
|
|
||||||
|
|
||||||
Afterwards, copyright should only be modified when the copyright author changes.
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
Before submitting a pull request, run all tests to make sure your changes don't cause a regression elsewhere.
|
|
||||||
|
|
||||||
Here's how to run the test suite:
|
Here's how to run the test suite:
|
||||||
|
|
||||||
@@ -159,304 +77,257 @@ Here's how to run the test suite:
|
|||||||
|
|
||||||
| | |
|
| | |
|
||||||
| :-------------------- | :---------------------------------------------------------------- |
|
| :-------------------- | :---------------------------------------------------------------- |
|
||||||
|``make lint`` | lint everything (not needed if you only change the front- **or** backend) |
|
|``make lint`` | lint everything (not suggest if you only change one type code) |
|
||||||
|``make lint-frontend`` | lint frontend files |
|
|``make lint-frontend`` | lint frontend files |
|
||||||
|``make lint-backend`` | lint backend files |
|
|``make lint-backend`` | lint backend files |
|
||||||
|
|
||||||
- run tests (we suggest running them on Linux)
|
- run test code (Suggest run in Linux)
|
||||||
|
|
||||||
| Command | Action | |
|
| | |
|
||||||
| :------------------------------------- | :----------------------------------------------- | ------------ |
|
| :------------------------------------- | :----------------------------------------------- |
|
||||||
|``make test[\#SpecificTestName]`` | run unit test(s) |
|
|``make test[\#TestSpecificName]`` | run unit test |
|
||||||
|``make test-sqlite[\#SpecificTestName]``| run [integration](tests/integration) test(s) for SQLite |[More details](tests/integration/README.md) |
|
|``make test-sqlite[\#TestSpecificName]``| run [integration](tests/integration) test for SQLite |
|
||||||
|``make test-e2e-sqlite[\#SpecificTestName]``| run [end-to-end](tests/e2e) test(s) for SQLite |[More details](tests/e2e/README.md) |
|
|[More details about integration tests](tests/integration/README.md) |
|
||||||
|
|``make test-e2e-sqlite[\#TestSpecificFileName]``| run [end-to-end](tests/e2e) test for SQLite |
|
||||||
|
|[More details about e2e tests](tests/e2e/README.md) |
|
||||||
|
|
||||||
|
## Vendoring
|
||||||
|
|
||||||
|
We manage dependencies via [Go Modules](https://golang.org/cmd/go/#hdr-Module_maintenance), more details: [go mod](https://go.dev/ref/mod).
|
||||||
|
|
||||||
|
Pull requests should only include `go.mod`, `go.sum` updates if they are part of
|
||||||
|
the same change, be it a bugfix or a feature addition.
|
||||||
|
|
||||||
|
The `go.mod`, `go.sum` update needs to be justified as part of the PR description,
|
||||||
|
and must be verified by the reviewers and/or merger to always reference
|
||||||
|
an existing upstream commit.
|
||||||
|
|
||||||
|
You can find more information on how to get started with it on the [Modules Wiki](https://github.com/golang/go/wiki/Modules).
|
||||||
|
|
||||||
## Translation
|
## Translation
|
||||||
|
|
||||||
All translation work happens on [Crowdin](https://crowdin.com/project/gitea).
|
We do all translation work inside [Crowdin](https://crowdin.com/project/gitea).
|
||||||
The only translation that is maintained in this repository is [the English translation](https://github.com/go-gitea/gitea/blob/main/options/locale/locale_en-US.ini).
|
The only translation that is maintained in this Git repository is
|
||||||
It is synced regularly with Crowdin. \
|
[`en_US.ini`](https://github.com/go-gitea/gitea/blob/master/options/locale/locale_en-US.ini)
|
||||||
Other locales on main branch **should not** be updated manually as they will be overwritten with each sync. \
|
and is synced regularly to Crowdin. Once a translation has reached
|
||||||
Once a language has reached a **satisfactory percentage** of translated keys (~25%), it will be synced back into this repo and included in the next released version.
|
A SATISFACTORY PERCENTAGE it will be synced back into this repo and
|
||||||
|
included in the next released version.
|
||||||
|
|
||||||
The tool `go run build/backport-locale.go` can be used to backport locales from the main branch to release branches that were missed.
|
## Building Gitea
|
||||||
|
|
||||||
|
See the [hacking instructions](https://docs.gitea.io/en-us/hacking-on-gitea/).
|
||||||
|
|
||||||
## Code review
|
## Code review
|
||||||
|
|
||||||
### Pull request format
|
Changes to Gitea must be reviewed before they are accepted—no matter who
|
||||||
|
makes the change, even if they are an owner or a maintainer. We use GitHub's
|
||||||
|
pull request workflow to do that. And, we also use [LGTM](http://lgtm.co)
|
||||||
|
to ensure every PR is reviewed by at least 2 maintainers.
|
||||||
|
|
||||||
Please try to make your pull request easy to review for us. \
|
Please try to make your pull request easy to review for us. And, please read
|
||||||
For that, please read the [*Best Practices for Faster Reviews*](https://github.com/kubernetes/community/blob/261cb0fd089b64002c91e8eddceebf032462ccd6/contributors/guide/pull-requests.md#best-practices-for-faster-reviews) guide. \
|
the *[How to get faster PR reviews](https://github.com/kubernetes/community/blob/261cb0fd089b64002c91e8eddceebf032462ccd6/contributors/guide/pull-requests.md#best-practices-for-faster-reviews)* guide;
|
||||||
It has lots of useful tips for any project you may want to contribute to. \
|
it has lots of useful tips for any project you may want to contribute.
|
||||||
Some of the key points:
|
Some of the key points:
|
||||||
|
|
||||||
- Make small pull requests. \
|
- Make small pull requests. The smaller, the faster to review and the
|
||||||
The smaller, the faster to review and the more likely it will be merged soon.
|
more likely it will be merged soon.
|
||||||
- Don't make changes unrelated to your PR. \
|
- Don't make changes unrelated to your PR. Maybe there are typos on
|
||||||
Maybe there are typos on some comments, maybe refactoring would be welcome on a function... \
|
some comments, maybe refactoring would be welcome on a function... but
|
||||||
but if that is not related to your PR, please make *another* PR for that.
|
if that is not related to your PR, please make *another* PR for that.
|
||||||
- Split big pull requests into multiple small ones. \
|
- Split big pull requests into multiple small ones. An incremental change
|
||||||
An incremental change will be faster to review than a huge PR.
|
will be faster to review than a huge PR.
|
||||||
- Allow edits by maintainers. This way, the maintainers will take care of merging the PR later on instead of you.
|
- Use the first comment as a summary explainer of your PR and you should keep this up-to-date as the PR evolves.
|
||||||
|
|
||||||
### PR title and summary
|
If your PR could cause a breaking change you must add a BREAKING section to this comment e.g.:
|
||||||
|
|
||||||
In the PR title, describe the problem you are fixing, not how you are fixing it. \
|
|
||||||
Use the first comment as a summary of your PR. \
|
|
||||||
In the PR summary, you can describe exactly how you are fixing this problem. \
|
|
||||||
Keep this summary up-to-date as the PR evolves. \
|
|
||||||
If your PR changes the UI, you must add **after** screenshots in the PR summary. \
|
|
||||||
If you are not implementing a new feature, you should also post **before** screenshots for comparison. \
|
|
||||||
If your PR closes some issues, you must note that in a way that both GitHub and Gitea understand, i.e. by appending a paragraph like
|
|
||||||
|
|
||||||
```text
|
|
||||||
Fixes/Closes/Resolves #<ISSUE_NR_X>.
|
|
||||||
Fixes/Closes/Resolves #<ISSUE_NR_Y>.
|
|
||||||
```
|
|
||||||
|
|
||||||
to your summary. \
|
|
||||||
Each issue that will be closed must stand on a separate line.
|
|
||||||
|
|
||||||
### Milestone
|
|
||||||
|
|
||||||
A PR should only be assigned to a milestone if it will likely be merged into the given version. \
|
|
||||||
As a rule of thumb, assume that a PR will stay open for an additional month for every 100 added lines. \
|
|
||||||
PRs without a milestone may not be merged.
|
|
||||||
|
|
||||||
### Labels
|
|
||||||
|
|
||||||
Every PR should be labeled correctly with every label that applies. \
|
|
||||||
This includes especially the distinction between `bug` (fixing existing functionality), `feature` (new functionality), `enhancement` (upgrades for existing functionality), and `refactoring` (improving the internal code structure without changing the output (much)). \
|
|
||||||
Furthermore,
|
|
||||||
|
|
||||||
- the amount of pending required approvals
|
|
||||||
- whether this PR is `blocked`, a `backport` or `breaking`
|
|
||||||
- if it targets the `ui` or `api`
|
|
||||||
- if it increases the application `speed`
|
|
||||||
- reduces `memory usage`
|
|
||||||
|
|
||||||
are oftentimes notable labels.
|
|
||||||
|
|
||||||
### Breaking PRs
|
|
||||||
|
|
||||||
#### What is a breaking PR?
|
|
||||||
|
|
||||||
A PR is breaking if it meets one of the following criteria:
|
|
||||||
|
|
||||||
- It changes API output in an incompatible way for existing users
|
|
||||||
- It removes a setting that an admin could previously set (i.e. via `app.ini`)
|
|
||||||
- An admin must do something manually to restore the old behavior
|
|
||||||
|
|
||||||
In particular, this means that adding new settings is not breaking.\
|
|
||||||
Changing the default value of a setting or replacing the setting with another one is breaking, however.
|
|
||||||
|
|
||||||
#### How to handle breaking PRs?
|
|
||||||
|
|
||||||
If your PR has a breaking change, you must add a `BREAKING` section to your PR summary, e.g.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
## :warning: BREAKING :warning:
|
## :warning: BREAKING :warning:
|
||||||
```
|
```
|
||||||
|
|
||||||
To explain how this will affect users and how to mitigate these changes.
|
To explain how this could affect users and how to mitigate these changes.
|
||||||
|
|
||||||
### Maintaining open PRs
|
Once code review starts on your PR, do not rebase nor squash your branch as it makes it
|
||||||
|
difficult to review the new changes. Only if there is a need, sync your branch by merging
|
||||||
|
the base branch into yours. Don't worry about merge commits messing up your tree as
|
||||||
|
the final merge process squashes all commits into one, with the visible commit message (first
|
||||||
|
line) being the PR title + PR index and description being the PR's first comment.
|
||||||
|
|
||||||
The moment you create a non-draft PR or the moment you convert a draft PR to a non-draft PR is the moment code review starts for it. \
|
Once your PR gets the `lgtm/done` label, don't worry about keeping it up-to-date or breaking
|
||||||
Once that happens, do not rebase or squash your branch anymore as it makes it difficult to review the new changes. \
|
builds (unless there's a merge conflict or a request is made by a maintainer to make
|
||||||
Merge the base branch into your branch only when you really need to, i.e. because of conflicting changes in the mean time. \
|
modifications). It is the maintainer team's responsibility from this point to get it merged.
|
||||||
This reduces unnecessary CI runs. \
|
|
||||||
Don't worry about merge commits messing up your commit history as every PR will be squash merged. \
|
|
||||||
This means that all changes are joined into a single new commit whose message is as described below.
|
|
||||||
|
|
||||||
### Getting PRs merged
|
## Styleguide
|
||||||
|
|
||||||
Changes to Gitea must be reviewed before they are accepted — no matter who
|
For imports you should use the following format (*without* the comments)
|
||||||
makes the change, even if they are an owner or a maintainer. \
|
|
||||||
The only exception are critical bugs that prevent Gitea from being compiled or started. \
|
|
||||||
Specifically, we require two approvals from maintainers for every PR. \
|
|
||||||
Once this criteria has been met, your PR receives the `lgtm/done` label. \
|
|
||||||
From this point on, your only responsibility is to fix merge conflicts or respond to/implement requests by maintainers. \
|
|
||||||
It is the responsibility of the maintainers from this point to get your PR merged.
|
|
||||||
|
|
||||||
If a PR has the `lgtm/done` label and there are no open discussions or merge conflicts anymore, any maintainer can add the `reviewed/wait-merge` label. \
|
```go
|
||||||
This label means that the PR is part of the merge queue and will be merged as soon as possible. \
|
import (
|
||||||
The merge queue will be cleared in the order of the list below:
|
// stdlib
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
|
||||||
<https://github.com/go-gitea/gitea/pulls?q=is%3Apr+label%3Areviewed%2Fwait-merge+sort%3Acreated-asc+is%3Aopen>
|
// local packages
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
|
"code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
Gitea uses it's own tool, the <https://github.com/GiteaBot/gitea-backporter> to automate parts of the review process. \
|
// external packages
|
||||||
This tool does the things listed below automatically:
|
"github.com/foo/bar"
|
||||||
|
"gopkg.io/baz.v1"
|
||||||
- create a backport PR if needed once the initial PR was merged
|
)
|
||||||
- remove the PR from the merge queue after the PR merged
|
|
||||||
- keep the oldest branch in the merge queue up to date with merges
|
|
||||||
|
|
||||||
### Final call
|
|
||||||
|
|
||||||
If a PR has been ignored for more than 7 days with no comments or reviews, and the author or any maintainer believes it will not survive a long wait (such as a refactoring PR), they can send "final call" to the TOC by mentioning them in a comment.
|
|
||||||
|
|
||||||
After another 7 days, if there is still zero approval, this is considered a polite refusal, and the PR will be closed to avoid wasting further time. Therefore, the "final call" has a cost, and should be used cautiously.
|
|
||||||
|
|
||||||
However, if there are no objections from maintainers, the PR can be merged with only one approval from the TOC (not the author).
|
|
||||||
|
|
||||||
### Commit messages
|
|
||||||
|
|
||||||
Mergers are able and required to rewrite the PR title and summary (the first comment of a PR) so that it can produce an easily understandable commit message if necessary. \
|
|
||||||
The final commit message should no longer contain any uncertainty such as `hopefully, <x> won't happen anymore`. Replace uncertainty with certainty.
|
|
||||||
|
|
||||||
#### PR Co-authors
|
|
||||||
|
|
||||||
A person counts as a PR co-author the moment they (co-)authored a commit that is not simply a `Merge base branch into branch` commit. \
|
|
||||||
Mergers are required to remove such "false-positive" co-authors when writing the commit message. \
|
|
||||||
The true co-authors must remain in the commit message.
|
|
||||||
|
|
||||||
#### PRs targeting `main`
|
|
||||||
|
|
||||||
The commit message of PRs targeting `main` is always
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$PR_TITLE ($PR_INDEX)
|
|
||||||
|
|
||||||
$REWRITTEN_PR_SUMMARY
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Backport PRs
|
## Design guideline
|
||||||
|
|
||||||
The commit message of backport PRs is always
|
To maintain understandable code and avoid circular dependencies it is important to have a good structure of the code. The Gitea code is divided into the following parts:
|
||||||
|
|
||||||
```bash
|
- **models:** Contains the data structures used by xorm to construct database tables. It also contains supporting functions to query and update the database. Dependencies to other code in Gitea should be avoided although some modules might be needed (for example for logging).
|
||||||
$PR_TITLE ($INITIAL_PR_INDEX) ($BACKPORT_PR_INDEX)
|
- **models/fixtures:** Sample model data used in integration tests.
|
||||||
|
- **models/migrations:** Handling of database migrations between versions. PRs that changes a database structure shall also have a migration step.
|
||||||
$REWRITTEN_PR_SUMMARY
|
- **modules:** Different modules to handle specific functionality in Gitea. Shall only depend on other modules but not other packages (models, services).
|
||||||
```
|
- **public:** Frontend files (javascript, images, css, etc.)
|
||||||
|
- **routers:** Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers.
|
||||||
|
- **services:** Support functions for common routing operations. Uses models and modules to handle the request.
|
||||||
|
- **templates:** Golang templates for generating the html output.
|
||||||
|
- **tests/e2e:** End to end tests
|
||||||
|
- **tests/integration:** Integration tests
|
||||||
|
- **tests/gitea-repositories-meta:** Sample repos used in integration tests. Adding a new repo requires editing `models/fixtures/repositories.yml` and `models/fixtures/repo_unit.yml` to match.
|
||||||
|
- **tests/gitea-lfs-meta:** Sample LFS objects used in integration tests. Adding a new object requires editing `models/fixtures/lfs_meta_object.yml` to match.
|
||||||
|
- **vendor:** External code that Gitea depends on.
|
||||||
|
|
||||||
## Documentation
|
## 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.
|
||||||
|
|
||||||
## API v1
|
## 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](http://try.gitea.io/api/swagger) and is based on [GitHub API v3](https://developer.github.com/v3/).
|
||||||
|
|
||||||
### GitHub API compatibility
|
Thus, Gitea´s API should use the same endpoints and fields as GitHub´s API as far as possible, unless there are good reasons to deviate.
|
||||||
|
|
||||||
Gitea's API should use the same endpoints and fields as the GitHub API as far as possible, unless there are good reasons to deviate. \
|
If Gitea provides functionality that GitHub does not, a new endpoint can be created.
|
||||||
If Gitea provides functionality that GitHub does not, a new endpoint can be created. \
|
|
||||||
If information is provided by Gitea that is not provided by the GitHub API, a new field can be used that doesn't collide with any GitHub fields. \
|
|
||||||
Updating an existing API should not remove existing fields unless there is a really good reason to do so. \
|
|
||||||
The same applies to status responses. If you notice a problem, feel free to leave a comment in the code for future refactoring to API v2 (which is currently not planned).
|
|
||||||
|
|
||||||
### Adding/Maintaining API routes
|
If information is provided by Gitea that is not provided by the GitHub API, a new field can be used that doesn't collide with any GitHub fields.
|
||||||
|
|
||||||
All expected results (errors, success, fail messages) must be documented ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)). \
|
Updating an existing API should not remove existing fields unless there is a really good reason to do so.
|
||||||
All JSON input types must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91)) \
|
|
||||||
and referenced in [routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go). \
|
|
||||||
They can then be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318). \
|
|
||||||
All JSON responses must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L36-L68)) \
|
|
||||||
and referenced in its category in [routers/api/v1/swagger/](routers/api/v1/swagger/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16)) \
|
|
||||||
They can be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279).
|
|
||||||
|
|
||||||
### When to use what HTTP method
|
The same applies to status responses. If you notice a problem, feel free to leave a comment in the code for future refactoring to APIv2 (which is currently not planned).
|
||||||
|
|
||||||
|
All expected results (errors, success, fail messages) should be documented
|
||||||
|
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)).
|
||||||
|
|
||||||
|
All JSON input types must be defined as a struct in [modules/structs/](modules/structs/)
|
||||||
|
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91))
|
||||||
|
and referenced in
|
||||||
|
[routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go).
|
||||||
|
|
||||||
|
They can then be used like the following:
|
||||||
|
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318)).
|
||||||
|
|
||||||
|
All JSON responses must be defined as a struct in [modules/structs/](modules/structs/)
|
||||||
|
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L36-L68))
|
||||||
|
and referenced in its category in [routers/api/v1/swagger/](routers/api/v1/swagger/)
|
||||||
|
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16))
|
||||||
|
|
||||||
|
They can be used like the following:
|
||||||
|
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279))
|
||||||
|
|
||||||
In general, HTTP methods are chosen as follows:
|
In general, HTTP methods are chosen as follows:
|
||||||
|
|
||||||
- **GET** endpoints return the requested object(s) and status **OK (200)**
|
- **GET** endpoints return requested object and status **OK (200)**
|
||||||
- **DELETE** endpoints return the status **No Content (204)** and no content either
|
- **DELETE** endpoints return status **No Content (204)**
|
||||||
- **POST** endpoints are used to **create** new objects (e.g. a User) and return the status **Created (201)** and the created object
|
- **POST** endpoints return status **Created (201)**, used to **create** new objects (e.g. a User)
|
||||||
- **PUT** endpoints are used to **add/assign** existing Objects (e.g. a user to a team) and return the status **No Content (204)** and no content either
|
- **PUT** endpoints return status **No Content (204)**, used to **add/assign** existing Objects (e.g. User) to something (e.g. Org-Team)
|
||||||
- **PATCH** endpoints are used to **edit/change** an existing object and return the changed object and the status **OK (200)**
|
- **PATCH** endpoints return changed object and status **OK (200)**, used to **edit/change** an existing object
|
||||||
|
|
||||||
### Requirements for API routes
|
An endpoint which changes/edits an object expects all fields to be optional (except ones to identify the object, which are required).
|
||||||
|
|
||||||
All parameters of endpoints changing/editing an object must be optional (except the ones to identify the object, which are required).
|
### Endpoints returning lists should
|
||||||
|
|
||||||
Endpoints returning lists must
|
|
||||||
|
|
||||||
- support pagination (`page` & `limit` options in query)
|
- support pagination (`page` & `limit` options in query)
|
||||||
- set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444))
|
- set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444))
|
||||||
|
|
||||||
## Backports and Frontports
|
## Backports and Frontports
|
||||||
|
|
||||||
### What is backported?
|
Occasionally backports of PRs are required.
|
||||||
|
|
||||||
We backport PRs given the following circumstances:
|
The backported PR title should be:
|
||||||
|
|
||||||
1. Feature freeze is active, but `<version>-rc0` has not been released yet. Here, we backport as much as possible. <!-- TODO: Is that our definition with the new backport bot? -->
|
|
||||||
2. `rc0` has been released. Here, we only backport bug- and security-fixes, and small enhancements. Large PRs such as refactors are not backported anymore. <!-- TODO: Is that our definition with the new backport bot? -->
|
|
||||||
3. We never backport new features.
|
|
||||||
4. We never backport breaking changes except when
|
|
||||||
1. The breaking change has no effect on the vast majority of users
|
|
||||||
2. The component triggering the breaking change is marked as experimental
|
|
||||||
|
|
||||||
### How to backport?
|
|
||||||
|
|
||||||
In the past, it was necessary to manually backport your PRs. \
|
|
||||||
Now, that's not a requirement anymore as our [backport bot](https://github.com/GiteaBot) tries to create backports automatically once the PR is merged when the PR
|
|
||||||
|
|
||||||
- does not have the label `backport/manual`
|
|
||||||
- has the label `backport/<version>`
|
|
||||||
|
|
||||||
The `backport/manual` label signifies either that you want to backport the change yourself, or that there were conflicts when backporting, thus you **must** do it yourself.
|
|
||||||
|
|
||||||
### Format of backport PRs
|
|
||||||
|
|
||||||
The title of backport PRs should be
|
|
||||||
|
|
||||||
```
|
```
|
||||||
<original PR title> (#<original pr number>)
|
Title of backported PR (#ORIGINAL_PR_NUMBER)
|
||||||
```
|
```
|
||||||
|
|
||||||
The first two lines of the summary of the backporting PR should be
|
The first two lines of the summary of the backporting PR should be:
|
||||||
|
|
||||||
```
|
```
|
||||||
Backport #<original pr number>
|
Backport #ORIGINAL_PR_NUMBER
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
with the rest of the summary and labels matching the original PR.
|
with the rest of the summary matching the original PR. Similarly for frontports
|
||||||
|
|
||||||
### Frontports
|
---
|
||||||
|
|
||||||
Frontports behave exactly as described above for backports.
|
A command to help create backports can be found in `contrib/backport` and can be installed (from inside the gitea repo root directory) using:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go install contrib/backport/backport.go
|
||||||
|
```
|
||||||
|
|
||||||
## Developer Certificate of Origin (DCO)
|
## Developer Certificate of Origin (DCO)
|
||||||
|
|
||||||
We consider the act of contributing to the code by submitting a Pull Request as the "Sign off" or agreement to the certifications and terms of the [DCO](DCO) and [MIT license](LICENSE). \
|
We consider the act of contributing to the code by submitting a Pull
|
||||||
No further action is required. \
|
Request as the "Sign off" or agreement to the certifications and terms
|
||||||
You can also decide to sign off your commits by adding the following line at the end of your commit messages:
|
of the [DCO](DCO) and [MIT license](LICENSE). No further action is required.
|
||||||
|
Additionally you could add a line at the end of your commit message.
|
||||||
|
|
||||||
```
|
```
|
||||||
Signed-off-by: Joe Smith <joe.smith@email.com>
|
Signed-off-by: Joe Smith <joe.smith@email.com>
|
||||||
```
|
```
|
||||||
|
|
||||||
If you set the `user.name` and `user.email` Git config options, you can add the line to the end of your commits automatically with `git commit -s`.
|
If you set your `user.name` and `user.email` Git configs, you can add the
|
||||||
|
line to the end of your commit automatically with `git commit -s`.
|
||||||
|
|
||||||
We assume in good faith that the information you provide is legally binding.
|
We assume in good faith that the information you provide is legally binding.
|
||||||
|
|
||||||
## Release Cycle
|
## Release Cycle
|
||||||
|
|
||||||
We adopted a release schedule to streamline the process of working on, finishing, and issuing releases. \
|
We adopted a release schedule to streamline the process of working
|
||||||
The overall goal is to make a major release every three or four months, which breaks down into two or three months of general development followed by one month of testing and polishing known as the release freeze. \
|
on, finishing, and issuing releases. The overall goal is to make a
|
||||||
All the feature pull requests should be
|
minor release every three or four months, which breaks down into two or three months of
|
||||||
|
general development followed by one month of testing and polishing
|
||||||
|
known as the release freeze. All the feature pull requests should be
|
||||||
merged before feature freeze. And, during the frozen period, a corresponding
|
merged before feature freeze. And, during the frozen period, a corresponding
|
||||||
release branch is open for fixes backported from main branch. Release candidates
|
release branch is open for fixes backported from main branch. Release candidates
|
||||||
are made during this period for user testing to
|
are made during this period for user testing to
|
||||||
obtain a final version that is maintained in this branch.
|
obtain a final version that is maintained in this branch.
|
||||||
|
|
||||||
|
Major release cycles are seasonal. They always begin on the 25th and end on
|
||||||
|
the 24th (i.e., the 25th of December to March 24th).
|
||||||
|
|
||||||
During a development cycle, we may also publish any necessary minor releases
|
During a development cycle, we may also publish any necessary minor releases
|
||||||
for the previous version. For example, if the latest, published release is
|
for the previous version. For example, if the latest, published release is
|
||||||
v1.2, then minor changes for the previous release—e.g., v1.1.0 -> v1.1.1—are
|
v1.2, then minor changes for the previous release—e.g., v1.1.0 -> v1.1.1—are
|
||||||
still possible.
|
still possible.
|
||||||
|
|
||||||
|
The previous release gets fixes for:
|
||||||
|
|
||||||
|
- Security issues
|
||||||
|
- Critical bugs
|
||||||
|
- Regressions
|
||||||
|
- Build issues
|
||||||
|
- Necessary enhancements (including necessary UI/UX fixes)
|
||||||
|
|
||||||
|
The backported fixes should avoid breaking downgrade between minor releases as much as possible.
|
||||||
|
|
||||||
## Maintainers
|
## Maintainers
|
||||||
|
|
||||||
To make sure every PR is checked, we have [maintainers](MAINTAINERS). \
|
To make sure every PR is checked, we have [team
|
||||||
Every PR **must** be reviewed by at least two maintainers (or owners) before it can get merged. \
|
maintainers](MAINTAINERS). Every PR **MUST** be reviewed by at least
|
||||||
For refactoring PRs after a week and documentation only PRs, the approval of only one maintainer is enough. \
|
two maintainers (or owners) before it can get merged. A maintainer
|
||||||
A maintainer should be a contributor of Gitea and contributed at least
|
should be a contributor of Gitea (or Gogs) and contributed at least
|
||||||
4 accepted PRs. A contributor should apply as a maintainer in the
|
4 accepted PRs. A contributor should apply as a maintainer in the
|
||||||
[Discord](https://discord.gg/Gitea) `#develop` channel. The team maintainers may invite the contributor. A maintainer
|
[Discord](https://discord.gg/NsatcWJ) #develop channel. The owners
|
||||||
|
or the team maintainers may invite the contributor. A maintainer
|
||||||
should spend some time on code reviews. If a maintainer has no
|
should spend some time on code reviews. If a maintainer has no
|
||||||
time to do that, they should apply to leave the maintainers team
|
time to do that, they should apply to leave the maintainers team
|
||||||
and we will give them the honor of being a member of the [advisors
|
and we will give them the honor of being a member of the [advisors
|
||||||
@@ -470,74 +341,69 @@ if possible provide GPG signed commits.
|
|||||||
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
|
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
|
||||||
https://help.github.com/articles/signing-commits-with-gpg/
|
https://help.github.com/articles/signing-commits-with-gpg/
|
||||||
|
|
||||||
## Technical Oversight Committee (TOC)
|
## Owners
|
||||||
|
|
||||||
At the start of 2023, the `Owners` team was dissolved. Instead, the governance charter proposed a technical oversight committee (TOC) which expands the ownership team of the Gitea project from three elected positions to six positions. Three positions would be elected as it has been over the past years, and the other three would consist of appointed members from the Gitea company.
|
Since Gitea is a pure community organization without any company support,
|
||||||
https://blog.gitea.io/2023/02/gitea-quarterly-report-23q1/
|
to keep the development healthy we will elect three owners every year. All
|
||||||
|
contributors may vote to elect up to three candidates, one of which will
|
||||||
When the new community members have been elected, the old members will give up ownership to the newly elected members. For security reasons, TOC members or any account with write access (like a bot) must use 2FA.
|
be the main owner, and the other two the assistant owners. When the new
|
||||||
|
owners have been elected, the old owners will give up ownership to the
|
||||||
|
newly elected owners. If an owner is unable to do so, the other owners
|
||||||
|
will assist in ceding ownership to the newly elected owners.
|
||||||
|
For security reasons, Owners or any account with write access (like a bot)
|
||||||
|
must use 2FA.
|
||||||
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
|
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
|
||||||
|
|
||||||
### Current TOC members
|
After the election, the new owners should proactively agree
|
||||||
|
with our [CONTRIBUTING](CONTRIBUTING.md) requirements in the
|
||||||
|
[Discord](https://discord.gg/NsatcWJ) #general channel. Below are the
|
||||||
|
words to speak:
|
||||||
|
|
||||||
- 2023-01-01 ~ 2023-12-31 - https://blog.gitea.io/2023/02/gitea-quarterly-report-23q1/
|
```
|
||||||
- Company
|
I'm honored to having been elected an owner of Gitea, I agree with
|
||||||
- [Jason Song](https://gitea.com/wolfogre) <i@wolfogre.com>
|
[CONTRIBUTING](CONTRIBUTING.md). I will spend part of my time on Gitea
|
||||||
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
|
and lead the development of Gitea.
|
||||||
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.io>
|
```
|
||||||
- Community
|
|
||||||
- [6543](https://gitea.com/6543) <6543@obermui.de>
|
|
||||||
- [Andrew Thornton](https://gitea.com/zeripath) <art27@cantab.net>
|
|
||||||
- [John Olheiser](https://gitea.com/jolheiser) <john.olheiser@gmail.com>
|
|
||||||
|
|
||||||
### Previous TOC/owners members
|
To honor the past owners, here's the history of the owners and the time
|
||||||
|
they served:
|
||||||
|
|
||||||
Here's the history of the owners and the time they served:
|
- 2022-01-01 ~ 2022-12-31 - https://github.com/go-gitea/gitea/issues/17872
|
||||||
|
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
|
||||||
|
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.io>
|
||||||
|
- [Andrew Thornton](https://gitea.com/zeripath) <art27@cantab.net>
|
||||||
|
|
||||||
- [Lunny Xiao](https://gitea.com/lunny) - 2016, 2017, [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872)
|
- 2021-01-01 ~ 2021-12-31 - https://github.com/go-gitea/gitea/issues/13801
|
||||||
- [Kim Carlbäcker](https://github.com/bkcsoft) - 2016, 2017
|
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
|
||||||
- [Thomas Boerger](https://gitea.com/tboerger) - 2016, 2017
|
- [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) <lauris@nix.lv>
|
||||||
- [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) - [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801)
|
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.io>
|
||||||
- [Matti Ranta](https://gitea.com/techknowlogick) - [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872)
|
|
||||||
- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872)
|
|
||||||
|
|
||||||
## Governance Compensation
|
- 2020-01-01 ~ 2020-12-31 - https://github.com/go-gitea/gitea/issues/9230
|
||||||
|
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
|
||||||
|
- [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) <lauris@nix.lv>
|
||||||
|
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.io>
|
||||||
|
|
||||||
Each member of the community elected TOC will be granted $500 each month as compensation for their work.
|
- 2019-01-01 ~ 2019-12-31 - https://github.com/go-gitea/gitea/issues/5572
|
||||||
|
- [Lunny Xiao](https://github.com/lunny) <xiaolunwen@gmail.com>
|
||||||
|
- [Lauris Bukšis-Haberkorns](https://github.com/lafriks) <lauris@nix.lv>
|
||||||
|
- [Matti Ranta](https://github.com/techknowlogick) <techknowlogick@gitea.io>
|
||||||
|
|
||||||
Furthermore, any community release manager for a specific release or LTS will be compensated $500 for the delivery of said release.
|
- 2018-01-01 ~ 2018-12-31 - https://github.com/go-gitea/gitea/issues/3255
|
||||||
|
- [Lunny Xiao](https://github.com/lunny) <xiaolunwen@gmail.com>
|
||||||
|
- [Lauris Bukšis-Haberkorns](https://github.com/lafriks) <lauris@nix.lv>
|
||||||
|
- [Kim Carlbäcker](https://github.com/bkcsoft) <kim.carlbacker@gmail.com>
|
||||||
|
|
||||||
These funds will come from community sources like the OpenCollective rather than directly from the company.
|
- 2016-11-04 ~ 2017-12-31
|
||||||
Only non-company members are eligible for this compensation, and if a member of the community TOC takes the responsibility of release manager, they would only be compensated for their TOC duties.
|
- [Lunny Xiao](https://github.com/lunny) <xiaolunwen@gmail.com>
|
||||||
Gitea Ltd employees are not eligible to receive any funds from the OpenCollective unless it is reimbursement for a purchase made for the Gitea project itself.
|
- [Thomas Boerger](https://github.com/tboerger) <thomas@webhippie.de>
|
||||||
|
- [Kim Carlbäcker](https://github.com/bkcsoft) <kim.carlbacker@gmail.com>
|
||||||
## TOC & Working groups
|
|
||||||
|
|
||||||
With Gitea covering many projects outside of the main repository, several groups will be created to help focus on specific areas instead of requiring maintainers to be a jack-of-all-trades. Maintainers are of course more than welcome to be part of multiple groups should they wish to contribute in multiple places.
|
|
||||||
|
|
||||||
The currently proposed groups are:
|
|
||||||
|
|
||||||
- **Core Group**: maintain the primary Gitea repository
|
|
||||||
- **Integration Group**: maintain the Gitea ecosystem's related tools, including go-sdk/tea/changelog/bots etc.
|
|
||||||
- **Documentation Group**: maintain related documents and repositories
|
|
||||||
- **Translation Group**: coordinate with translators and maintain translations
|
|
||||||
- **Security Group**: managed by TOC directly, members are decided by TOC, maintains security patches/responsible for security items
|
|
||||||
|
|
||||||
## Roadmap
|
|
||||||
|
|
||||||
Each year a roadmap will be discussed with the entire Gitea maintainers team, and feedback will be solicited from various stakeholders.
|
|
||||||
TOC members need to review the roadmap every year and work together on the direction of the project.
|
|
||||||
|
|
||||||
When a vote is required for a proposal or other change, the vote of community elected TOC members count slightly more than the vote of company elected TOC members. With this approach, we both avoid ties and ensure that changes align with the mission statement and community opinion.
|
|
||||||
|
|
||||||
You can visit our roadmap on the wiki.
|
|
||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
Gitea has the `main` branch as a tip branch and has version branches
|
Gitea has the `main` branch as a tip branch and has version branches
|
||||||
such as `release/v1.19`. `release/v1.19` is a release branch and we will
|
such as `release/v0.9`. `release/v0.9` is a release branch and we will
|
||||||
tag `v1.19.0` for binary download. If `v1.19.0` has bugs, we will accept
|
tag `v0.9.0` for binary download. If `v0.9.0` has bugs, we will accept
|
||||||
pull requests on the `release/v1.19` branch and publish a `v1.19.1` tag,
|
pull requests on the `release/v0.9` branch and publish a `v0.9.1` tag,
|
||||||
after bringing the bug fix also to the main branch.
|
after bringing the bug fix also to the main branch.
|
||||||
|
|
||||||
Since the `main` branch is a tip version, if you wish to use Gitea
|
Since the `main` branch is a tip version, if you wish to use Gitea
|
||||||
@@ -557,7 +423,21 @@ be reviewed by two maintainers and must pass the automatic tests.
|
|||||||
- And then push the tag as `git push origin v$vmaj.$vmin.$`. Drone CI will automatically create a release and upload all the compiled binary. (But currently it doesn't add the release notes automatically. Maybe we should fix that.)
|
- And then push the tag as `git push origin v$vmaj.$vmin.$`. Drone CI will automatically create a release and upload all the compiled binary. (But currently it doesn't add the release notes automatically. Maybe we should fix that.)
|
||||||
- If needed send a frontport PR for the changelog to branch `main` and update the version in `docs/config.yaml` to refer to the new version.
|
- If needed send a frontport PR for the changelog to branch `main` and update the version in `docs/config.yaml` to refer to the new version.
|
||||||
- Send PR to [blog repository](https://gitea.com/gitea/blog) announcing the release.
|
- Send PR to [blog repository](https://gitea.com/gitea/blog) announcing the release.
|
||||||
- Verify all release assets were correctly published through CI on dl.gitea.com and GitHub releases. Once ACKed:
|
- Verify all release assets were correctly published through CI on dl.gitea.io and GitHub releases. Once ACKed:
|
||||||
- bump the version of https://dl.gitea.com/gitea/version.json
|
- bump the version of https://dl.gitea.io/gitea/version.json
|
||||||
- merge the blog post PR
|
- merge the blog post PR
|
||||||
- announce the release in discord `#announcements`
|
- announce the release in discord `#announcements`
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
|
||||||
|
Code that you contribute should use the standard copyright header:
|
||||||
|
|
||||||
|
```
|
||||||
|
// Copyright <year> The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Files in the repository contain copyright from the year they are added
|
||||||
|
to the year they are last changed. If the copyright author is changed,
|
||||||
|
just paste the header below the old one.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#Build stage
|
#Build stage
|
||||||
FROM docker.io/library/golang:1.20-alpine3.18 AS build-env
|
FROM golang:1.20-alpine3.17 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY ${GOPROXY:-direct}
|
ENV GOPROXY ${GOPROXY:-direct}
|
||||||
@@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
|
|||||||
# Begin env-to-ini build
|
# Begin env-to-ini build
|
||||||
RUN go build contrib/environment-to-ini/environment-to-ini.go
|
RUN go build contrib/environment-to-ini/environment-to-ini.go
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.18
|
FROM alpine:3.17
|
||||||
LABEL maintainer="maintainers@gitea.io"
|
LABEL maintainer="maintainers@gitea.io"
|
||||||
|
|
||||||
EXPOSE 22 3000
|
EXPOSE 22 3000
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#Build stage
|
#Build stage
|
||||||
FROM docker.io/library/golang:1.20-alpine3.18 AS build-env
|
FROM golang:1.20-alpine3.17 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY ${GOPROXY:-direct}
|
ENV GOPROXY ${GOPROXY:-direct}
|
||||||
@@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
|
|||||||
# Begin env-to-ini build
|
# Begin env-to-ini build
|
||||||
RUN go build contrib/environment-to-ini/environment-to-ini.go
|
RUN go build contrib/environment-to-ini/environment-to-ini.go
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.18
|
FROM alpine:3.17
|
||||||
LABEL maintainer="maintainers@gitea.io"
|
LABEL maintainer="maintainers@gitea.io"
|
||||||
|
|
||||||
EXPOSE 2222 3000
|
EXPOSE 2222 3000
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Kees de Vries <bouwko@gmail.com> (@Bwko)
|
|||||||
Kim Carlbäcker <kim.carlbacker@gmail.com> (@bkcsoft)
|
Kim Carlbäcker <kim.carlbacker@gmail.com> (@bkcsoft)
|
||||||
LefsFlare <nobody@nobody.tld> (@LefsFlarey)
|
LefsFlare <nobody@nobody.tld> (@LefsFlarey)
|
||||||
Lunny Xiao <xiaolunwen@gmail.com> (@lunny)
|
Lunny Xiao <xiaolunwen@gmail.com> (@lunny)
|
||||||
|
Matthias Loibl <mail@matthiasloibl.com> (@metalmatze)
|
||||||
Rachid Zarouali <nobody@nobody.tld> (@xinity)
|
Rachid Zarouali <nobody@nobody.tld> (@xinity)
|
||||||
Rémy Boulanouar <admin@dblk.org> (@DblK)
|
Rémy Boulanouar <admin@dblk.org> (@DblK)
|
||||||
Sandro Santilli <strk@kbt.io> (@strk)
|
Sandro Santilli <strk@kbt.io> (@strk)
|
||||||
@@ -43,12 +44,9 @@ Steven Kriegler <sk.bunsenbrenner@gmail.com> (@justusbunsi)
|
|||||||
Jimmy Praet <jimmy.praet@telenet.be> (@jpraet)
|
Jimmy Praet <jimmy.praet@telenet.be> (@jpraet)
|
||||||
Leon Hofmeister <dev.lh@web.de> (@delvh)
|
Leon Hofmeister <dev.lh@web.de> (@delvh)
|
||||||
Wim <wim@42.be> (@42wim)
|
Wim <wim@42.be> (@42wim)
|
||||||
|
Xinyu Zhou <i@sourcehut.net> (@xin-u)
|
||||||
Jason Song <i@wolfogre.com> (@wolfogre)
|
Jason Song <i@wolfogre.com> (@wolfogre)
|
||||||
Yarden Shoham <git@yardenshoham.com> (@yardenshoham)
|
Yarden Shoham <hrsi88@gmail.com> (@yardenshoham)
|
||||||
Yu Tian <zettat123@gmail.com> (@Zettat123)
|
Yu Tian <zettat123@gmail.com> (@Zettat123)
|
||||||
Eddie Yang <576951401@qq.com> (@yp05327)
|
Eddie Yang <576951401@qq.com> (@yp05327)
|
||||||
Dong Ge <gedong_1994@163.com> (@sillyguodong)
|
Dong Ge <gedong_1994@163.com> (@sillyguodong)
|
||||||
Xinyi Gong <hestergong@gmail.com> (@HesterG)
|
|
||||||
wxiaoguang <wxiaoguang@gmail.com> (@wxiaoguang)
|
|
||||||
Gary Moon <gary@garymoon.net> (@garymoon)
|
|
||||||
Philip Peterson <philip.c.peterson@gmail.com> (@philip-peterson)
|
|
||||||
|
|||||||
216
Makefile
216
Makefile
@@ -20,28 +20,28 @@ IMPORT := code.gitea.io/gitea
|
|||||||
|
|
||||||
GO ?= go
|
GO ?= go
|
||||||
SHASUM ?= shasum -a 256
|
SHASUM ?= shasum -a 256
|
||||||
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
|
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
|
||||||
COMMA := ,
|
COMMA := ,
|
||||||
|
|
||||||
XGO_VERSION := go-1.20.x
|
XGO_VERSION := go-1.20.x
|
||||||
|
|
||||||
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.43.0
|
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.40.4
|
||||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0
|
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.6.0
|
||||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.5.0
|
ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.2
|
||||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.52.2
|
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.4.0
|
||||||
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
|
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.0
|
||||||
|
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
|
||||||
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
|
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
|
||||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.4
|
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.3
|
||||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||||
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0
|
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.5.0
|
||||||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@latest
|
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@latest
|
||||||
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@latest
|
|
||||||
|
|
||||||
DOCKER_IMAGE ?= gitea/gitea
|
DOCKER_IMAGE ?= gitea/gitea
|
||||||
DOCKER_TAG ?= latest
|
DOCKER_TAG ?= latest
|
||||||
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
|
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
|
||||||
|
|
||||||
ifeq ($(HAS_GO), yes)
|
ifeq ($(HAS_GO), GO)
|
||||||
GOPATH ?= $(shell $(GO) env GOPATH)
|
GOPATH ?= $(shell $(GO) env GOPATH)
|
||||||
export PATH := $(GOPATH)/bin:$(PATH)
|
export PATH := $(GOPATH)/bin:$(PATH)
|
||||||
|
|
||||||
@@ -77,23 +77,13 @@ ifeq ($(RACE_ENABLED),true)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
STORED_VERSION_FILE := VERSION
|
STORED_VERSION_FILE := VERSION
|
||||||
HUGO_VERSION ?= 0.111.3
|
|
||||||
|
|
||||||
GITHUB_REF_TYPE ?= branch
|
|
||||||
GITHUB_REF_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
|
||||||
|
|
||||||
# backwards compatible to build with Drone
|
|
||||||
ifneq ($(DRONE_TAG),)
|
ifneq ($(DRONE_TAG),)
|
||||||
GITHUB_REF_TYPE := tag
|
VERSION ?= $(subst v,,$(DRONE_TAG))
|
||||||
GITHUB_REF_NAME := $(DRONE_TAG)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(GITHUB_REF_TYPE),branch)
|
|
||||||
VERSION ?= $(subst v,,$(GITHUB_REF_NAME))
|
|
||||||
GITEA_VERSION ?= $(VERSION)
|
GITEA_VERSION ?= $(VERSION)
|
||||||
else
|
else
|
||||||
ifneq ($(GITHUB_REF_NAME),)
|
ifneq ($(DRONE_BRANCH),)
|
||||||
VERSION ?= $(subst release/v,,$(GITHUB_REF_NAME))
|
VERSION ?= $(subst release/v,,$(DRONE_BRANCH))
|
||||||
else
|
else
|
||||||
VERSION ?= main
|
VERSION ?= main
|
||||||
endif
|
endif
|
||||||
@@ -106,11 +96,6 @@ else
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# if version = "main" then update version to "nightly"
|
|
||||||
ifeq ($(VERSION),main)
|
|
||||||
VERSION := main-nightly
|
|
||||||
endif
|
|
||||||
|
|
||||||
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
|
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
|
||||||
|
|
||||||
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
|
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
|
||||||
@@ -120,10 +105,10 @@ GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/m
|
|||||||
|
|
||||||
FOMANTIC_WORK_DIR := web_src/fomantic
|
FOMANTIC_WORK_DIR := web_src/fomantic
|
||||||
|
|
||||||
WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
|
WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f)
|
||||||
WEBPACK_CONFIGS := webpack.config.js
|
WEBPACK_CONFIGS := webpack.config.js
|
||||||
WEBPACK_DEST := public/js/index.js public/css/index.css
|
WEBPACK_DEST := public/js/index.js public/css/index.css
|
||||||
WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/img/webpack
|
WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/img/webpack public/serviceworker.js
|
||||||
|
|
||||||
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
|
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
|
||||||
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
|
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
|
||||||
@@ -145,11 +130,11 @@ TEST_TAGS ?= 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)
|
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
|
GO_DIRS := cmd tests models modules routers build services tools
|
||||||
WEB_DIRS := web_src/js web_src/css
|
WEB_DIRS := web_src/js web_src/less
|
||||||
|
|
||||||
GO_SOURCES := $(wildcard *.go)
|
GO_SOURCES := $(wildcard *.go)
|
||||||
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" ! -path modules/options/bindata.go ! -path modules/public/bindata.go ! -path modules/templates/bindata.go)
|
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" -not -path modules/options/bindata.go -not -path modules/public/bindata.go -not -path modules/templates/bindata.go)
|
||||||
GO_SOURCES += $(GENERATED_GO_DEST)
|
GO_SOURCES += $(GENERATED_GO_DEST)
|
||||||
GO_SOURCES_NO_BINDATA := $(GO_SOURCES)
|
GO_SOURCES_NO_BINDATA := $(GO_SOURCES)
|
||||||
|
|
||||||
@@ -205,23 +190,9 @@ help:
|
|||||||
@echo " - deps install dependencies"
|
@echo " - deps install dependencies"
|
||||||
@echo " - deps-frontend install frontend dependencies"
|
@echo " - deps-frontend install frontend dependencies"
|
||||||
@echo " - deps-backend install backend dependencies"
|
@echo " - deps-backend install backend dependencies"
|
||||||
@echo " - deps-tools install tool dependencies"
|
|
||||||
@echo " - lint lint everything"
|
@echo " - lint lint everything"
|
||||||
@echo " - lint-fix lint everything and fix issues"
|
|
||||||
@echo " - lint-actions lint action workflow files"
|
|
||||||
@echo " - lint-frontend lint frontend files"
|
@echo " - lint-frontend lint frontend files"
|
||||||
@echo " - lint-frontend-fix lint frontend files and fix issues"
|
|
||||||
@echo " - lint-backend lint backend files"
|
@echo " - lint-backend lint backend files"
|
||||||
@echo " - lint-backend-fix lint backend files and fix issues"
|
|
||||||
@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-js lint js files"
|
|
||||||
@echo " - lint-js-fix lint js files and fix issues"
|
|
||||||
@echo " - lint-css lint css files"
|
|
||||||
@echo " - lint-css-fix lint css files and fix issues"
|
|
||||||
@echo " - lint-md lint markdown files"
|
|
||||||
@echo " - lint-swagger lint swagger files"
|
|
||||||
@echo " - checks run various consistency checks"
|
@echo " - checks run various consistency checks"
|
||||||
@echo " - checks-frontend check frontend files"
|
@echo " - checks-frontend check frontend files"
|
||||||
@echo " - checks-backend check backend files"
|
@echo " - checks-backend check backend files"
|
||||||
@@ -239,10 +210,13 @@ help:
|
|||||||
@echo " - generate-manpage generate manpage"
|
@echo " - generate-manpage generate manpage"
|
||||||
@echo " - generate-swagger generate the swagger spec from code comments"
|
@echo " - generate-swagger generate the swagger spec from code comments"
|
||||||
@echo " - swagger-validate check if the swagger spec is valid"
|
@echo " - swagger-validate check if the swagger spec is valid"
|
||||||
|
@echo " - golangci-lint run golangci-lint linter"
|
||||||
@echo " - go-licenses regenerate go licenses"
|
@echo " - go-licenses regenerate go licenses"
|
||||||
|
@echo " - vet examines Go source code and reports suspicious constructs"
|
||||||
@echo " - tidy run go mod tidy"
|
@echo " - tidy run go mod tidy"
|
||||||
@echo " - test[\#TestSpecificName] run unit test"
|
@echo " - test[\#TestSpecificName] run unit test"
|
||||||
@echo " - test-sqlite[\#TestSpecificName] run integration test for sqlite"
|
@echo " - test-sqlite[\#TestSpecificName] run integration test for sqlite"
|
||||||
|
@echo " - pr#<index> build and start gitea from a PR with integration test data loaded"
|
||||||
|
|
||||||
.PHONY: go-check
|
.PHONY: go-check
|
||||||
go-check:
|
go-check:
|
||||||
@@ -293,16 +267,12 @@ clean:
|
|||||||
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'))
|
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
|
||||||
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
|
@# strip whitespace after '{{' and before `}}` unless there is only whitespace before it
|
||||||
@# whitespace before it
|
@$(SED_INPLACE) -e 's/{{[ ]\{1,\}/{{/g' -e '/^[ ]\{1,\}}}/! s/[ ]\{1,\}}}/}}/g' $(TEMPLATES)
|
||||||
@$(SED_INPLACE) \
|
|
||||||
-e 's/{{[ ]\{1,\}/{{/g' -e '/^[ ]\{1,\}}}/! s/[ ]\{1,\}}}/}}/g' \
|
|
||||||
-e 's/([ ]\{1,\}/(/g' -e '/^[ ]\{1,\})/! s/[ ]\{1,\})/)/g' \
|
|
||||||
$(TEMPLATES)
|
|
||||||
|
|
||||||
.PHONY: fmt-check
|
.PHONY: fmt-check
|
||||||
fmt-check: fmt
|
fmt-check: fmt
|
||||||
@diff=$$(git diff --color=always $(GO_SOURCES) templates $(WEB_DIRS)); \
|
@diff=$$(git diff $(GO_SOURCES) templates $(WEB_DIRS)); \
|
||||||
if [ -n "$$diff" ]; then \
|
if [ -n "$$diff" ]; then \
|
||||||
echo "Please run 'make fmt' and commit the result:"; \
|
echo "Please run 'make fmt' and commit the result:"; \
|
||||||
echo "$${diff}"; \
|
echo "$${diff}"; \
|
||||||
@@ -313,6 +283,12 @@ fmt-check: fmt
|
|||||||
misspell-check:
|
misspell-check:
|
||||||
go run $(MISSPELL_PACKAGE) -error $(GO_DIRS) $(WEB_DIRS)
|
go run $(MISSPELL_PACKAGE) -error $(GO_DIRS) $(WEB_DIRS)
|
||||||
|
|
||||||
|
.PHONY: vet
|
||||||
|
vet:
|
||||||
|
@echo "Running go vet..."
|
||||||
|
@GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet
|
||||||
|
@$(GO) vet -vettool=gitea-vet $(GO_PACKAGES)
|
||||||
|
|
||||||
.PHONY: $(TAGS_EVIDENCE)
|
.PHONY: $(TAGS_EVIDENCE)
|
||||||
$(TAGS_EVIDENCE):
|
$(TAGS_EVIDENCE):
|
||||||
@mkdir -p $(MAKE_EVIDENCE_DIR)
|
@mkdir -p $(MAKE_EVIDENCE_DIR)
|
||||||
@@ -332,7 +308,7 @@ $(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA)
|
|||||||
|
|
||||||
.PHONY: swagger-check
|
.PHONY: swagger-check
|
||||||
swagger-check: generate-swagger
|
swagger-check: generate-swagger
|
||||||
@diff=$$(git diff --color=always '$(SWAGGER_SPEC)'); \
|
@diff=$$(git diff '$(SWAGGER_SPEC)'); \
|
||||||
if [ -n "$$diff" ]; then \
|
if [ -n "$$diff" ]; then \
|
||||||
echo "Please run 'make generate-swagger' and commit the result:"; \
|
echo "Please run 'make generate-swagger' and commit the result:"; \
|
||||||
echo "$${diff}"; \
|
echo "$${diff}"; \
|
||||||
@@ -345,6 +321,11 @@ swagger-validate:
|
|||||||
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
|
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
|
||||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
||||||
|
|
||||||
|
.PHONY: errcheck
|
||||||
|
errcheck:
|
||||||
|
@echo "Running errcheck..."
|
||||||
|
$(GO) run $(ERRCHECK_PACKAGE) $(GO_PACKAGES)
|
||||||
|
|
||||||
.PHONY: checks
|
.PHONY: checks
|
||||||
checks: checks-frontend checks-backend
|
checks: checks-frontend checks-backend
|
||||||
|
|
||||||
@@ -357,81 +338,23 @@ checks-backend: tidy-check swagger-check fmt-check misspell-check swagger-valida
|
|||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint: lint-frontend lint-backend
|
lint: lint-frontend lint-backend
|
||||||
|
|
||||||
.PHONY: lint-fix
|
|
||||||
lint-fix: lint-frontend-fix lint-backend-fix
|
|
||||||
|
|
||||||
.PHONY: lint-frontend
|
.PHONY: lint-frontend
|
||||||
lint-frontend: lint-js lint-css lint-md lint-swagger
|
lint-frontend: node_modules
|
||||||
|
npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js docs/assets/js tests/e2e
|
||||||
.PHONY: lint-frontend-fix
|
npx stylelint --color --max-warnings=0 web_src/less
|
||||||
lint-frontend-fix: lint-js-fix lint-css-fix lint-md lint-swagger
|
|
||||||
|
|
||||||
.PHONY: lint-backend
|
|
||||||
lint-backend: lint-go lint-go-vet 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 web_src/js build *.config.js tests/e2e
|
|
||||||
|
|
||||||
.PHONY: lint-js-fix
|
|
||||||
lint-js-fix: node_modules
|
|
||||||
npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js tests/e2e --fix
|
|
||||||
|
|
||||||
.PHONY: lint-css
|
|
||||||
lint-css: node_modules
|
|
||||||
npx stylelint --color --max-warnings=0 web_src/css web_src/js/components/*.vue
|
|
||||||
|
|
||||||
.PHONY: lint-css-fix
|
|
||||||
lint-css-fix: node_modules
|
|
||||||
npx stylelint --color --max-warnings=0 web_src/css web_src/js/components/*.vue --fix
|
|
||||||
|
|
||||||
.PHONY: lint-swagger
|
|
||||||
lint-swagger: node_modules
|
|
||||||
npx spectral lint -q -F hint $(SWAGGER_SPEC)
|
npx spectral lint -q -F hint $(SWAGGER_SPEC)
|
||||||
|
|
||||||
.PHONY: lint-md
|
|
||||||
lint-md: node_modules
|
|
||||||
npx markdownlint docs *.md
|
npx markdownlint docs *.md
|
||||||
|
|
||||||
.PHONY: lint-go
|
.PHONY: lint-backend
|
||||||
lint-go:
|
lint-backend: golangci-lint vet editorconfig-checker
|
||||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
|
||||||
|
|
||||||
.PHONY: lint-go-fix
|
|
||||||
lint-go-fix:
|
|
||||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix
|
|
||||||
|
|
||||||
# workaround step for the lint-go-windows CI task because 'go run' can not
|
|
||||||
# have distinct GOOS/GOARCH for its build and run steps
|
|
||||||
.PHONY: lint-go-windows
|
|
||||||
lint-go-windows:
|
|
||||||
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
|
|
||||||
golangci-lint run
|
|
||||||
|
|
||||||
.PHONY: lint-go-vet
|
|
||||||
lint-go-vet:
|
|
||||||
@echo "Running go vet..."
|
|
||||||
@GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet
|
|
||||||
@$(GO) vet -vettool=gitea-vet $(GO_PACKAGES)
|
|
||||||
|
|
||||||
.PHONY: lint-editorconfig
|
|
||||||
lint-editorconfig:
|
|
||||||
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .github/workflows
|
|
||||||
|
|
||||||
.PHONY: lint-actions
|
|
||||||
lint-actions:
|
|
||||||
$(GO) run $(ACTIONLINT_PACKAGE)
|
|
||||||
|
|
||||||
.PHONY: watch
|
.PHONY: watch
|
||||||
watch:
|
watch:
|
||||||
@bash build/watch.sh
|
bash tools/watch.sh
|
||||||
|
|
||||||
.PHONY: watch-frontend
|
.PHONY: watch-frontend
|
||||||
watch-frontend: node-check node_modules
|
watch-frontend: node-check node_modules
|
||||||
@rm -rf $(WEBPACK_DEST_ENTRIES)
|
rm -rf $(WEBPACK_DEST_ENTRIES)
|
||||||
NODE_ENV=development npx webpack --watch --progress
|
NODE_ENV=development npx webpack --watch --progress
|
||||||
|
|
||||||
.PHONY: watch-backend
|
.PHONY: watch-backend
|
||||||
@@ -490,7 +413,7 @@ vendor: go.mod go.sum
|
|||||||
|
|
||||||
.PHONY: tidy-check
|
.PHONY: tidy-check
|
||||||
tidy-check: tidy
|
tidy-check: tidy
|
||||||
@diff=$$(git diff --color=always go.mod go.sum $(GO_LICENSE_FILE)); \
|
@diff=$$(git diff go.mod go.sum $(GO_LICENSE_FILE)); \
|
||||||
if [ -n "$$diff" ]; then \
|
if [ -n "$$diff" ]; then \
|
||||||
echo "Please run 'make tidy' and commit the result:"; \
|
echo "Please run 'make tidy' and commit the result:"; \
|
||||||
echo "$${diff}"; \
|
echo "$${diff}"; \
|
||||||
@@ -822,7 +745,7 @@ generate-go: $(TAGS_PREREQ)
|
|||||||
|
|
||||||
.PHONY: security-check
|
.PHONY: security-check
|
||||||
security-check:
|
security-check:
|
||||||
go run $(GOVULNCHECK_PACKAGE) ./...
|
go run $(GOVULNCHECK_PACKAGE) -v ./...
|
||||||
|
|
||||||
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
|
||||||
@@ -839,28 +762,28 @@ release-windows: | $(DIST_DIRS)
|
|||||||
ifeq (,$(findstring gogit,$(TAGS)))
|
ifeq (,$(findstring gogit,$(TAGS)))
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||||
endif
|
endif
|
||||||
ifneq ($(DRONE_TAG),)
|
ifeq ($(CI),true)
|
||||||
cp /build/* $(DIST)/binaries
|
cp /build/* $(DIST)/binaries
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: release-linux
|
.PHONY: release-linux
|
||||||
release-linux: | $(DIST_DIRS)
|
release-linux: | $(DIST_DIRS)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
||||||
ifneq ($(DRONE_TAG),)
|
ifeq ($(CI),true)
|
||||||
cp /build/* $(DIST)/binaries
|
cp /build/* $(DIST)/binaries
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: release-darwin
|
.PHONY: release-darwin
|
||||||
release-darwin: | $(DIST_DIRS)
|
release-darwin: | $(DIST_DIRS)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
||||||
ifneq ($(DRONE_TAG),)
|
ifeq ($(CI),true)
|
||||||
cp /build/* $(DIST)/binaries
|
cp /build/* $(DIST)/binaries
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: release-freebsd
|
.PHONY: release-freebsd
|
||||||
release-freebsd: | $(DIST_DIRS)
|
release-freebsd: | $(DIST_DIRS)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) .
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) .
|
||||||
ifneq ($(DRONE_TAG),)
|
ifeq ($(CI),true)
|
||||||
cp /build/* $(DIST)/binaries
|
cp /build/* $(DIST)/binaries
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -888,14 +811,17 @@ release-sources: | $(DIST_DIRS)
|
|||||||
|
|
||||||
.PHONY: release-docs
|
.PHONY: release-docs
|
||||||
release-docs: | $(DIST_DIRS) docs
|
release-docs: | $(DIST_DIRS) docs
|
||||||
tar -czf $(DIST)/release/gitea-docs-$(VERSION).tar.gz -C ./docs .
|
tar -czf $(DIST)/release/gitea-docs-$(VERSION).tar.gz -C ./docs/public .
|
||||||
|
|
||||||
.PHONY: docs
|
.PHONY: docs
|
||||||
docs:
|
docs:
|
||||||
cd docs; bash scripts/trans-copy.sh;
|
@hash hugo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
curl -sL https://github.com/gohugoio/hugo/releases/download/v0.74.3/hugo_0.74.3_Linux-64bit.tar.gz | tar zxf - -C /tmp && mv /tmp/hugo /usr/bin/hugo && chmod +x /usr/bin/hugo; \
|
||||||
|
fi
|
||||||
|
cd docs; make trans-copy clean build-offline;
|
||||||
|
|
||||||
.PHONY: deps
|
.PHONY: deps
|
||||||
deps: deps-frontend deps-backend deps-tools
|
deps: deps-frontend deps-backend
|
||||||
|
|
||||||
.PHONY: deps-frontend
|
.PHONY: deps-frontend
|
||||||
deps-frontend: node_modules
|
deps-frontend: node_modules
|
||||||
@@ -903,11 +829,9 @@ deps-frontend: node_modules
|
|||||||
.PHONY: deps-backend
|
.PHONY: deps-backend
|
||||||
deps-backend:
|
deps-backend:
|
||||||
$(GO) mod download
|
$(GO) mod download
|
||||||
|
|
||||||
.PHONY: deps-tools
|
|
||||||
deps-tools:
|
|
||||||
$(GO) install $(AIR_PACKAGE)
|
$(GO) install $(AIR_PACKAGE)
|
||||||
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
|
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
|
||||||
|
$(GO) install $(ERRCHECK_PACKAGE)
|
||||||
$(GO) install $(GOFUMPT_PACKAGE)
|
$(GO) install $(GOFUMPT_PACKAGE)
|
||||||
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||||
$(GO) install $(GXZ_PAGAGE)
|
$(GO) install $(GXZ_PAGAGE)
|
||||||
@@ -916,7 +840,6 @@ deps-tools:
|
|||||||
$(GO) install $(XGO_PACKAGE)
|
$(GO) install $(XGO_PACKAGE)
|
||||||
$(GO) install $(GO_LICENSES_PACKAGE)
|
$(GO) install $(GO_LICENSES_PACKAGE)
|
||||||
$(GO) install $(GOVULNCHECK_PACKAGE)
|
$(GO) install $(GOVULNCHECK_PACKAGE)
|
||||||
$(GO) install $(ACTIONLINT_PACKAGE)
|
|
||||||
|
|
||||||
node_modules: package-lock.json
|
node_modules: package-lock.json
|
||||||
npm install --no-save
|
npm install --no-save
|
||||||
@@ -958,7 +881,7 @@ svg: node-check | node_modules
|
|||||||
.PHONY: svg-check
|
.PHONY: svg-check
|
||||||
svg-check: svg
|
svg-check: svg
|
||||||
@git add $(SVG_DEST_DIR)
|
@git add $(SVG_DEST_DIR)
|
||||||
@diff=$$(git diff --color=always --cached $(SVG_DEST_DIR)); \
|
@diff=$$(git diff --cached $(SVG_DEST_DIR)); \
|
||||||
if [ -n "$$diff" ]; then \
|
if [ -n "$$diff" ]; then \
|
||||||
echo "Please run 'make svg' and 'git add $(SVG_DEST_DIR)' and commit the result:"; \
|
echo "Please run 'make svg' and 'git add $(SVG_DEST_DIR)' and commit the result:"; \
|
||||||
echo "$${diff}"; \
|
echo "$${diff}"; \
|
||||||
@@ -968,7 +891,7 @@ svg-check: svg
|
|||||||
.PHONY: lockfile-check
|
.PHONY: lockfile-check
|
||||||
lockfile-check:
|
lockfile-check:
|
||||||
npm install --package-lock-only
|
npm install --package-lock-only
|
||||||
@diff=$$(git diff --color=always package-lock.json); \
|
@diff=$$(git diff package-lock.json); \
|
||||||
if [ -n "$$diff" ]; then \
|
if [ -n "$$diff" ]; then \
|
||||||
echo "package-lock.json is inconsistent with package.json"; \
|
echo "package-lock.json is inconsistent with package.json"; \
|
||||||
echo "Please run 'npm install --package-lock-only' and commit the result:"; \
|
echo "Please run 'npm install --package-lock-only' and commit the result:"; \
|
||||||
@@ -1007,10 +930,33 @@ generate-manpage:
|
|||||||
@gzip -9 man/man1/gitea.1 && echo man/man1/gitea.1.gz created
|
@gzip -9 man/man1/gitea.1 && echo man/man1/gitea.1.gz created
|
||||||
@#TODO A small script that formats config-cheat-sheet.en-us.md nicely for use as a config man page
|
@#TODO A small script that formats config-cheat-sheet.en-us.md nicely for use as a config man page
|
||||||
|
|
||||||
|
.PHONY: pr\#%
|
||||||
|
pr\#%: clean-all
|
||||||
|
$(GO) run contrib/pr/checkout.go $*
|
||||||
|
|
||||||
|
.PHONY: golangci-lint
|
||||||
|
golangci-lint:
|
||||||
|
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
||||||
|
|
||||||
|
# workaround step for the lint-backend-windows CI task because 'go run' can not
|
||||||
|
# have distinct GOOS/GOARCH for its build and run steps
|
||||||
|
.PHONY: golangci-lint-windows
|
||||||
|
golangci-lint-windows:
|
||||||
|
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||||
|
golangci-lint run
|
||||||
|
|
||||||
|
.PHONY: editorconfig-checker
|
||||||
|
editorconfig-checker:
|
||||||
|
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates
|
||||||
|
|
||||||
.PHONY: docker
|
.PHONY: docker
|
||||||
docker:
|
docker:
|
||||||
docker build --disable-content-trust=false -t $(DOCKER_REF) .
|
docker build --disable-content-trust=false -t $(DOCKER_REF) .
|
||||||
# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" .
|
# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" .
|
||||||
|
|
||||||
|
.PHONY: docker-build
|
||||||
|
docker-build:
|
||||||
|
docker run -ti --rm -v "$(CURDIR):/srv/app/src/code.gitea.io/gitea" -w /srv/app/src/code.gitea.io/gitea -e TAGS="bindata $(TAGS)" LDFLAGS="$(LDFLAGS)" CGO_EXTRA_CFLAGS="$(CGO_EXTRA_CFLAGS)" webhippie/golang:edge make clean build
|
||||||
|
|
||||||
# This endif closes the if at the top of the file
|
# This endif closes the if at the top of the file
|
||||||
endif
|
endif
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -86,7 +86,7 @@ When building from the official source tarballs which include pre-built frontend
|
|||||||
|
|
||||||
Parallelism (`make -j <num>`) is not supported.
|
Parallelism (`make -j <num>`) is not supported.
|
||||||
|
|
||||||
More info: https://docs.gitea.com/installation/install-from-source
|
More info: https://docs.gitea.io/en-us/install-from-source/
|
||||||
|
|
||||||
## Using
|
## Using
|
||||||
|
|
||||||
@@ -110,13 +110,13 @@ Translations are done through Crowdin. If you want to translate to a new languag
|
|||||||
|
|
||||||
You can also just create an issue for adding a language or ask on discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty but we hope to fill it as questions pop up.
|
You can also just create an issue for adding a language or ask on discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty but we hope to fill it as questions pop up.
|
||||||
|
|
||||||
https://docs.gitea.com/contributing/localization
|
https://docs.gitea.io/en-us/translation-guidelines/
|
||||||
|
|
||||||
[](https://crowdin.com/project/gitea)
|
[](https://crowdin.com/project/gitea)
|
||||||
|
|
||||||
## Further information
|
## Further information
|
||||||
|
|
||||||
For more information and instructions about how to install Gitea, please look at our [documentation](https://docs.gitea.com).
|
For more information and instructions about how to install Gitea, please look at our [documentation](https://docs.gitea.io/en-us/).
|
||||||
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://discourse.gitea.io/).
|
||||||
|
|
||||||
We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea).
|
We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea).
|
||||||
@@ -173,8 +173,8 @@ for the full license text.
|
|||||||
|
|
||||||
Looking for an overview of the interface? Check it out!
|
Looking for an overview of the interface? Check it out!
|
||||||
|
|
||||||
||||
|
||||
|
||||||
|:---:|:---:|:---:|
|
|:---:|:---:|:---:|
|
||||||
||||
|
||||
|
||||||
|||
|
|||
|
||||||
|||
|
|||
|
||||||
|
|||||||
10
README_ZH.md
10
README_ZH.md
@@ -68,7 +68,7 @@ Gitea 的首要目标是创建一个极易安装,运行非常快速,安装
|
|||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
关于如何安装请访问我们的 [文档站](https://docs.gitea.com/zh-cn/category/installation),如果没有找到对应的文档,你也可以通过 [Discord - 英文](https://discord.gg/gitea) 和 QQ群 328432459 来和我们交流。
|
关于如何安装请访问我们的 [文档站](https://docs.gitea.io/zh-cn/),如果没有找到对应的文档,你也可以通过 [Discord - 英文](https://discord.gg/gitea) 和 QQ群 328432459 来和我们交流。
|
||||||
|
|
||||||
## 贡献流程
|
## 贡献流程
|
||||||
|
|
||||||
@@ -91,8 +91,8 @@ Fork -> Patch -> Push -> Pull Request
|
|||||||
|
|
||||||
## 截图
|
## 截图
|
||||||
|
|
||||||
||||
|
||||
|
||||||
|:---:|:---:|:---:|
|
|:---:|:---:|:---:|
|
||||||
||||
|
||||
|
||||||
|||
|
|||
|
||||||
|||
|
|||
|
||||||
|
|||||||
115
assets/go-licenses.json
generated
115
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
1
build.go
1
build.go
@@ -1,6 +1,7 @@
|
|||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
|
||||||
//go:build vendor
|
//go:build vendor
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
//go:build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if len(os.Args) != 2 {
|
|
||||||
println("usage: backport-locales <to-ref>")
|
|
||||||
println("eg: backport-locales release/v1.19")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
mustNoErr := func(err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
collectInis := func(ref string) map[string]setting.ConfigProvider {
|
|
||||||
inis := map[string]setting.ConfigProvider{}
|
|
||||||
err := filepath.WalkDir("options/locale", func(path string, d os.DirEntry, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if d.IsDir() || !strings.HasSuffix(d.Name(), ".ini") {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
cfg, err := setting.NewConfigProviderForLocale(path)
|
|
||||||
mustNoErr(err)
|
|
||||||
inis[path] = cfg
|
|
||||||
fmt.Printf("collecting: %s @ %s\n", path, ref)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
mustNoErr(err)
|
|
||||||
return inis
|
|
||||||
}
|
|
||||||
|
|
||||||
// collect new locales from current working directory
|
|
||||||
inisNew := collectInis("HEAD")
|
|
||||||
|
|
||||||
// switch to the target ref, and collect the old locales
|
|
||||||
cmd := exec.Command("git", "checkout", os.Args[1])
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
mustNoErr(cmd.Run())
|
|
||||||
inisOld := collectInis(os.Args[1])
|
|
||||||
|
|
||||||
// use old en-US as the base, and copy the new translations to the old locales
|
|
||||||
enUsOld := inisOld["options/locale/locale_en-US.ini"]
|
|
||||||
brokenWarned := map[string]bool{}
|
|
||||||
for path, iniOld := range inisOld {
|
|
||||||
if iniOld == enUsOld {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
iniNew := inisNew[path]
|
|
||||||
if iniNew == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, secEnUS := range enUsOld.Sections() {
|
|
||||||
secOld := iniOld.Section(secEnUS.Name())
|
|
||||||
secNew := iniNew.Section(secEnUS.Name())
|
|
||||||
for _, keyEnUs := range secEnUS.Keys() {
|
|
||||||
if secNew.HasKey(keyEnUs.Name()) {
|
|
||||||
oldStr := secOld.Key(keyEnUs.Name()).String()
|
|
||||||
newStr := secNew.Key(keyEnUs.Name()).String()
|
|
||||||
broken := oldStr != "" && strings.Count(oldStr, "%") != strings.Count(newStr, "%")
|
|
||||||
broken = broken || strings.Contains(oldStr, "\n") || strings.Contains(oldStr, "\n")
|
|
||||||
if broken {
|
|
||||||
brokenWarned[secOld.Name()+"."+keyEnUs.Name()] = true
|
|
||||||
fmt.Println("----")
|
|
||||||
fmt.Printf("WARNING: skip broken locale: %s , [%s] %s\n", path, secEnUS.Name(), keyEnUs.Name())
|
|
||||||
fmt.Printf("\told: %s\n", strings.ReplaceAll(oldStr, "\n", "\\n"))
|
|
||||||
fmt.Printf("\tnew: %s\n", strings.ReplaceAll(newStr, "\n", "\\n"))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
secOld.Key(keyEnUs.Name()).SetValue(newStr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mustNoErr(iniOld.SaveTo(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("========")
|
|
||||||
|
|
||||||
for path, iniNew := range inisNew {
|
|
||||||
for _, sec := range iniNew.Sections() {
|
|
||||||
for _, key := range sec.Keys() {
|
|
||||||
str := sec.Key(key.Name()).String()
|
|
||||||
broken := strings.Contains(str, "\n")
|
|
||||||
broken = broken || strings.HasPrefix(str, "`") != strings.HasSuffix(str, "`")
|
|
||||||
broken = broken || strings.HasPrefix(str, "\"`")
|
|
||||||
broken = broken || strings.HasPrefix(str, "`\"")
|
|
||||||
broken = broken || strings.Count(str, `"`)%2 == 1
|
|
||||||
broken = broken || strings.Count(str, "`")%2 == 1
|
|
||||||
if broken && !brokenWarned[sec.Name()+"."+key.Name()] {
|
|
||||||
fmt.Printf("WARNING: found broken locale: %s , [%s] %s\n", path, sec.Name(), key.Name())
|
|
||||||
fmt.Printf("\tstr: %s\n", strings.ReplaceAll(str, "\n", "\\n"))
|
|
||||||
fmt.Println("----")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -25,7 +25,7 @@ import (
|
|||||||
|
|
||||||
var optionLogVerbose bool
|
var optionLogVerbose bool
|
||||||
|
|
||||||
func logVerbose(msg string, args ...any) {
|
func logVerbose(msg string, args ...interface{}) {
|
||||||
if optionLogVerbose {
|
if optionLogVerbose {
|
||||||
log.Printf(msg, args...)
|
log.Printf(msg, args...)
|
||||||
}
|
}
|
||||||
@@ -65,6 +65,7 @@ func newFileCollector(fileFilter string, batchSize int) (*fileCollector, error)
|
|||||||
"modules",
|
"modules",
|
||||||
"routers",
|
"routers",
|
||||||
"services",
|
"services",
|
||||||
|
"tools",
|
||||||
}
|
}
|
||||||
co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`))
|
co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`))
|
||||||
|
|
||||||
|
|||||||
@@ -60,13 +60,13 @@ func main() {
|
|||||||
// generate data
|
// generate data
|
||||||
buf, err := generate()
|
buf, err := generate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("generate err: %v", err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write
|
// write
|
||||||
err = os.WriteFile(*flagOut, buf, 0o644)
|
err = os.WriteFile(*flagOut, buf, 0o644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("WriteFile err: %v", err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
goPath "path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -28,47 +27,14 @@ type LicenseEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) != 3 {
|
|
||||||
fmt.Println("usage: go run generate-go-licenses.go <base-dir> <out-json-file>")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
base, out := os.Args[1], os.Args[2]
|
base, out := os.Args[1], os.Args[2]
|
||||||
|
|
||||||
// Add ext for excluded files because license_test.go will be included for some reason.
|
paths := []string{}
|
||||||
// And there are more files that should be excluded, check with:
|
|
||||||
//
|
|
||||||
// go run github.com/google/go-licenses@v1.6.0 save . --force --save_path=.go-licenses 2>/dev/null
|
|
||||||
// find .go-licenses -type f | while read FILE; do echo "${$(basename $FILE)##*.}"; done | sort -u
|
|
||||||
// AUTHORS
|
|
||||||
// COPYING
|
|
||||||
// LICENSE
|
|
||||||
// Makefile
|
|
||||||
// NOTICE
|
|
||||||
// gitignore
|
|
||||||
// go
|
|
||||||
// md
|
|
||||||
// mod
|
|
||||||
// sum
|
|
||||||
// toml
|
|
||||||
// txt
|
|
||||||
// yml
|
|
||||||
//
|
|
||||||
// It could be removed once we have a better regex.
|
|
||||||
excludedExt := map[string]bool{
|
|
||||||
".gitignore": true,
|
|
||||||
".go": true,
|
|
||||||
".mod": true,
|
|
||||||
".sum": true,
|
|
||||||
".toml": true,
|
|
||||||
".yml": true,
|
|
||||||
}
|
|
||||||
var paths []string
|
|
||||||
err := filepath.WalkDir(base, func(path string, entry fs.DirEntry, err error) error {
|
err := filepath.WalkDir(base, func(path string, entry fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if entry.IsDir() || !licenseRe.MatchString(entry.Name()) || excludedExt[filepath.Ext(entry.Name())] {
|
if entry.IsDir() || !licenseRe.MatchString(entry.Name()) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
paths = append(paths, path)
|
paths = append(paths, path)
|
||||||
@@ -80,27 +46,28 @@ func main() {
|
|||||||
|
|
||||||
sort.Strings(paths)
|
sort.Strings(paths)
|
||||||
|
|
||||||
var entries []LicenseEntry
|
entries := []LicenseEntry{}
|
||||||
for _, filePath := range paths {
|
for _, path := range paths {
|
||||||
licenseText, err := os.ReadFile(filePath)
|
path := filepath.ToSlash(path)
|
||||||
|
|
||||||
|
licenseText, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgPath := filepath.ToSlash(filePath)
|
path = strings.Replace(path, base+"/", "", 1)
|
||||||
pkgPath = strings.TrimPrefix(pkgPath, base+"/")
|
name := goPath.Dir(path)
|
||||||
pkgName := path.Dir(pkgPath)
|
|
||||||
|
|
||||||
// There might be a bug somewhere in go-licenses that sometimes interprets the
|
// There might be a bug somewhere in go-licenses that sometimes interprets the
|
||||||
// root package as "." and sometimes as "code.gitea.io/gitea". Workaround by
|
// root package as "." and sometimes as "code.gitea.io/gitea". Workaround by
|
||||||
// removing both of them for the sake of stable output.
|
// removing both of them for the sake of stable output.
|
||||||
if pkgName == "." || pkgName == "code.gitea.io/gitea" {
|
if name == "." || name == "code.gitea.io/gitea" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
entries = append(entries, LicenseEntry{
|
entries = append(entries, LicenseEntry{
|
||||||
Name: pkgName,
|
Name: name,
|
||||||
Path: pkgPath,
|
Path: path,
|
||||||
LicenseText: string(licenseText),
|
LicenseText: string(licenseText),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -110,11 +77,6 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure file has a final newline
|
|
||||||
if jsonBytes[len(jsonBytes)-1] != '\n' {
|
|
||||||
jsonBytes = append(jsonBytes, '\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.WriteFile(out, jsonBytes, 0o644)
|
err = os.WriteFile(out, jsonBytes, 0o644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
@@ -25,22 +25,14 @@ async function processFile(file, {prefix, fullName} = {}) {
|
|||||||
if (prefix === 'octicon') name = name.replace(/-[0-9]+$/, ''); // chop of '-16' on octicons
|
if (prefix === 'octicon') name = name.replace(/-[0-9]+$/, ''); // chop of '-16' on octicons
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the `xmlns` attribute so that the files are displayable in standalone documents
|
|
||||||
// The svg backend module will strip the attribute during startup for inline display
|
|
||||||
const {data} = optimize(await readFile(file, 'utf8'), {
|
const {data} = optimize(await readFile(file, 'utf8'), {
|
||||||
plugins: [
|
plugins: [
|
||||||
{name: 'preset-default'},
|
{name: 'preset-default'},
|
||||||
|
{name: 'removeXMLNS'},
|
||||||
{name: 'removeDimensions'},
|
{name: 'removeDimensions'},
|
||||||
{name: 'prefixIds', params: {prefix: () => name}},
|
{name: 'prefixIds', params: {prefix: () => name}},
|
||||||
{name: 'addClassesToSVGElement', params: {classNames: ['svg', name]}},
|
{name: 'addClassesToSVGElement', params: {classNames: ['svg', name]}},
|
||||||
{
|
{name: 'addAttributesToSVGElement', params: {attributes: [{'width': '16'}, {'height': '16'}, {'aria-hidden': 'true'}]}},
|
||||||
name: 'addAttributesToSVGElement', params: {
|
|
||||||
attributes: [
|
|
||||||
{'xmlns': 'http://www.w3.org/2000/svg'},
|
|
||||||
{'width': '16'}, {'height': '16'}, {'aria-hidden': 'true'},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
//go:build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
_, err := io.Copy(os.Stdout, os.Stdin)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +1,14 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
# this script runs in alpine image which only has `sh` shell
|
|
||||||
|
|
||||||
set +e
|
|
||||||
if sed --version 2>/dev/null | grep -q GNU; then
|
|
||||||
SED_INPLACE="sed -i"
|
|
||||||
else
|
|
||||||
SED_INPLACE="sed -i ''"
|
|
||||||
fi
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ ! -f ./options/locale/locale_en-US.ini ]; then
|
|
||||||
echo "please run this script in the root directory of the project"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv ./options/locale/locale_en-US.ini ./options/
|
mv ./options/locale/locale_en-US.ini ./options/
|
||||||
|
|
||||||
# the "ini" library for locale has many quirks, its behavior is different from Crowdin.
|
# Make sure to only change lines that have the translation enclosed between quotes
|
||||||
# see i18n_test.go for more details
|
sed -i -r -e '/^[a-zA-Z0-9_.-]+[ ]*=[ ]*".*"$/ {
|
||||||
|
s/^([a-zA-Z0-9_.-]+)[ ]*="/\1=/
|
||||||
# this script helps to unquote the Crowdin outputs for the quirky ini library
|
|
||||||
# * find all `key="...\"..."` lines
|
|
||||||
# * remove the leading quote
|
|
||||||
# * remove the trailing quote
|
|
||||||
# * unescape the quotes
|
|
||||||
# * eg: key="...\"..." => key=..."...
|
|
||||||
$SED_INPLACE -r -e '/^[-.A-Za-z0-9_]+[ ]*=[ ]*".*"$/ {
|
|
||||||
s/^([-.A-Za-z0-9_]+)[ ]*=[ ]*"/\1=/
|
|
||||||
s/"$//
|
|
||||||
s/\\"/"/g
|
s/\\"/"/g
|
||||||
|
s/"$//
|
||||||
}' ./options/locale/*.ini
|
}' ./options/locale/*.ini
|
||||||
|
|
||||||
# * if the escaped line is incomplete like `key="...` or `key=..."`, quote it with backticks
|
|
||||||
# * eg: key="... => key=`"...`
|
|
||||||
# * eg: key=..." => key=`..."`
|
|
||||||
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*(".*[^"])$/\1=`\2`/' ./options/locale/*.ini
|
|
||||||
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*([^"].*")$/\1=`\2`/' ./options/locale/*.ini
|
|
||||||
|
|
||||||
# Remove translation under 25% of en_us
|
# Remove translation under 25% of en_us
|
||||||
baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1)
|
baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1)
|
||||||
baselines=$((baselines / 4))
|
baselines=$((baselines / 4))
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
make --no-print-directory watch-frontend &
|
|
||||||
make --no-print-directory watch-backend &
|
|
||||||
|
|
||||||
trap 'kill $(jobs -p)' EXIT
|
|
||||||
wait
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/private"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// CmdActions represents the available actions sub-commands.
|
|
||||||
CmdActions = cli.Command{
|
|
||||||
Name: "actions",
|
|
||||||
Usage: "",
|
|
||||||
Description: "Commands for managing Gitea Actions",
|
|
||||||
Subcommands: []cli.Command{
|
|
||||||
subcmdActionsGenRunnerToken,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
subcmdActionsGenRunnerToken = cli.Command{
|
|
||||||
Name: "generate-runner-token",
|
|
||||||
Usage: "Generate a new token for a runner to use to register with the server",
|
|
||||||
Action: runGenerateActionsRunnerToken,
|
|
||||||
Aliases: []string{"grt"},
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "scope, s",
|
|
||||||
Value: "",
|
|
||||||
Usage: "{owner}[/{repo}] - leave empty for a global runner",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func runGenerateActionsRunnerToken(c *cli.Context) error {
|
|
||||||
ctx, cancel := installSignals()
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
setting.MustInstalled()
|
|
||||||
|
|
||||||
scope := c.String("scope")
|
|
||||||
|
|
||||||
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
|
|
||||||
if extra.HasError() {
|
|
||||||
return handleCliResponseExtra(extra)
|
|
||||||
}
|
|
||||||
_, _ = fmt.Printf("%s\n", respText)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
15
cmd/admin.go
15
cmd/admin.go
@@ -7,7 +7,6 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
@@ -348,10 +347,6 @@ func runRepoSyncReleases(_ *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := git.InitSimple(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Trace("Synchronizing repository releases (this may take a while)")
|
log.Trace("Synchronizing repository releases (this may take a while)")
|
||||||
for page := 1; ; page++ {
|
for page := 1; ; page++ {
|
||||||
repos, count, err := repo_model.SearchRepositoryByName(ctx, &repo_model.SearchRepoOptions{
|
repos, count, err := repo_model.SearchRepositoryByName(ctx, &repo_model.SearchRepoOptions{
|
||||||
@@ -474,19 +469,11 @@ func runAddOauth(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
config := parseOAuth2Config(c)
|
|
||||||
if config.Provider == "openidConnect" {
|
|
||||||
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
|
|
||||||
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
|
|
||||||
return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return auth_model.CreateSource(&auth_model.Source{
|
return auth_model.CreateSource(&auth_model.Source{
|
||||||
Type: auth_model.OAuth2,
|
Type: auth_model.OAuth2,
|
||||||
Name: c.String("name"),
|
Name: c.String("name"),
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
Cfg: config,
|
Cfg: parseOAuth2Config(c),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,28 +55,17 @@ func runGenerateAccessToken(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct token with name and user so we can make sure it is unique
|
accessTokenScope, err := auth_model.AccessTokenScope(c.String("scopes")).Normalize()
|
||||||
t := &auth_model.AccessToken{
|
|
||||||
Name: c.String("token-name"),
|
|
||||||
UID: user.ID,
|
|
||||||
}
|
|
||||||
|
|
||||||
exist, err := auth_model.AccessTokenByNameExists(t)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if exist {
|
|
||||||
return fmt.Errorf("access token name has been used already")
|
t := &auth_model.AccessToken{
|
||||||
|
Name: c.String("token-name"),
|
||||||
|
UID: user.ID,
|
||||||
|
Scope: accessTokenScope,
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the scopes are valid
|
|
||||||
accessTokenScope, err := auth_model.AccessTokenScope(c.String("scopes")).Normalize()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid access token scope provided: %w", err)
|
|
||||||
}
|
|
||||||
t.Scope = accessTokenScope
|
|
||||||
|
|
||||||
// create the token
|
|
||||||
if err := auth_model.NewAccessToken(t); err != nil {
|
if err := auth_model.NewAccessToken(t); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func publicKey(priv any) any {
|
func publicKey(priv interface{}) interface{} {
|
||||||
switch k := priv.(type) {
|
switch k := priv.(type) {
|
||||||
case *rsa.PrivateKey:
|
case *rsa.PrivateKey:
|
||||||
return &k.PublicKey
|
return &k.PublicKey
|
||||||
@@ -74,7 +74,7 @@ func publicKey(priv any) any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pemBlockForKey(priv any) *pem.Block {
|
func pemBlockForKey(priv interface{}) *pem.Block {
|
||||||
switch k := priv.(type) {
|
switch k := priv.(type) {
|
||||||
case *rsa.PrivateKey:
|
case *rsa.PrivateKey:
|
||||||
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
|
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
|
||||||
@@ -94,7 +94,7 @@ func runCert(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var priv any
|
var priv interface{}
|
||||||
var err error
|
var err error
|
||||||
switch c.String("ecdsa-curve") {
|
switch c.String("ecdsa-curve") {
|
||||||
case "":
|
case "":
|
||||||
|
|||||||
36
cmd/cmd.go
36
cmd/cmd.go
@@ -9,7 +9,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -58,9 +57,10 @@ func confirm() (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initDB(ctx context.Context) error {
|
func initDB(ctx context.Context) error {
|
||||||
setting.MustInstalled()
|
setting.InitProviderFromExistingFile()
|
||||||
|
setting.LoadCommonSettings()
|
||||||
setting.LoadDBSetting()
|
setting.LoadDBSetting()
|
||||||
setting.InitSQLLoggersForCli(log.INFO)
|
setting.InitSQLLog(false)
|
||||||
|
|
||||||
if setting.Database.Type == "" {
|
if setting.Database.Type == "" {
|
||||||
log.Fatal(`Database settings are missing from the configuration file: %q.
|
log.Fatal(`Database settings are missing from the configuration file: %q.
|
||||||
@@ -94,33 +94,3 @@ func installSignals() (context.Context, context.CancelFunc) {
|
|||||||
|
|
||||||
return ctx, cancel
|
return ctx, cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupConsoleLogger(level log.Level, colorize bool, out io.Writer) {
|
|
||||||
if out != os.Stdout && out != os.Stderr {
|
|
||||||
panic("setupConsoleLogger can only be used with os.Stdout or os.Stderr")
|
|
||||||
}
|
|
||||||
|
|
||||||
writeMode := log.WriterMode{
|
|
||||||
Level: level,
|
|
||||||
Colorize: colorize,
|
|
||||||
WriterOption: log.WriterConsoleOption{Stderr: out == os.Stderr},
|
|
||||||
}
|
|
||||||
writer := log.NewEventWriterConsole("console-default", writeMode)
|
|
||||||
log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrepareConsoleLoggerLevel by default, use INFO level for console logger, but some sub-commands (for git/ssh protocol) shouldn't output any log to stdout.
|
|
||||||
// Any log appears in git stdout pipe will break the git protocol, eg: client can't push and hangs forever.
|
|
||||||
func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(*cli.Context) error {
|
|
||||||
return func(c *cli.Context) error {
|
|
||||||
level := defaultLevel
|
|
||||||
if c.Bool("quiet") || c.GlobalBoolT("quiet") {
|
|
||||||
level = log.FATAL
|
|
||||||
}
|
|
||||||
if c.Bool("debug") || c.GlobalBool("debug") || c.Bool("verbose") || c.GlobalBool("verbose") {
|
|
||||||
level = log.TRACE
|
|
||||||
}
|
|
||||||
log.SetConsoleLogger(log.DEFAULT, "console-default", level)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
var CmdConvert = cli.Command{
|
var CmdConvert = cli.Command{
|
||||||
Name: "convert",
|
Name: "convert",
|
||||||
Usage: "Convert the database",
|
Usage: "Convert the database",
|
||||||
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4 or MSSQL database from varchar to nvarchar",
|
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
||||||
Action: runConvert,
|
Action: runConvert,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,22 +35,17 @@ func runConvert(ctx *cli.Context) error {
|
|||||||
log.Info("Log path: %s", setting.Log.RootPath)
|
log.Info("Log path: %s", setting.Log.RootPath)
|
||||||
log.Info("Configuration file: %s", setting.CustomConf)
|
log.Info("Configuration file: %s", setting.CustomConf)
|
||||||
|
|
||||||
switch {
|
if !setting.Database.UseMySQL {
|
||||||
case setting.Database.Type.IsMySQL():
|
fmt.Println("This command can only be used with a MySQL database")
|
||||||
if err := db.ConvertUtf8ToUtf8mb4(); err != nil {
|
return nil
|
||||||
log.Fatal("Failed to convert database from utf8 to utf8mb4: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4")
|
|
||||||
case setting.Database.Type.IsMSSQL():
|
|
||||||
if err := db.ConvertVarcharToNVarchar(); err != nil {
|
|
||||||
log.Fatal("Failed to convert database from varchar to nvarchar: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println("Converted successfully, please confirm your database's all columns character is NVARCHAR now")
|
|
||||||
default:
|
|
||||||
fmt.Println("This command can only be used with a MySQL or MSSQL database")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := db.ConvertUtf8ToUtf8mb4(); err != nil {
|
||||||
|
log.Fatal("Failed to convert database from utf8 to utf8mb4: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
golog "log"
|
golog "log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
@@ -82,25 +82,24 @@ You should back-up your database before doing this and ensure that your database
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runRecreateTable(ctx *cli.Context) error {
|
func runRecreateTable(ctx *cli.Context) error {
|
||||||
stdCtx, cancel := installSignals()
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// Redirect the default golog to here
|
// Redirect the default golog to here
|
||||||
golog.SetFlags(0)
|
golog.SetFlags(0)
|
||||||
golog.SetPrefix("")
|
golog.SetPrefix("")
|
||||||
golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info))
|
golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
|
||||||
|
|
||||||
debug := ctx.Bool("debug")
|
setting.InitProviderFromExistingFile()
|
||||||
setting.MustInstalled()
|
setting.LoadCommonSettings()
|
||||||
setting.LoadDBSetting()
|
setting.LoadDBSetting()
|
||||||
|
|
||||||
if debug {
|
setting.Log.EnableXORMLog = ctx.Bool("debug")
|
||||||
setting.InitSQLLoggersForCli(log.DEBUG)
|
setting.Database.LogSQL = ctx.Bool("debug")
|
||||||
} else {
|
// FIXME: don't use CfgProvider directly
|
||||||
setting.InitSQLLoggersForCli(log.INFO)
|
setting.CfgProvider.Section("log").Key("XORM").SetValue(",")
|
||||||
}
|
|
||||||
|
setting.InitSQLLog(!ctx.Bool("debug"))
|
||||||
|
stdCtx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setting.Database.LogSQL = debug
|
|
||||||
if err := db.InitEngine(stdCtx); err != nil {
|
if err := db.InitEngine(stdCtx); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Check if you are using the right config file. You can use a --config directive to specify one.")
|
fmt.Println("Check if you are using the right config file. You can use a --config directive to specify one.")
|
||||||
@@ -127,31 +126,44 @@ func runRecreateTable(ctx *cli.Context) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) {
|
func setDoctorLogger(ctx *cli.Context) {
|
||||||
// Silence the default loggers
|
|
||||||
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
|
|
||||||
|
|
||||||
logFile := ctx.String("log-file")
|
logFile := ctx.String("log-file")
|
||||||
if !ctx.IsSet("log-file") {
|
if !ctx.IsSet("log-file") {
|
||||||
logFile = "doctor.log"
|
logFile = "doctor.log"
|
||||||
}
|
}
|
||||||
|
colorize := log.CanColorStdout
|
||||||
|
if ctx.IsSet("color") {
|
||||||
|
colorize = ctx.Bool("color")
|
||||||
|
}
|
||||||
|
|
||||||
if len(logFile) == 0 {
|
if len(logFile) == 0 {
|
||||||
// if no doctor log-file is set, do not show any log from default logger
|
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"NONE","stacktracelevel":"NONE","colorize":%t}`, colorize))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if logFile == "-" {
|
defer func() {
|
||||||
setupConsoleLogger(log.TRACE, colorize, os.Stdout)
|
recovered := recover()
|
||||||
} else {
|
if recovered == nil {
|
||||||
logFile, _ = filepath.Abs(logFile)
|
|
||||||
writeMode := log.WriterMode{Level: log.TRACE, WriterOption: log.WriterFileOption{FileName: logFile}}
|
|
||||||
writer, err := log.NewEventWriter("console-to-file", "file", writeMode)
|
|
||||||
if err != nil {
|
|
||||||
log.FallbackErrorf("unable to create file log writer: %v", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer)
|
|
||||||
|
err, ok := recovered.(error)
|
||||||
|
if !ok {
|
||||||
|
panic(recovered)
|
||||||
|
}
|
||||||
|
if errors.Is(err, os.ErrPermission) {
|
||||||
|
fmt.Fprintf(os.Stderr, "ERROR: Unable to write logs to provided file due to permissions error: %s\n %v\n", logFile, err)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(os.Stderr, "ERROR: Unable to write logs to provided file: %s\n %v\n", logFile, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "WARN: Logging will be disabled\n Use `--log-file` to configure log file location\n")
|
||||||
|
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"NONE","stacktracelevel":"NONE","colorize":%t}`, colorize))
|
||||||
|
}()
|
||||||
|
|
||||||
|
if logFile == "-" {
|
||||||
|
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"trace","stacktracelevel":"NONE","colorize":%t}`, colorize))
|
||||||
|
} else {
|
||||||
|
log.NewLogger(1000, "doctor", "file", fmt.Sprintf(`{"filename":%q,"level":"trace","stacktracelevel":"NONE"}`, logFile))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,17 +171,22 @@ func runDoctor(ctx *cli.Context) error {
|
|||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
// Silence the default loggers
|
||||||
|
log.DelNamedLogger("console")
|
||||||
|
log.DelNamedLogger(log.DEFAULT)
|
||||||
|
|
||||||
|
// Now setup our own
|
||||||
|
setDoctorLogger(ctx)
|
||||||
|
|
||||||
colorize := log.CanColorStdout
|
colorize := log.CanColorStdout
|
||||||
if ctx.IsSet("color") {
|
if ctx.IsSet("color") {
|
||||||
colorize = ctx.Bool("color")
|
colorize = ctx.Bool("color")
|
||||||
}
|
}
|
||||||
|
|
||||||
setupDoctorDefaultLogger(ctx, colorize)
|
// Finally redirect the default golog to here
|
||||||
|
|
||||||
// Finally redirect the default golang's log to here
|
|
||||||
golog.SetFlags(0)
|
golog.SetFlags(0)
|
||||||
golog.SetPrefix("")
|
golog.SetPrefix("")
|
||||||
golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info))
|
golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
|
||||||
|
|
||||||
if ctx.IsSet("list") {
|
if ctx.IsSet("list") {
|
||||||
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
|
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
|
||||||
@@ -217,5 +234,17 @@ func runDoctor(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return doctor.RunChecks(stdCtx, colorize, ctx.Bool("fix"), checks)
|
// Now we can set up our own logger to return information about what the doctor is doing
|
||||||
|
if err := log.NewNamedLogger("doctorouter",
|
||||||
|
0,
|
||||||
|
"console",
|
||||||
|
"console",
|
||||||
|
fmt.Sprintf(`{"level":"INFO","stacktracelevel":"NONE","colorize":%t,"flags":-1}`, colorize)); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := log.GetLogger("doctorouter")
|
||||||
|
defer logger.Close()
|
||||||
|
return doctor.RunChecks(stdCtx, logger, ctx.Bool("fix"), checks)
|
||||||
}
|
}
|
||||||
|
|||||||
48
cmd/dump.go
48
cmd/dump.go
@@ -112,10 +112,6 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
|
|||||||
Name: "verbose, V",
|
Name: "verbose, V",
|
||||||
Usage: "Show process details",
|
Usage: "Show process details",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
|
||||||
Name: "quiet, q",
|
|
||||||
Usage: "Only display warnings and errors",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "tempdir, t",
|
Name: "tempdir, t",
|
||||||
Value: os.TempDir(),
|
Value: os.TempDir(),
|
||||||
@@ -161,7 +157,7 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func fatal(format string, args ...any) {
|
func fatal(format string, args ...interface{}) {
|
||||||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||||||
log.Fatal(format, args...)
|
log.Fatal(format, args...)
|
||||||
}
|
}
|
||||||
@@ -172,7 +168,10 @@ func runDump(ctx *cli.Context) error {
|
|||||||
outType := ctx.String("type")
|
outType := ctx.String("type")
|
||||||
if fileName == "-" {
|
if fileName == "-" {
|
||||||
file = os.Stdout
|
file = os.Stdout
|
||||||
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
|
err := log.DelLogger("console")
|
||||||
|
if err != nil {
|
||||||
|
fatal("Deleting default logger failed. Can not write to stdout: %v", err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, suffix := range outputTypeEnum.Enum {
|
for _, suffix := range outputTypeEnum.Enum {
|
||||||
if strings.HasSuffix(fileName, "."+suffix) {
|
if strings.HasSuffix(fileName, "."+suffix) {
|
||||||
@@ -182,7 +181,8 @@ func runDump(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
fileName += "." + outType
|
fileName += "." + outType
|
||||||
}
|
}
|
||||||
setting.MustInstalled()
|
setting.InitProviderFromExistingFile()
|
||||||
|
setting.LoadCommonSettings()
|
||||||
|
|
||||||
// make sure we are logging to the console no matter what the configuration tells us do to
|
// make sure we are logging to the console no matter what the configuration tells us do to
|
||||||
// FIXME: don't use CfgProvider directly
|
// FIXME: don't use CfgProvider directly
|
||||||
@@ -192,25 +192,12 @@ func runDump(ctx *cli.Context) error {
|
|||||||
if _, err := setting.CfgProvider.Section("log.console").NewKey("STDERR", "true"); err != nil {
|
if _, err := setting.CfgProvider.Section("log.console").NewKey("STDERR", "true"); err != nil {
|
||||||
fatal("Setting console logger to stderr failed: %v", err)
|
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 {
|
if !setting.InstallLock {
|
||||||
log.Error("Is '%s' really the right config path?\n", setting.CustomConf)
|
log.Error("Is '%s' really the right config path?\n", setting.CustomConf)
|
||||||
return fmt.Errorf("gitea is not initialized")
|
return fmt.Errorf("gitea is not initialized")
|
||||||
}
|
}
|
||||||
setting.LoadSettings() // cannot access session settings otherwise
|
setting.LoadSettings() // cannot access session settings otherwise
|
||||||
|
|
||||||
verbose := ctx.Bool("verbose")
|
|
||||||
if verbose && ctx.Bool("quiet") {
|
|
||||||
return fmt.Errorf("--quiet and --verbose cannot both be set")
|
|
||||||
}
|
|
||||||
|
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -236,7 +223,8 @@ func runDump(ctx *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var iface any
|
verbose := ctx.Bool("verbose")
|
||||||
|
var iface interface{}
|
||||||
if fileName == "-" {
|
if fileName == "-" {
|
||||||
iface, err = archiver.ByExtension(fmt.Sprintf(".%s", outType))
|
iface, err = archiver.ByExtension(fmt.Sprintf(".%s", outType))
|
||||||
} else {
|
} else {
|
||||||
@@ -262,9 +250,7 @@ func runDump(ctx *cli.Context) error {
|
|||||||
|
|
||||||
if ctx.IsSet("skip-lfs-data") && ctx.Bool("skip-lfs-data") {
|
if ctx.IsSet("skip-lfs-data") && ctx.Bool("skip-lfs-data") {
|
||||||
log.Info("Skip dumping LFS data")
|
log.Info("Skip dumping LFS data")
|
||||||
} else if !setting.LFS.StartServer {
|
} else if err := storage.LFS.IterateObjects(func(objPath string, object storage.Object) error {
|
||||||
log.Info("LFS isn't enabled. Skip dumping LFS data")
|
|
||||||
} else if err := storage.LFS.IterateObjects("", func(objPath string, object storage.Object) error {
|
|
||||||
info, err := object.Stat()
|
info, err := object.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -293,7 +279,7 @@ func runDump(ctx *cli.Context) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
targetDBType := ctx.String("database")
|
targetDBType := ctx.String("database")
|
||||||
if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() {
|
if len(targetDBType) > 0 && targetDBType != setting.Database.Type {
|
||||||
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
|
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
|
||||||
} else {
|
} else {
|
||||||
log.Info("Dumping database...")
|
log.Info("Dumping database...")
|
||||||
@@ -353,9 +339,9 @@ func runDump(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
excludes = append(excludes, setting.RepoRootPath)
|
excludes = append(excludes, setting.RepoRootPath)
|
||||||
excludes = append(excludes, setting.LFS.Storage.Path)
|
excludes = append(excludes, setting.LFS.Path)
|
||||||
excludes = append(excludes, setting.Attachment.Storage.Path)
|
excludes = append(excludes, setting.Attachment.Path)
|
||||||
excludes = append(excludes, setting.Packages.Storage.Path)
|
excludes = append(excludes, setting.Packages.Path)
|
||||||
excludes = append(excludes, setting.Log.RootPath)
|
excludes = append(excludes, setting.Log.RootPath)
|
||||||
excludes = append(excludes, absFileName)
|
excludes = append(excludes, absFileName)
|
||||||
if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil {
|
if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil {
|
||||||
@@ -365,7 +351,7 @@ func runDump(ctx *cli.Context) error {
|
|||||||
|
|
||||||
if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") {
|
if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") {
|
||||||
log.Info("Skip dumping attachment data")
|
log.Info("Skip dumping attachment data")
|
||||||
} else if err := storage.Attachments.IterateObjects("", func(objPath string, object storage.Object) error {
|
} else if err := storage.Attachments.IterateObjects(func(objPath string, object storage.Object) error {
|
||||||
info, err := object.Stat()
|
info, err := object.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -378,9 +364,7 @@ func runDump(ctx *cli.Context) error {
|
|||||||
|
|
||||||
if ctx.IsSet("skip-package-data") && ctx.Bool("skip-package-data") {
|
if ctx.IsSet("skip-package-data") && ctx.Bool("skip-package-data") {
|
||||||
log.Info("Skip dumping package data")
|
log.Info("Skip dumping package data")
|
||||||
} else if !setting.Packages.Enabled {
|
} else if err := storage.Packages.IterateObjects(func(objPath string, object storage.Object) error {
|
||||||
log.Info("Packages isn't enabled. Skip dumping package data")
|
|
||||||
} else if err := storage.Packages.IterateObjects("", func(objPath string, object storage.Object) error {
|
|
||||||
info, err := object.Stat()
|
info, err := object.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
130
cmd/embedded.go
130
cmd/embedded.go
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//go:build bindata
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -8,9 +10,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/assetfs"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/options"
|
"code.gitea.io/gitea/modules/options"
|
||||||
"code.gitea.io/gitea/modules/public"
|
"code.gitea.io/gitea/modules/public"
|
||||||
@@ -22,9 +24,9 @@ import (
|
|||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdEmbedded represents the available extract sub-command.
|
// Cmdembedded represents the available extract sub-command.
|
||||||
var (
|
var (
|
||||||
CmdEmbedded = cli.Command{
|
Cmdembedded = cli.Command{
|
||||||
Name: "embedded",
|
Name: "embedded",
|
||||||
Usage: "Extract embedded resources",
|
Usage: "Extract embedded resources",
|
||||||
Description: "A command for extracting embedded resources, like templates and images",
|
Description: "A command for extracting embedded resources, like templates and images",
|
||||||
@@ -87,26 +89,50 @@ var (
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
matchedAssetFiles []assetFile
|
sections map[string]*section
|
||||||
|
assets []asset
|
||||||
)
|
)
|
||||||
|
|
||||||
type assetFile struct {
|
type section struct {
|
||||||
fs *assetfs.LayeredFS
|
Path string
|
||||||
name string
|
Names func() []string
|
||||||
path string
|
IsDir func(string) (bool, error)
|
||||||
|
Asset func(string) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type asset struct {
|
||||||
|
Section *section
|
||||||
|
Name string
|
||||||
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func initEmbeddedExtractor(c *cli.Context) error {
|
func initEmbeddedExtractor(c *cli.Context) error {
|
||||||
setupConsoleLogger(log.ERROR, log.CanColorStderr, os.Stderr)
|
// Silence the console logger
|
||||||
|
log.DelNamedLogger("console")
|
||||||
|
log.DelNamedLogger(log.DEFAULT)
|
||||||
|
|
||||||
patterns, err := compileCollectPatterns(c.Args())
|
// Read configuration file
|
||||||
|
setting.InitProviderAllowEmpty()
|
||||||
|
setting.LoadCommonSettings()
|
||||||
|
|
||||||
|
pats, err := getPatterns(c.Args())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
sections := make(map[string]*section, 3)
|
||||||
|
|
||||||
collectAssetFilesByPattern(c, patterns, "options", options.BuiltinAssets())
|
sections["public"] = §ion{Path: "public", Names: public.AssetNames, IsDir: public.AssetIsDir, Asset: public.Asset}
|
||||||
collectAssetFilesByPattern(c, patterns, "public", public.BuiltinAssets())
|
sections["options"] = §ion{Path: "options", Names: options.AssetNames, IsDir: options.AssetIsDir, Asset: options.Asset}
|
||||||
collectAssetFilesByPattern(c, patterns, "templates", templates.BuiltinAssets())
|
sections["templates"] = §ion{Path: "templates", Names: templates.BuiltinAssetNames, IsDir: templates.BuiltinAssetIsDir, Asset: templates.BuiltinAsset}
|
||||||
|
|
||||||
|
for _, sec := range sections {
|
||||||
|
assets = append(assets, buildAssetList(sec, pats, c)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort assets
|
||||||
|
sort.SliceStable(assets, func(i, j int) bool {
|
||||||
|
return assets[i].Path < assets[j].Path
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -140,8 +166,8 @@ func runListDo(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, a := range matchedAssetFiles {
|
for _, a := range assets {
|
||||||
fmt.Println(a.path)
|
fmt.Println(a.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -152,19 +178,19 @@ func runViewDo(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(matchedAssetFiles) == 0 {
|
if len(assets) == 0 {
|
||||||
return fmt.Errorf("no files matched the given pattern")
|
return fmt.Errorf("No files matched the given pattern")
|
||||||
} else if len(matchedAssetFiles) > 1 {
|
} else if len(assets) > 1 {
|
||||||
return fmt.Errorf("too many files matched the given pattern, try to be more specific")
|
return fmt.Errorf("Too many files matched the given pattern; try to be more specific")
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := matchedAssetFiles[0].fs.ReadFile(matchedAssetFiles[0].name)
|
data, err := assets[0].Section.Asset(assets[0].Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s: %w", matchedAssetFiles[0].path, err)
|
return fmt.Errorf("%s: %w", assets[0].Path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = os.Stdout.Write(data); err != nil {
|
if _, err = os.Stdout.Write(data); err != nil {
|
||||||
return fmt.Errorf("%s: %w", matchedAssetFiles[0].path, err)
|
return fmt.Errorf("%s: %w", assets[0].Path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -176,7 +202,7 @@ func runExtractDo(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(c.Args()) == 0 {
|
if len(c.Args()) == 0 {
|
||||||
return fmt.Errorf("a list of pattern of files to extract is mandatory (e.g. '**' for all)")
|
return fmt.Errorf("A list of pattern of files to extract is mandatory (e.g. '**' for all)")
|
||||||
}
|
}
|
||||||
|
|
||||||
destdir := "."
|
destdir := "."
|
||||||
@@ -201,7 +227,7 @@ func runExtractDo(c *cli.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s: %s", destdir, err)
|
return fmt.Errorf("%s: %s", destdir, err)
|
||||||
} else if !fi.IsDir() {
|
} else if !fi.IsDir() {
|
||||||
return fmt.Errorf("destination %q is not a directory", destdir)
|
return fmt.Errorf("%s is not a directory.", destdir)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Extracting to %s:\n", destdir)
|
fmt.Printf("Extracting to %s:\n", destdir)
|
||||||
@@ -209,23 +235,23 @@ func runExtractDo(c *cli.Context) error {
|
|||||||
overwrite := c.Bool("overwrite")
|
overwrite := c.Bool("overwrite")
|
||||||
rename := c.Bool("rename")
|
rename := c.Bool("rename")
|
||||||
|
|
||||||
for _, a := range matchedAssetFiles {
|
for _, a := range assets {
|
||||||
if err := extractAsset(destdir, a, overwrite, rename); err != nil {
|
if err := extractAsset(destdir, a, overwrite, rename); err != nil {
|
||||||
// Non-fatal error
|
// Non-fatal error
|
||||||
fmt.Fprintf(os.Stderr, "%s: %v", a.path, err)
|
fmt.Fprintf(os.Stderr, "%s: %v", a.Path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractAsset(d string, a assetFile, overwrite, rename bool) error {
|
func extractAsset(d string, a asset, overwrite, rename bool) error {
|
||||||
dest := filepath.Join(d, filepath.FromSlash(a.path))
|
dest := filepath.Join(d, filepath.FromSlash(a.Path))
|
||||||
dir := filepath.Dir(dest)
|
dir := filepath.Dir(dest)
|
||||||
|
|
||||||
data, err := a.fs.ReadFile(a.name)
|
data, err := a.Section.Asset(a.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s: %w", a.path, err)
|
return fmt.Errorf("%s: %w", a.Path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||||
@@ -246,7 +272,7 @@ func extractAsset(d string, a assetFile, overwrite, rename bool) error {
|
|||||||
return fmt.Errorf("%s already exists, but it's not a regular file", dest)
|
return fmt.Errorf("%s already exists, but it's not a regular file", dest)
|
||||||
} else if rename {
|
} else if rename {
|
||||||
if err := util.Rename(dest, dest+".bak"); err != nil {
|
if err := util.Rename(dest, dest+".bak"); err != nil {
|
||||||
return fmt.Errorf("error creating backup for %s: %w", dest, err)
|
return fmt.Errorf("Error creating backup for %s: %w", dest, err)
|
||||||
}
|
}
|
||||||
// Attempt to respect file permissions mask (even if user:group will be set anew)
|
// Attempt to respect file permissions mask (even if user:group will be set anew)
|
||||||
perms = fi.Mode()
|
perms = fi.Mode()
|
||||||
@@ -267,30 +293,32 @@ func extractAsset(d string, a assetFile, overwrite, rename bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectAssetFilesByPattern(c *cli.Context, globs []glob.Glob, path string, layer *assetfs.Layer) {
|
func buildAssetList(sec *section, globs []glob.Glob, c *cli.Context) []asset {
|
||||||
fs := assetfs.Layered(layer)
|
results := make([]asset, 0, 64)
|
||||||
files, err := fs.ListAllFiles(".", true)
|
for _, name := range sec.Names() {
|
||||||
if err != nil {
|
if isdir, err := sec.IsDir(name); !isdir && err == nil {
|
||||||
log.Error("Error listing files in %q: %v", path, err)
|
if sec.Path == "public" &&
|
||||||
return
|
strings.HasPrefix(name, "vendor/") &&
|
||||||
}
|
!c.Bool("include-vendored") {
|
||||||
for _, name := range files {
|
continue
|
||||||
if path == "public" &&
|
}
|
||||||
strings.HasPrefix(name, "vendor/") &&
|
matchName := sec.Path + "/" + name
|
||||||
!c.Bool("include-vendored") {
|
for _, g := range globs {
|
||||||
continue
|
if g.Match(matchName) {
|
||||||
}
|
results = append(results, asset{
|
||||||
matchName := path + "/" + name
|
Section: sec,
|
||||||
for _, g := range globs {
|
Name: name,
|
||||||
if g.Match(matchName) {
|
Path: sec.Path + "/" + name,
|
||||||
matchedAssetFiles = append(matchedAssetFiles, assetFile{fs: fs, name: name, path: path + "/" + name})
|
})
|
||||||
break
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileCollectPatterns(args []string) ([]glob.Glob, error) {
|
func getPatterns(args []string) ([]glob.Glob, error) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
args = []string{"**"}
|
args = []string{"**"}
|
||||||
}
|
}
|
||||||
@@ -298,7 +326,7 @@ func compileCollectPatterns(args []string) ([]glob.Glob, error) {
|
|||||||
for i := range args {
|
for i := range args {
|
||||||
if g, err := glob.Compile(args[i], '/'); err != nil {
|
if g, err := glob.Compile(args[i], '/'); err != nil {
|
||||||
return nil, fmt.Errorf("'%s': Invalid glob pattern: %w", args[i], err)
|
return nil, fmt.Errorf("'%s': Invalid glob pattern: %w", args[i], err)
|
||||||
} else { //nolint:revive
|
} else {
|
||||||
pat[i] = g
|
pat[i] = g
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
cmd/embedded_stub.go
Normal file
29
cmd/embedded_stub.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//go:build !bindata
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cmdembedded represents the available extract sub-command.
|
||||||
|
var (
|
||||||
|
Cmdembedded = cli.Command{
|
||||||
|
Name: "embedded",
|
||||||
|
Usage: "Extract embedded resources",
|
||||||
|
Description: "A command for extracting embedded resources, like templates and images",
|
||||||
|
Action: extractorNotImplemented,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func extractorNotImplemented(c *cli.Context) error {
|
||||||
|
err := fmt.Errorf("Sorry: the 'embedded' subcommand is not available in builds without bindata")
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
163
cmd/hook.go
163
cmd/hook.go
@@ -6,19 +6,19 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
@@ -33,7 +33,6 @@ var (
|
|||||||
Name: "hook",
|
Name: "hook",
|
||||||
Usage: "Delegate commands to corresponding Git hooks",
|
Usage: "Delegate commands to corresponding Git hooks",
|
||||||
Description: "This should only be called by Git",
|
Description: "This should only be called by Git",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []cli.Command{
|
||||||
subcmdHookPreReceive,
|
subcmdHookPreReceive,
|
||||||
subcmdHookUpdate,
|
subcmdHookUpdate,
|
||||||
@@ -142,7 +141,7 @@ func (d *delayWriter) Close() error {
|
|||||||
if d == nil {
|
if d == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
stopped := d.timer.Stop()
|
stopped := util.StopTimer(d.timer)
|
||||||
if stopped || d.buf == nil {
|
if stopped || d.buf == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -168,11 +167,11 @@ func runHookPreReceive(c *cli.Context) error {
|
|||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("hooks/pre-receive.log", c.Bool("debug"))
|
||||||
|
|
||||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||||
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
||||||
return fail(ctx, `Rejecting changes as Gitea environment not set.
|
return fail(`Rejecting changes as Gitea environment not set.
|
||||||
If you are pushing over SSH you must push with a key managed by
|
If you are pushing over SSH you must push with a key managed by
|
||||||
Gitea or set your environment appropriately.`, "")
|
Gitea or set your environment appropriately.`, "")
|
||||||
}
|
}
|
||||||
@@ -203,7 +202,7 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
|
|
||||||
oldCommitIDs := make([]string, hookBatchSize)
|
oldCommitIDs := make([]string, hookBatchSize)
|
||||||
newCommitIDs := make([]string, hookBatchSize)
|
newCommitIDs := make([]string, hookBatchSize)
|
||||||
refFullNames := make([]git.RefName, hookBatchSize)
|
refFullNames := make([]string, hookBatchSize)
|
||||||
count := 0
|
count := 0
|
||||||
total := 0
|
total := 0
|
||||||
lastline := 0
|
lastline := 0
|
||||||
@@ -238,14 +237,14 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
|
|
||||||
oldCommitID := string(fields[0])
|
oldCommitID := string(fields[0])
|
||||||
newCommitID := string(fields[1])
|
newCommitID := string(fields[1])
|
||||||
refFullName := git.RefName(fields[2])
|
refFullName := string(fields[2])
|
||||||
total++
|
total++
|
||||||
lastline++
|
lastline++
|
||||||
|
|
||||||
// If the ref is a branch or tag, check if it's protected
|
// If the ref is a branch or tag, check if it's protected
|
||||||
// if supportProcReceive all ref should be checked because
|
// if supportProcReceive all ref should be checked because
|
||||||
// permission check was delayed
|
// permission check was delayed
|
||||||
if supportProcReceive || refFullName.IsBranch() || refFullName.IsTag() {
|
if supportProcReceive || strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) {
|
||||||
oldCommitIDs[count] = oldCommitID
|
oldCommitIDs[count] = oldCommitID
|
||||||
newCommitIDs[count] = newCommitID
|
newCommitIDs[count] = newCommitID
|
||||||
refFullNames[count] = refFullName
|
refFullNames[count] = refFullName
|
||||||
@@ -258,9 +257,14 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
hookOptions.OldCommitIDs = oldCommitIDs
|
hookOptions.OldCommitIDs = oldCommitIDs
|
||||||
hookOptions.NewCommitIDs = newCommitIDs
|
hookOptions.NewCommitIDs = newCommitIDs
|
||||||
hookOptions.RefFullNames = refFullNames
|
hookOptions.RefFullNames = refFullNames
|
||||||
extra := private.HookPreReceive(ctx, username, reponame, hookOptions)
|
statusCode, msg := private.HookPreReceive(ctx, username, reponame, hookOptions)
|
||||||
if extra.HasError() {
|
switch statusCode {
|
||||||
return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error)
|
case http.StatusOK:
|
||||||
|
// no-op
|
||||||
|
case http.StatusInternalServerError:
|
||||||
|
return fail("Internal Server Error", msg)
|
||||||
|
default:
|
||||||
|
return fail(msg, "")
|
||||||
}
|
}
|
||||||
count = 0
|
count = 0
|
||||||
lastline = 0
|
lastline = 0
|
||||||
@@ -281,9 +285,12 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
|
|
||||||
fmt.Fprintf(out, " Checking %d references\n", count)
|
fmt.Fprintf(out, " Checking %d references\n", count)
|
||||||
|
|
||||||
extra := private.HookPreReceive(ctx, username, reponame, hookOptions)
|
statusCode, msg := private.HookPreReceive(ctx, username, reponame, hookOptions)
|
||||||
if extra.HasError() {
|
switch statusCode {
|
||||||
return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error)
|
case http.StatusInternalServerError:
|
||||||
|
return fail("Internal Server Error", msg)
|
||||||
|
case http.StatusForbidden:
|
||||||
|
return fail(msg, "")
|
||||||
}
|
}
|
||||||
} else if lastline > 0 {
|
} else if lastline > 0 {
|
||||||
fmt.Fprintf(out, "\n")
|
fmt.Fprintf(out, "\n")
|
||||||
@@ -302,7 +309,7 @@ func runHookPostReceive(c *cli.Context) error {
|
|||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("hooks/post-receive.log", c.Bool("debug"))
|
||||||
|
|
||||||
// First of all run update-server-info no matter what
|
// First of all run update-server-info no matter what
|
||||||
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
|
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
|
||||||
@@ -316,7 +323,7 @@ func runHookPostReceive(c *cli.Context) error {
|
|||||||
|
|
||||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||||
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
||||||
return fail(ctx, `Rejecting changes as Gitea environment not set.
|
return fail(`Rejecting changes as Gitea environment not set.
|
||||||
If you are pushing over SSH you must push with a key managed by
|
If you are pushing over SSH you must push with a key managed by
|
||||||
Gitea or set your environment appropriately.`, "")
|
Gitea or set your environment appropriately.`, "")
|
||||||
}
|
}
|
||||||
@@ -353,7 +360,7 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
}
|
}
|
||||||
oldCommitIDs := make([]string, hookBatchSize)
|
oldCommitIDs := make([]string, hookBatchSize)
|
||||||
newCommitIDs := make([]string, hookBatchSize)
|
newCommitIDs := make([]string, hookBatchSize)
|
||||||
refFullNames := make([]git.RefName, hookBatchSize)
|
refFullNames := make([]string, hookBatchSize)
|
||||||
count := 0
|
count := 0
|
||||||
total := 0
|
total := 0
|
||||||
wasEmpty := false
|
wasEmpty := false
|
||||||
@@ -375,7 +382,7 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
fmt.Fprintf(out, ".")
|
fmt.Fprintf(out, ".")
|
||||||
oldCommitIDs[count] = string(fields[0])
|
oldCommitIDs[count] = string(fields[0])
|
||||||
newCommitIDs[count] = string(fields[1])
|
newCommitIDs[count] = string(fields[1])
|
||||||
refFullNames[count] = git.RefName(fields[2])
|
refFullNames[count] = string(fields[2])
|
||||||
if refFullNames[count] == git.BranchPrefix+"master" && newCommitIDs[count] != git.EmptySHA && count == total {
|
if refFullNames[count] == git.BranchPrefix+"master" && newCommitIDs[count] != git.EmptySHA && count == total {
|
||||||
masterPushed = true
|
masterPushed = true
|
||||||
}
|
}
|
||||||
@@ -387,11 +394,11 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
hookOptions.OldCommitIDs = oldCommitIDs
|
hookOptions.OldCommitIDs = oldCommitIDs
|
||||||
hookOptions.NewCommitIDs = newCommitIDs
|
hookOptions.NewCommitIDs = newCommitIDs
|
||||||
hookOptions.RefFullNames = refFullNames
|
hookOptions.RefFullNames = refFullNames
|
||||||
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
resp, err := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
||||||
if extra.HasError() {
|
if resp == nil {
|
||||||
_ = dWriter.Close()
|
_ = dWriter.Close()
|
||||||
hookPrintResults(results)
|
hookPrintResults(results)
|
||||||
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
|
return fail("Internal Server Error", err)
|
||||||
}
|
}
|
||||||
wasEmpty = wasEmpty || resp.RepoWasEmpty
|
wasEmpty = wasEmpty || resp.RepoWasEmpty
|
||||||
results = append(results, resp.Results...)
|
results = append(results, resp.Results...)
|
||||||
@@ -402,9 +409,9 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
if count == 0 {
|
if count == 0 {
|
||||||
if wasEmpty && masterPushed {
|
if wasEmpty && masterPushed {
|
||||||
// We need to tell the repo to reset the default branch to master
|
// We need to tell the repo to reset the default branch to master
|
||||||
extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
|
err := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
|
||||||
if extra.HasError() {
|
if err != nil {
|
||||||
return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
|
return fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintf(out, "Processed %d references in total\n", total)
|
fmt.Fprintf(out, "Processed %d references in total\n", total)
|
||||||
@@ -420,11 +427,11 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
|
|
||||||
fmt.Fprintf(out, " Processing %d references\n", count)
|
fmt.Fprintf(out, " Processing %d references\n", count)
|
||||||
|
|
||||||
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
resp, err := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
||||||
if resp == nil {
|
if resp == nil {
|
||||||
_ = dWriter.Close()
|
_ = dWriter.Close()
|
||||||
hookPrintResults(results)
|
hookPrintResults(results)
|
||||||
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
|
return fail("Internal Server Error", err)
|
||||||
}
|
}
|
||||||
wasEmpty = wasEmpty || resp.RepoWasEmpty
|
wasEmpty = wasEmpty || resp.RepoWasEmpty
|
||||||
results = append(results, resp.Results...)
|
results = append(results, resp.Results...)
|
||||||
@@ -433,9 +440,9 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
|
|
||||||
if wasEmpty && masterPushed {
|
if wasEmpty && masterPushed {
|
||||||
// We need to tell the repo to reset the default branch to master
|
// We need to tell the repo to reset the default branch to master
|
||||||
extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
|
err := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
|
||||||
if extra.HasError() {
|
if err != nil {
|
||||||
return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
|
return fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = dWriter.Close()
|
_ = dWriter.Close()
|
||||||
@@ -478,22 +485,22 @@ func pushOptions() map[string]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runHookProcReceive(c *cli.Context) error {
|
func runHookProcReceive(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals()
|
setup("hooks/proc-receive.log", c.Bool("debug"))
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
|
||||||
|
|
||||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||||
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
||||||
return fail(ctx, `Rejecting changes as Gitea environment not set.
|
return fail(`Rejecting changes as Gitea environment not set.
|
||||||
If you are pushing over SSH you must push with a key managed by
|
If you are pushing over SSH you must push with a key managed by
|
||||||
Gitea or set your environment appropriately.`, "")
|
Gitea or set your environment appropriately.`, "")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if git.CheckGitVersionAtLeast("2.29") != nil {
|
if git.CheckGitVersionAtLeast("2.29") != nil {
|
||||||
return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.")
|
return fail("Internal Server Error", "git not support proc-receive.")
|
||||||
}
|
}
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
@@ -508,7 +515,7 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
// H: PKT-LINE(version=1\0push-options...)
|
// H: PKT-LINE(version=1\0push-options...)
|
||||||
// H: flush-pkt
|
// H: flush-pkt
|
||||||
|
|
||||||
rs, err := readPktLine(ctx, reader, pktLineTypeData)
|
rs, err := readPktLine(reader, pktLineTypeData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -523,19 +530,19 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
|
|
||||||
index := bytes.IndexByte(rs.Data, byte(0))
|
index := bytes.IndexByte(rs.Data, byte(0))
|
||||||
if index >= len(rs.Data) {
|
if index >= len(rs.Data) {
|
||||||
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
|
return fail("Internal Server Error", "pkt-line: format error "+fmt.Sprint(rs.Data))
|
||||||
}
|
}
|
||||||
|
|
||||||
if index < 0 {
|
if index < 0 {
|
||||||
if len(rs.Data) == 10 && rs.Data[9] == '\n' {
|
if len(rs.Data) == 10 && rs.Data[9] == '\n' {
|
||||||
index = 9
|
index = 9
|
||||||
} else {
|
} else {
|
||||||
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
|
return fail("Internal Server Error", "pkt-line: format error "+fmt.Sprint(rs.Data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if string(rs.Data[0:index]) != VersionHead {
|
if string(rs.Data[0:index]) != VersionHead {
|
||||||
return fail(ctx, "Protocol: version error", "Received unsupported version: %s", string(rs.Data[0:index]))
|
return fail("Internal Server Error", "Received unsupported version: %s", string(rs.Data[0:index]))
|
||||||
}
|
}
|
||||||
requestOptions = strings.Split(string(rs.Data[index+1:]), " ")
|
requestOptions = strings.Split(string(rs.Data[index+1:]), " ")
|
||||||
|
|
||||||
@@ -548,17 +555,17 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
}
|
}
|
||||||
response = append(response, '\n')
|
response = append(response, '\n')
|
||||||
|
|
||||||
_, err = readPktLine(ctx, reader, pktLineTypeFlush)
|
_, err = readPktLine(reader, pktLineTypeFlush)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeDataPktLine(ctx, os.Stdout, response)
|
err = writeDataPktLine(os.Stdout, response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeFlushPktLine(ctx, os.Stdout)
|
err = writeFlushPktLine(os.Stdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -577,11 +584,11 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
}
|
}
|
||||||
hookOptions.OldCommitIDs = make([]string, 0, hookBatchSize)
|
hookOptions.OldCommitIDs = make([]string, 0, hookBatchSize)
|
||||||
hookOptions.NewCommitIDs = make([]string, 0, hookBatchSize)
|
hookOptions.NewCommitIDs = make([]string, 0, hookBatchSize)
|
||||||
hookOptions.RefFullNames = make([]git.RefName, 0, hookBatchSize)
|
hookOptions.RefFullNames = make([]string, 0, hookBatchSize)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed
|
// note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed
|
||||||
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
|
rs, err = readPktLine(reader, pktLineTypeUnknow)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -595,14 +602,14 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
}
|
}
|
||||||
hookOptions.OldCommitIDs = append(hookOptions.OldCommitIDs, t[0])
|
hookOptions.OldCommitIDs = append(hookOptions.OldCommitIDs, t[0])
|
||||||
hookOptions.NewCommitIDs = append(hookOptions.NewCommitIDs, t[1])
|
hookOptions.NewCommitIDs = append(hookOptions.NewCommitIDs, t[1])
|
||||||
hookOptions.RefFullNames = append(hookOptions.RefFullNames, git.RefName(t[2]))
|
hookOptions.RefFullNames = append(hookOptions.RefFullNames, t[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
hookOptions.GitPushOptions = make(map[string]string)
|
hookOptions.GitPushOptions = make(map[string]string)
|
||||||
|
|
||||||
if hasPushOptions {
|
if hasPushOptions {
|
||||||
for {
|
for {
|
||||||
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
|
rs, err = readPktLine(reader, pktLineTypeUnknow)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -619,9 +626,9 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. run hook
|
// 3. run hook
|
||||||
resp, extra := private.HookProcReceive(ctx, repoUser, repoName, hookOptions)
|
resp, err := private.HookProcReceive(ctx, repoUser, repoName, hookOptions)
|
||||||
if extra.HasError() {
|
if err != nil {
|
||||||
return fail(ctx, extra.UserMsg, "HookProcReceive failed: %v", extra.Error)
|
return fail("Internal Server Error", "run proc-receive hook failed :%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. response result to service
|
// 4. response result to service
|
||||||
@@ -642,7 +649,7 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
|
|
||||||
for _, rs := range resp.Results {
|
for _, rs := range resp.Results {
|
||||||
if len(rs.Err) > 0 {
|
if len(rs.Err) > 0 {
|
||||||
err = writeDataPktLine(ctx, os.Stdout, []byte("ng "+rs.OriginalRef.String()+" "+rs.Err))
|
err = writeDataPktLine(os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -650,43 +657,43 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
}
|
}
|
||||||
|
|
||||||
if rs.IsNotMatched {
|
if rs.IsNotMatched {
|
||||||
err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef.String()))
|
err = writeDataPktLine(os.Stdout, []byte("ok "+rs.OriginalRef))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option fall-through"))
|
err = writeDataPktLine(os.Stdout, []byte("option fall-through"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef))
|
err = writeDataPktLine(os.Stdout, []byte("ok "+rs.OriginalRef))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option refname "+rs.Ref))
|
err = writeDataPktLine(os.Stdout, []byte("option refname "+rs.Ref))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if rs.OldOID != git.EmptySHA {
|
if rs.OldOID != git.EmptySHA {
|
||||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID))
|
err = writeDataPktLine(os.Stdout, []byte("option old-oid "+rs.OldOID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option new-oid "+rs.NewOID))
|
err = writeDataPktLine(os.Stdout, []byte("option new-oid "+rs.NewOID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if rs.IsForcePush {
|
if rs.IsForcePush {
|
||||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option forced-update"))
|
err = writeDataPktLine(os.Stdout, []byte("option forced-update"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = writeFlushPktLine(ctx, os.Stdout)
|
err = writeFlushPktLine(os.Stdout)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -711,7 +718,7 @@ type gitPktLine struct {
|
|||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
|
func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
r *gitPktLine
|
r *gitPktLine
|
||||||
@@ -722,33 +729,33 @@ func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType)
|
|||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
lengthBytes[i], err = in.ReadByte()
|
lengthBytes[i], err = in.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err)
|
return nil, fail("Internal Server Error", "Pkt-Line: read stdin failed : %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = new(gitPktLine)
|
r = new(gitPktLine)
|
||||||
r.Length, err = strconv.ParseUint(string(lengthBytes), 16, 32)
|
r.Length, err = strconv.ParseUint(string(lengthBytes), 16, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fail(ctx, "Protocol: format parse error", "Pkt-Line format is wrong :%v", err)
|
return nil, fail("Internal Server Error", "Pkt-Line format is wrong :%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Length == 0 {
|
if r.Length == 0 {
|
||||||
if requestType == pktLineTypeData {
|
if requestType == pktLineTypeData {
|
||||||
return nil, fail(ctx, "Protocol: format data error", "Pkt-Line format is wrong")
|
return nil, fail("Internal Server Error", "Pkt-Line format is wrong")
|
||||||
}
|
}
|
||||||
r.Type = pktLineTypeFlush
|
r.Type = pktLineTypeFlush
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Length <= 4 || r.Length > 65520 || requestType == pktLineTypeFlush {
|
if r.Length <= 4 || r.Length > 65520 || requestType == pktLineTypeFlush {
|
||||||
return nil, fail(ctx, "Protocol: format length error", "Pkt-Line format is wrong")
|
return nil, fail("Internal Server Error", "Pkt-Line format is wrong")
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Data = make([]byte, r.Length-4)
|
r.Data = make([]byte, r.Length-4)
|
||||||
for i := range r.Data {
|
for i := range r.Data {
|
||||||
r.Data[i], err = in.ReadByte()
|
r.Data[i], err = in.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fail(ctx, "Protocol: data error", "Pkt-Line: read stdin failed : %v", err)
|
return nil, fail("Internal Server Error", "Pkt-Line: read stdin failed : %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -757,15 +764,19 @@ func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType)
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeFlushPktLine(ctx context.Context, out io.Writer) error {
|
func writeFlushPktLine(out io.Writer) error {
|
||||||
l, err := out.Write([]byte("0000"))
|
l, err := out.Write([]byte("0000"))
|
||||||
if err != nil || l != 4 {
|
if err != nil {
|
||||||
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
|
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
|
||||||
}
|
}
|
||||||
|
if l != 4 {
|
||||||
|
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeDataPktLine(ctx context.Context, out io.Writer, data []byte) error {
|
func writeDataPktLine(out io.Writer, data []byte) error {
|
||||||
hexchar := []byte("0123456789abcdef")
|
hexchar := []byte("0123456789abcdef")
|
||||||
hex := func(n uint64) byte {
|
hex := func(n uint64) byte {
|
||||||
return hexchar[(n)&15]
|
return hexchar[(n)&15]
|
||||||
@@ -779,13 +790,19 @@ func writeDataPktLine(ctx context.Context, out io.Writer, data []byte) error {
|
|||||||
tmp[3] = hex(length)
|
tmp[3] = hex(length)
|
||||||
|
|
||||||
lr, err := out.Write(tmp)
|
lr, err := out.Write(tmp)
|
||||||
if err != nil || lr != 4 {
|
if err != nil {
|
||||||
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
|
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
|
||||||
|
}
|
||||||
|
if lr != 4 {
|
||||||
|
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lr, err = out.Write(data)
|
lr, err = out.Write(data)
|
||||||
if err != nil || int(length-4) != lr {
|
if err != nil {
|
||||||
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
|
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
|
||||||
|
}
|
||||||
|
if int(length-4) != lr {
|
||||||
|
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -15,28 +14,27 @@ import (
|
|||||||
|
|
||||||
func TestPktLine(t *testing.T) {
|
func TestPktLine(t *testing.T) {
|
||||||
// test read
|
// test read
|
||||||
ctx := context.Background()
|
|
||||||
s := strings.NewReader("0000")
|
s := strings.NewReader("0000")
|
||||||
r := bufio.NewReader(s)
|
r := bufio.NewReader(s)
|
||||||
result, err := readPktLine(ctx, r, pktLineTypeFlush)
|
result, err := readPktLine(r, pktLineTypeFlush)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, pktLineTypeFlush, result.Type)
|
assert.Equal(t, pktLineTypeFlush, result.Type)
|
||||||
|
|
||||||
s = strings.NewReader("0006a\n")
|
s = strings.NewReader("0006a\n")
|
||||||
r = bufio.NewReader(s)
|
r = bufio.NewReader(s)
|
||||||
result, err = readPktLine(ctx, r, pktLineTypeData)
|
result, err = readPktLine(r, pktLineTypeData)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, pktLineTypeData, result.Type)
|
assert.Equal(t, pktLineTypeData, result.Type)
|
||||||
assert.Equal(t, []byte("a\n"), result.Data)
|
assert.Equal(t, []byte("a\n"), result.Data)
|
||||||
|
|
||||||
// test write
|
// test write
|
||||||
w := bytes.NewBuffer([]byte{})
|
w := bytes.NewBuffer([]byte{})
|
||||||
err = writeFlushPktLine(ctx, w)
|
err = writeFlushPktLine(w)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []byte("0000"), w.Bytes())
|
assert.Equal(t, []byte("0000"), w.Bytes())
|
||||||
|
|
||||||
w.Reset()
|
w.Reset()
|
||||||
err = writeDataPktLine(ctx, w, []byte("a\nb"))
|
err = writeDataPktLine(w, []byte("a\nb"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []byte("0007a\nb"), w.Bytes())
|
assert.Equal(t, []byte("0007a\nb"), w.Bytes())
|
||||||
}
|
}
|
||||||
|
|||||||
11
cmd/keys.go
11
cmd/keys.go
@@ -8,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
@@ -18,7 +17,6 @@ import (
|
|||||||
var CmdKeys = cli.Command{
|
var CmdKeys = cli.Command{
|
||||||
Name: "keys",
|
Name: "keys",
|
||||||
Usage: "This command queries the Gitea database to get the authorized command for a given ssh key fingerprint",
|
Usage: "This command queries the Gitea database to get the authorized command for a given ssh key fingerprint",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
|
||||||
Action: runKeys,
|
Action: runKeys,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
@@ -66,12 +64,11 @@ func runKeys(c *cli.Context) error {
|
|||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, false)
|
setup("keys.log", false)
|
||||||
|
|
||||||
authorizedString, extra := private.AuthorizedPublicKeyByContent(ctx, content)
|
authorizedString, err := private.AuthorizedPublicKeyByContent(ctx, content)
|
||||||
// do not use handleCliResponseExtra or cli.NewExitError, if it exists immediately, it breaks some tests like Test_CmdKeys
|
if err != nil {
|
||||||
if extra.Error != nil {
|
return err
|
||||||
return extra.Error
|
|
||||||
}
|
}
|
||||||
fmt.Println(strings.TrimSpace(authorizedString))
|
fmt.Println(strings.TrimSpace(authorizedString))
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@@ -16,7 +17,8 @@ func runSendMail(c *cli.Context) error {
|
|||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.InitProviderFromExistingFile()
|
||||||
|
setting.LoadCommonSettings()
|
||||||
|
|
||||||
if err := argsSet(c, "title"); err != nil {
|
if err := argsSet(c, "title"); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -41,10 +43,13 @@ func runSendMail(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
respText, extra := private.SendEmail(ctx, subject, body, nil)
|
status, message := private.SendEmail(ctx, subject, body, nil)
|
||||||
if extra.HasError() {
|
if status != http.StatusOK {
|
||||||
return handleCliResponseExtra(extra)
|
fmt.Printf("error: %s\n", message)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
_, _ = fmt.Printf("Sent %s email(s) to all users\n", respText)
|
|
||||||
|
fmt.Printf("Success: %s\n", message)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
26
cmd/main.go
26
cmd/main.go
@@ -1,26 +0,0 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RunMainApp(app *cli.App, args ...string) error {
|
|
||||||
err := app.Run(args)
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(err.Error(), "flag provided but not defined:") {
|
|
||||||
// the cli package should already have output the error message, so just exit
|
|
||||||
cli.OsExiter(1)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err)
|
|
||||||
cli.OsExiter(1)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
@@ -4,81 +4,19 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/test"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
setting.SetCustomPathAndConf("", "", "")
|
||||||
|
setting.InitProviderAndLoadCommonSettingsForTest()
|
||||||
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
unittest.MainTest(m, &unittest.TestOptions{
|
unittest.MainTest(m, &unittest.TestOptions{
|
||||||
GiteaRootPath: "..",
|
GiteaRootPath: "..",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestApp(testCmdAction func(ctx *cli.Context) error) *cli.App {
|
|
||||||
app := cli.NewApp()
|
|
||||||
app.HelpName = "gitea"
|
|
||||||
testCmd := cli.Command{Name: "test-cmd", Action: testCmdAction}
|
|
||||||
app.Commands = append(app.Commands, testCmd)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
type runResult struct {
|
|
||||||
Stdout string
|
|
||||||
Stderr string
|
|
||||||
ExitCode int
|
|
||||||
}
|
|
||||||
|
|
||||||
func runTestApp(app *cli.App, args ...string) (runResult, error) {
|
|
||||||
outBuf := new(strings.Builder)
|
|
||||||
errBuf := new(strings.Builder)
|
|
||||||
app.Writer = outBuf
|
|
||||||
app.ErrWriter = errBuf
|
|
||||||
exitCode := -1
|
|
||||||
defer test.MockVariableValue(&cli.ErrWriter, app.ErrWriter)()
|
|
||||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {
|
|
||||||
if exitCode == -1 {
|
|
||||||
exitCode = code // save the exit code once and then reset the writer (to simulate the exit)
|
|
||||||
app.Writer, app.ErrWriter, cli.ErrWriter = io.Discard, io.Discard, io.Discard
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
err := RunMainApp(app, args...)
|
|
||||||
return runResult{outBuf.String(), errBuf.String(), exitCode}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCliCmdError(t *testing.T) {
|
|
||||||
app := newTestApp(func(ctx *cli.Context) error { return fmt.Errorf("normal error") })
|
|
||||||
r, err := runTestApp(app, "./gitea", "test-cmd")
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
|
||||||
assert.Equal(t, "", r.Stdout)
|
|
||||||
assert.Equal(t, "Command error: normal error\n", r.Stderr)
|
|
||||||
|
|
||||||
app = newTestApp(func(ctx *cli.Context) error { return cli.NewExitError("exit error", 2) })
|
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd")
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Equal(t, 2, r.ExitCode)
|
|
||||||
assert.Equal(t, "", r.Stdout)
|
|
||||||
assert.Equal(t, "exit error\n", r.Stderr)
|
|
||||||
|
|
||||||
app = newTestApp(func(ctx *cli.Context) error { return nil })
|
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
|
||||||
assert.EqualValues(t, "Incorrect Usage: flag provided but not defined: -no-such\n\nNAME:\n gitea test-cmd - \n\nUSAGE:\n gitea test-cmd [arguments...]\n", r.Stdout)
|
|
||||||
assert.Equal(t, "", r.Stderr) // the cli package's strange behavior, the error message is not in stderr ....
|
|
||||||
|
|
||||||
app = newTestApp(func(ctx *cli.Context) error { return nil })
|
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
|
|
||||||
assert.Equal(t, "", r.Stdout)
|
|
||||||
assert.Equal(t, "", r.Stderr)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -21,7 +23,6 @@ var (
|
|||||||
Subcommands: []cli.Command{
|
Subcommands: []cli.Command{
|
||||||
subcmdShutdown,
|
subcmdShutdown,
|
||||||
subcmdRestart,
|
subcmdRestart,
|
||||||
subcmdReloadTemplates,
|
|
||||||
subcmdFlushQueues,
|
subcmdFlushQueues,
|
||||||
subcmdLogging,
|
subcmdLogging,
|
||||||
subCmdProcesses,
|
subCmdProcesses,
|
||||||
@@ -47,16 +48,6 @@ var (
|
|||||||
},
|
},
|
||||||
Action: runRestart,
|
Action: runRestart,
|
||||||
}
|
}
|
||||||
subcmdReloadTemplates = cli.Command{
|
|
||||||
Name: "reload-templates",
|
|
||||||
Usage: "Reload template files in the running process",
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
cli.BoolFlag{
|
|
||||||
Name: "debug",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: runReloadTemplates,
|
|
||||||
}
|
|
||||||
subcmdFlushQueues = cli.Command{
|
subcmdFlushQueues = cli.Command{
|
||||||
Name: "flush-queues",
|
Name: "flush-queues",
|
||||||
Usage: "Flush queues in the running process",
|
Usage: "Flush queues in the running process",
|
||||||
@@ -112,43 +103,57 @@ func runShutdown(c *cli.Context) error {
|
|||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("manager", c.Bool("debug"))
|
||||||
extra := private.Shutdown(ctx)
|
statusCode, msg := private.Shutdown(ctx)
|
||||||
return handleCliResponseExtra(extra)
|
switch statusCode {
|
||||||
|
case http.StatusInternalServerError:
|
||||||
|
return fail("InternalServerError", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stdout, msg)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRestart(c *cli.Context) error {
|
func runRestart(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("manager", c.Bool("debug"))
|
||||||
extra := private.Restart(ctx)
|
statusCode, msg := private.Restart(ctx)
|
||||||
return handleCliResponseExtra(extra)
|
switch statusCode {
|
||||||
}
|
case http.StatusInternalServerError:
|
||||||
|
return fail("InternalServerError", msg)
|
||||||
|
}
|
||||||
|
|
||||||
func runReloadTemplates(c *cli.Context) error {
|
fmt.Fprintln(os.Stdout, msg)
|
||||||
ctx, cancel := installSignals()
|
return nil
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
|
||||||
extra := private.ReloadTemplates(ctx)
|
|
||||||
return handleCliResponseExtra(extra)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFlushQueues(c *cli.Context) error {
|
func runFlushQueues(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("manager", c.Bool("debug"))
|
||||||
extra := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
|
statusCode, msg := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
|
||||||
return handleCliResponseExtra(extra)
|
switch statusCode {
|
||||||
|
case http.StatusInternalServerError:
|
||||||
|
return fail("InternalServerError", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stdout, msg)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runProcesses(c *cli.Context) error {
|
func runProcesses(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("manager", c.Bool("debug"))
|
||||||
extra := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
|
statusCode, msg := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
|
||||||
return handleCliResponseExtra(extra)
|
switch statusCode {
|
||||||
|
case http.StatusInternalServerError:
|
||||||
|
return fail("InternalServerError", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
@@ -16,13 +17,13 @@ import (
|
|||||||
var (
|
var (
|
||||||
defaultLoggingFlags = []cli.Flag{
|
defaultLoggingFlags = []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "logger",
|
Name: "group, g",
|
||||||
Usage: `Logger name - will default to "default"`,
|
Usage: "Group to add logger to - will default to \"default\"",
|
||||||
}, cli.StringFlag{
|
}, cli.StringFlag{
|
||||||
Name: "writer",
|
Name: "name, n",
|
||||||
Usage: "Name of the log writer - will default to mode",
|
Usage: "Name of the new logger - will default to mode",
|
||||||
}, cli.StringFlag{
|
}, cli.StringFlag{
|
||||||
Name: "level",
|
Name: "level, l",
|
||||||
Usage: "Logging level for the new logger",
|
Usage: "Logging level for the new logger",
|
||||||
}, cli.StringFlag{
|
}, cli.StringFlag{
|
||||||
Name: "stacktrace-level, L",
|
Name: "stacktrace-level, L",
|
||||||
@@ -83,8 +84,8 @@ var (
|
|||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "debug",
|
Name: "debug",
|
||||||
}, cli.StringFlag{
|
}, cli.StringFlag{
|
||||||
Name: "logger",
|
Name: "group, g",
|
||||||
Usage: `Logger name - will default to "default"`,
|
Usage: "Group to add logger to - will default to \"default\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: runRemoveLogger,
|
Action: runRemoveLogger,
|
||||||
@@ -93,6 +94,15 @@ var (
|
|||||||
Usage: "Add a logger",
|
Usage: "Add a logger",
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []cli.Command{
|
||||||
{
|
{
|
||||||
|
Name: "console",
|
||||||
|
Usage: "Add a console logger",
|
||||||
|
Flags: append(defaultLoggingFlags,
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "stderr",
|
||||||
|
Usage: "Output console logs to stderr - only relevant for console",
|
||||||
|
}),
|
||||||
|
Action: runAddConsoleLogger,
|
||||||
|
}, {
|
||||||
Name: "file",
|
Name: "file",
|
||||||
Usage: "Add a file logger",
|
Usage: "Add a file logger",
|
||||||
Flags: append(defaultLoggingFlags, []cli.Flag{
|
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||||
@@ -139,6 +149,28 @@ var (
|
|||||||
},
|
},
|
||||||
}...),
|
}...),
|
||||||
Action: runAddConnLogger,
|
Action: runAddConnLogger,
|
||||||
|
}, {
|
||||||
|
Name: "smtp",
|
||||||
|
Usage: "Add an SMTP logger",
|
||||||
|
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "username, u",
|
||||||
|
Usage: "Mail server username",
|
||||||
|
}, cli.StringFlag{
|
||||||
|
Name: "password, P",
|
||||||
|
Usage: "Mail server password",
|
||||||
|
}, cli.StringFlag{
|
||||||
|
Name: "host, H",
|
||||||
|
Usage: "Mail server host (defaults to: 127.0.0.1:25)",
|
||||||
|
}, cli.StringSliceFlag{
|
||||||
|
Name: "send-to, s",
|
||||||
|
Usage: "Email address(es) to send to",
|
||||||
|
}, cli.StringFlag{
|
||||||
|
Name: "subject, S",
|
||||||
|
Usage: "Subject header of sent emails",
|
||||||
|
},
|
||||||
|
}...),
|
||||||
|
Action: runAddSMTPLogger,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
@@ -159,26 +191,59 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func runRemoveLogger(c *cli.Context) error {
|
func runRemoveLogger(c *cli.Context) error {
|
||||||
|
setup("manager", c.Bool("debug"))
|
||||||
|
group := c.String("group")
|
||||||
|
if len(group) == 0 {
|
||||||
|
group = log.DEFAULT
|
||||||
|
}
|
||||||
|
name := c.Args().First()
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
statusCode, msg := private.RemoveLogger(ctx, group, name)
|
||||||
logger := c.String("logger")
|
switch statusCode {
|
||||||
if len(logger) == 0 {
|
case http.StatusInternalServerError:
|
||||||
logger = log.DEFAULT
|
return fail("InternalServerError", msg)
|
||||||
}
|
}
|
||||||
writer := c.Args().First()
|
|
||||||
|
|
||||||
extra := private.RemoveLogger(ctx, logger, writer)
|
fmt.Fprintln(os.Stdout, msg)
|
||||||
return handleCliResponseExtra(extra)
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runAddSMTPLogger(c *cli.Context) error {
|
||||||
|
setup("manager", c.Bool("debug"))
|
||||||
|
vals := map[string]interface{}{}
|
||||||
|
mode := "smtp"
|
||||||
|
if c.IsSet("host") {
|
||||||
|
vals["host"] = c.String("host")
|
||||||
|
} else {
|
||||||
|
vals["host"] = "127.0.0.1:25"
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.IsSet("username") {
|
||||||
|
vals["username"] = c.String("username")
|
||||||
|
}
|
||||||
|
if c.IsSet("password") {
|
||||||
|
vals["password"] = c.String("password")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.IsSet("send-to") {
|
||||||
|
return fmt.Errorf("Some recipients must be provided")
|
||||||
|
}
|
||||||
|
vals["sendTos"] = c.StringSlice("send-to")
|
||||||
|
|
||||||
|
if c.IsSet("subject") {
|
||||||
|
vals["subject"] = c.String("subject")
|
||||||
|
} else {
|
||||||
|
vals["subject"] = "Diagnostic message from Gitea"
|
||||||
|
}
|
||||||
|
|
||||||
|
return commonAddLogger(c, mode, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddConnLogger(c *cli.Context) error {
|
func runAddConnLogger(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals()
|
setup("manager", c.Bool("debug"))
|
||||||
defer cancel()
|
vals := map[string]interface{}{}
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
|
||||||
vals := map[string]any{}
|
|
||||||
mode := "conn"
|
mode := "conn"
|
||||||
vals["net"] = "tcp"
|
vals["net"] = "tcp"
|
||||||
if c.IsSet("protocol") {
|
if c.IsSet("protocol") {
|
||||||
@@ -204,11 +269,8 @@ func runAddConnLogger(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runAddFileLogger(c *cli.Context) error {
|
func runAddFileLogger(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals()
|
setup("manager", c.Bool("debug"))
|
||||||
defer cancel()
|
vals := map[string]interface{}{}
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
|
||||||
vals := map[string]any{}
|
|
||||||
mode := "file"
|
mode := "file"
|
||||||
if c.IsSet("filename") {
|
if c.IsSet("filename") {
|
||||||
vals["filename"] = c.String("filename")
|
vals["filename"] = c.String("filename")
|
||||||
@@ -236,12 +298,22 @@ func runAddFileLogger(c *cli.Context) error {
|
|||||||
return commonAddLogger(c, mode, vals)
|
return commonAddLogger(c, mode, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func commonAddLogger(c *cli.Context, mode string, vals map[string]any) error {
|
func runAddConsoleLogger(c *cli.Context) error {
|
||||||
|
setup("manager", c.Bool("debug"))
|
||||||
|
vals := map[string]interface{}{}
|
||||||
|
mode := "console"
|
||||||
|
if c.IsSet("stderr") && c.Bool("stderr") {
|
||||||
|
vals["stderr"] = c.Bool("stderr")
|
||||||
|
}
|
||||||
|
return commonAddLogger(c, mode, vals)
|
||||||
|
}
|
||||||
|
|
||||||
|
func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) error {
|
||||||
if len(c.String("level")) > 0 {
|
if len(c.String("level")) > 0 {
|
||||||
vals["level"] = log.LevelFromString(c.String("level")).String()
|
vals["level"] = log.FromString(c.String("level")).String()
|
||||||
}
|
}
|
||||||
if len(c.String("stacktrace-level")) > 0 {
|
if len(c.String("stacktrace-level")) > 0 {
|
||||||
vals["stacktraceLevel"] = log.LevelFromString(c.String("stacktrace-level")).String()
|
vals["stacktraceLevel"] = log.FromString(c.String("stacktrace-level")).String()
|
||||||
}
|
}
|
||||||
if len(c.String("expression")) > 0 {
|
if len(c.String("expression")) > 0 {
|
||||||
vals["expression"] = c.String("expression")
|
vals["expression"] = c.String("expression")
|
||||||
@@ -255,28 +327,39 @@ func commonAddLogger(c *cli.Context, mode string, vals map[string]any) error {
|
|||||||
if c.IsSet("color") {
|
if c.IsSet("color") {
|
||||||
vals["colorize"] = c.Bool("color")
|
vals["colorize"] = c.Bool("color")
|
||||||
}
|
}
|
||||||
logger := log.DEFAULT
|
group := "default"
|
||||||
if c.IsSet("logger") {
|
if c.IsSet("group") {
|
||||||
logger = c.String("logger")
|
group = c.String("group")
|
||||||
}
|
}
|
||||||
writer := mode
|
name := mode
|
||||||
if c.IsSet("writer") {
|
if c.IsSet("name") {
|
||||||
writer = c.String("writer")
|
name = c.String("name")
|
||||||
}
|
}
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
extra := private.AddLogger(ctx, logger, writer, mode, vals)
|
statusCode, msg := private.AddLogger(ctx, group, name, mode, vals)
|
||||||
return handleCliResponseExtra(extra)
|
switch statusCode {
|
||||||
|
case http.StatusInternalServerError:
|
||||||
|
return fail("InternalServerError", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stdout, msg)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runPauseLogging(c *cli.Context) error {
|
func runPauseLogging(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("manager", c.Bool("debug"))
|
||||||
userMsg := private.PauseLogging(ctx)
|
statusCode, msg := private.PauseLogging(ctx)
|
||||||
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
switch statusCode {
|
||||||
|
case http.StatusInternalServerError:
|
||||||
|
return fail("InternalServerError", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stdout, msg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,9 +367,14 @@ func runResumeLogging(c *cli.Context) error {
|
|||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("manager", c.Bool("debug"))
|
||||||
userMsg := private.ResumeLogging(ctx)
|
statusCode, msg := private.ResumeLogging(ctx)
|
||||||
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
switch statusCode {
|
||||||
|
case http.StatusInternalServerError:
|
||||||
|
return fail("InternalServerError", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stdout, msg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,17 +382,28 @@ func runReleaseReopenLogging(c *cli.Context) error {
|
|||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("manager", c.Bool("debug"))
|
||||||
userMsg := private.ReleaseReopenLogging(ctx)
|
statusCode, msg := private.ReleaseReopenLogging(ctx)
|
||||||
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
switch statusCode {
|
||||||
|
case http.StatusInternalServerError:
|
||||||
|
return fail("InternalServerError", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stdout, msg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSetLogSQL(c *cli.Context) error {
|
func runSetLogSQL(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("manager", c.Bool("debug"))
|
||||||
|
|
||||||
extra := private.SetLogSQL(ctx, !c.Bool("off"))
|
statusCode, msg := private.SetLogSQL(ctx, !c.Bool("off"))
|
||||||
return handleCliResponseExtra(extra)
|
switch statusCode {
|
||||||
|
case http.StatusInternalServerError:
|
||||||
|
return fail("InternalServerError", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stdout, msg)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
actions_model "code.gitea.io/gitea/models/actions"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
"code.gitea.io/gitea/models/migrations"
|
"code.gitea.io/gitea/models/migrations"
|
||||||
@@ -33,7 +32,7 @@ var CmdMigrateStorage = cli.Command{
|
|||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "type, t",
|
Name: "type, t",
|
||||||
Value: "",
|
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'",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "storage, s",
|
Name: "storage, s",
|
||||||
@@ -73,21 +72,12 @@ var CmdMigrateStorage = cli.Command{
|
|||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "minio-base-path",
|
Name: "minio-base-path",
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Minio storage base path on the bucket",
|
Usage: "Minio storage basepath on the bucket",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "minio-use-ssl",
|
Name: "minio-use-ssl",
|
||||||
Usage: "Enable SSL for minio",
|
Usage: "Enable SSL for minio",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
|
||||||
Name: "minio-insecure-skip-verify",
|
|
||||||
Usage: "Skip SSL verification",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "minio-checksum-algorithm",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio checksum algorithm (default/md5)",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,22 +125,6 @@ func migratePackages(ctx context.Context, dstStorage storage.ObjectStorage) erro
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func migrateActionsLog(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
|
||||||
return db.Iterate(ctx, nil, func(ctx context.Context, task *actions_model.ActionTask) error {
|
|
||||||
if task.LogExpired {
|
|
||||||
// the log has been cleared
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if !task.LogInStorage {
|
|
||||||
// running tasks store logs in DBFS
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
p := task.LogFilename
|
|
||||||
_, err := storage.Copy(dstStorage, p, storage.Actions, p)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func runMigrateStorage(ctx *cli.Context) error {
|
func runMigrateStorage(ctx *cli.Context) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -179,7 +153,7 @@ func runMigrateStorage(ctx *cli.Context) error {
|
|||||||
switch strings.ToLower(ctx.String("storage")) {
|
switch strings.ToLower(ctx.String("storage")) {
|
||||||
case "":
|
case "":
|
||||||
fallthrough
|
fallthrough
|
||||||
case string(setting.LocalStorageType):
|
case string(storage.LocalStorageType):
|
||||||
p := ctx.String("path")
|
p := ctx.String("path")
|
||||||
if p == "" {
|
if p == "" {
|
||||||
log.Fatal("Path must be given when storage is loal")
|
log.Fatal("Path must be given when storage is loal")
|
||||||
@@ -187,24 +161,20 @@ func runMigrateStorage(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
dstStorage, err = storage.NewLocalStorage(
|
dstStorage, err = storage.NewLocalStorage(
|
||||||
stdCtx,
|
stdCtx,
|
||||||
&setting.Storage{
|
storage.LocalStorageConfig{
|
||||||
Path: p,
|
Path: p,
|
||||||
})
|
})
|
||||||
case string(setting.MinioStorageType):
|
case string(storage.MinioStorageType):
|
||||||
dstStorage, err = storage.NewMinioStorage(
|
dstStorage, err = storage.NewMinioStorage(
|
||||||
stdCtx,
|
stdCtx,
|
||||||
&setting.Storage{
|
storage.MinioStorageConfig{
|
||||||
MinioConfig: setting.MinioStorageConfig{
|
Endpoint: ctx.String("minio-endpoint"),
|
||||||
Endpoint: ctx.String("minio-endpoint"),
|
AccessKeyID: ctx.String("minio-access-key-id"),
|
||||||
AccessKeyID: ctx.String("minio-access-key-id"),
|
SecretAccessKey: ctx.String("minio-secret-access-key"),
|
||||||
SecretAccessKey: ctx.String("minio-secret-access-key"),
|
Bucket: ctx.String("minio-bucket"),
|
||||||
Bucket: ctx.String("minio-bucket"),
|
Location: ctx.String("minio-location"),
|
||||||
Location: ctx.String("minio-location"),
|
BasePath: ctx.String("minio-base-path"),
|
||||||
BasePath: ctx.String("minio-base-path"),
|
UseSSL: ctx.Bool("minio-use-ssl"),
|
||||||
UseSSL: ctx.Bool("minio-use-ssl"),
|
|
||||||
InsecureSkipVerify: ctx.Bool("minio-insecure-skip-verify"),
|
|
||||||
ChecksumAlgorithm: ctx.String("minio-checksum-algorithm"),
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported storage type: %s", ctx.String("storage"))
|
return fmt.Errorf("unsupported storage type: %s", ctx.String("storage"))
|
||||||
@@ -220,7 +190,6 @@ func runMigrateStorage(ctx *cli.Context) error {
|
|||||||
"repo-avatars": migrateRepoAvatars,
|
"repo-avatars": migrateRepoAvatars,
|
||||||
"repo-archivers": migrateRepoArchivers,
|
"repo-archivers": migrateRepoArchivers,
|
||||||
"packages": migratePackages,
|
"packages": migratePackages,
|
||||||
"actions-log": migrateActionsLog,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tp := strings.ToLower(ctx.String("type"))
|
tp := strings.ToLower(ctx.String("type"))
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
|
|
||||||
@@ -26,7 +25,7 @@ func TestMigratePackages(t *testing.T) {
|
|||||||
creator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
creator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
|
|
||||||
content := "package main\n\nfunc main() {\nfmt.Println(\"hi\")\n}\n"
|
content := "package main\n\nfunc main() {\nfmt.Println(\"hi\")\n}\n"
|
||||||
buf, err := packages_module.CreateHashedBufferFromReaderWithSize(strings.NewReader(content), 1024)
|
buf, err := packages_module.CreateHashedBufferFromReader(strings.NewReader(content), 1024)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer buf.Close()
|
defer buf.Close()
|
||||||
|
|
||||||
@@ -58,7 +57,7 @@ func TestMigratePackages(t *testing.T) {
|
|||||||
|
|
||||||
dstStorage, err := storage.NewLocalStorage(
|
dstStorage, err := storage.NewLocalStorage(
|
||||||
ctx,
|
ctx,
|
||||||
&setting.Storage{
|
storage.LocalStorageConfig{
|
||||||
Path: p,
|
Path: p,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -68,7 +67,7 @@ func TestMigratePackages(t *testing.T) {
|
|||||||
|
|
||||||
entries, err := os.ReadDir(p)
|
entries, err := os.ReadDir(p)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, entries, 2)
|
assert.EqualValues(t, 2, len(entries))
|
||||||
assert.EqualValues(t, "01", entries[0].Name())
|
assert.EqualValues(t, "01", entries[0].Name())
|
||||||
assert.EqualValues(t, "tmp", entries[1].Name())
|
assert.EqualValues(t, "tmp", entries[1].Name())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,11 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
@@ -51,12 +54,13 @@ func runRestoreRepository(c *cli.Context) error {
|
|||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.InitProviderFromExistingFile()
|
||||||
|
setting.LoadCommonSettings()
|
||||||
var units []string
|
var units []string
|
||||||
if s := c.String("units"); s != "" {
|
if s := c.String("units"); s != "" {
|
||||||
units = strings.Split(s, ",")
|
units = strings.Split(s, ",")
|
||||||
}
|
}
|
||||||
extra := private.RestoreRepo(
|
statusCode, errStr := private.RestoreRepo(
|
||||||
ctx,
|
ctx,
|
||||||
c.String("repo_dir"),
|
c.String("repo_dir"),
|
||||||
c.String("owner_name"),
|
c.String("owner_name"),
|
||||||
@@ -64,5 +68,10 @@ func runRestoreRepository(c *cli.Context) error {
|
|||||||
units,
|
units,
|
||||||
c.Bool("validation"),
|
c.Bool("validation"),
|
||||||
)
|
)
|
||||||
return handleCliResponseExtra(extra)
|
if statusCode == http.StatusOK {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal("Failed to restore repository: %v", errStr)
|
||||||
|
return errors.New(errStr)
|
||||||
}
|
}
|
||||||
|
|||||||
108
cmd/serv.go
108
cmd/serv.go
@@ -7,6 +7,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -15,7 +16,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
|
||||||
|
|
||||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
@@ -44,7 +44,6 @@ var CmdServ = cli.Command{
|
|||||||
Name: "serv",
|
Name: "serv",
|
||||||
Usage: "This command should only be called by SSH shell",
|
Usage: "This command should only be called by SSH shell",
|
||||||
Description: "Serv provides access auth for repositories",
|
Description: "Serv provides access auth for repositories",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
|
||||||
Action: runServ,
|
Action: runServ,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
@@ -56,13 +55,15 @@ var CmdServ = cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup(ctx context.Context, debug bool) {
|
func setup(logPath string, debug bool) {
|
||||||
|
_ = log.DelLogger("console")
|
||||||
if debug {
|
if debug {
|
||||||
setupConsoleLogger(log.TRACE, false, os.Stderr)
|
_ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`)
|
||||||
} else {
|
} else {
|
||||||
setupConsoleLogger(log.FATAL, false, os.Stderr)
|
_ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`)
|
||||||
}
|
}
|
||||||
setting.MustInstalled()
|
setting.InitProviderFromExistingFile()
|
||||||
|
setting.LoadCommonSettings()
|
||||||
if debug {
|
if debug {
|
||||||
setting.RunMode = "dev"
|
setting.RunMode = "dev"
|
||||||
}
|
}
|
||||||
@@ -71,15 +72,15 @@ func setup(ctx context.Context, debug bool) {
|
|||||||
// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
|
// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
|
||||||
if _, err := os.Stat(setting.RepoRootPath); err != nil {
|
if _, err := os.Stat(setting.RepoRootPath); err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
_ = fail(ctx, "Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath)
|
_ = fail("Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath)
|
||||||
} else {
|
} else {
|
||||||
_ = fail(ctx, "Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err)
|
_ = fail("Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := git.InitSimple(context.Background()); err != nil {
|
if err := git.InitSimple(context.Background()); err != nil {
|
||||||
_ = fail(ctx, "Failed to init git", "Failed to init git, err: %v", err)
|
_ = fail("Failed to init git", "Failed to init git, err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,54 +94,32 @@ var (
|
|||||||
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
|
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// fail prints message to stdout, it's mainly used for git serv and git hook commands.
|
func fail(userMessage, logMessage string, args ...interface{}) error {
|
||||||
// The output will be passed to git client and shown to user.
|
|
||||||
func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error {
|
|
||||||
if userMessage == "" {
|
|
||||||
userMessage = "Internal Server Error (no specific error)"
|
|
||||||
}
|
|
||||||
|
|
||||||
// There appears to be a chance to cause a zombie process and failure to read the Exit status
|
// There appears to be a chance to cause a zombie process and failure to read the Exit status
|
||||||
// if nothing is outputted on stdout.
|
// if nothing is outputted on stdout.
|
||||||
_, _ = fmt.Fprintln(os.Stdout, "")
|
_, _ = fmt.Fprintln(os.Stdout, "")
|
||||||
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", userMessage)
|
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", userMessage)
|
||||||
|
|
||||||
if logMsgFmt != "" {
|
if len(logMessage) > 0 {
|
||||||
logMsg := fmt.Sprintf(logMsgFmt, args...)
|
|
||||||
if !setting.IsProd {
|
if !setting.IsProd {
|
||||||
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", logMsg)
|
_, _ = fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
|
||||||
}
|
}
|
||||||
if userMessage != "" {
|
}
|
||||||
if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
|
ctx, cancel := installSignals()
|
||||||
logMsg = userMessage + " " + logMsg
|
defer cancel()
|
||||||
} else {
|
|
||||||
logMsg = userMessage + ". " + logMsg
|
if len(logMessage) > 0 {
|
||||||
}
|
_ = private.SSHLog(ctx, true, fmt.Sprintf(logMessage+": ", args...))
|
||||||
}
|
|
||||||
_ = private.SSHLog(ctx, true, logMsg)
|
|
||||||
}
|
}
|
||||||
return cli.NewExitError("", 1)
|
return cli.NewExitError("", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleCliResponseExtra handles the extra response from the cli sub-commands
|
|
||||||
// If there is a user message it will be printed to stdout
|
|
||||||
// If the command failed it will return an error (the error will be printed by cli framework)
|
|
||||||
func handleCliResponseExtra(extra private.ResponseExtra) error {
|
|
||||||
if extra.UserMsg != "" {
|
|
||||||
_, _ = fmt.Fprintln(os.Stdout, extra.UserMsg)
|
|
||||||
}
|
|
||||||
if extra.HasError() {
|
|
||||||
return cli.NewExitError(extra.Error, 1)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func runServ(c *cli.Context) error {
|
func runServ(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// FIXME: This needs to internationalised
|
// FIXME: This needs to internationalised
|
||||||
setup(ctx, c.Bool("debug"))
|
setup("serv.log", c.Bool("debug"))
|
||||||
|
|
||||||
if setting.SSH.Disabled {
|
if setting.SSH.Disabled {
|
||||||
println("Gitea: SSH has been disabled")
|
println("Gitea: SSH has been disabled")
|
||||||
@@ -156,18 +135,18 @@ func runServ(c *cli.Context) error {
|
|||||||
|
|
||||||
keys := strings.Split(c.Args()[0], "-")
|
keys := strings.Split(c.Args()[0], "-")
|
||||||
if len(keys) != 2 || keys[0] != "key" {
|
if len(keys) != 2 || keys[0] != "key" {
|
||||||
return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args()[0])
|
return fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
|
||||||
}
|
}
|
||||||
keyID, err := strconv.ParseInt(keys[1], 10, 64)
|
keyID, err := strconv.ParseInt(keys[1], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fail(ctx, "Key ID parsing error", "Invalid key argument: %s", c.Args()[1])
|
return fail("Key ID format error", "Invalid key argument: %s", c.Args()[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
|
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
|
||||||
if len(cmd) == 0 {
|
if len(cmd) == 0 {
|
||||||
key, user, err := private.ServNoCommand(ctx, keyID)
|
key, user, err := private.ServNoCommand(ctx, keyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fail(ctx, "Key check failed", "Failed to check provided key: %v", err)
|
return fail("Internal error", "Failed to check provided key: %v", err)
|
||||||
}
|
}
|
||||||
switch key.Type {
|
switch key.Type {
|
||||||
case asymkey_model.KeyTypeDeploy:
|
case asymkey_model.KeyTypeDeploy:
|
||||||
@@ -185,7 +164,7 @@ func runServ(c *cli.Context) error {
|
|||||||
|
|
||||||
words, err := shellquote.Split(cmd)
|
words, err := shellquote.Split(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fail(ctx, "Error parsing arguments", "Failed to parse arguments: %v", err)
|
return fail("Error parsing arguments", "Failed to parse arguments: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(words) < 2 {
|
if len(words) < 2 {
|
||||||
@@ -196,7 +175,7 @@ func runServ(c *cli.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
|
return fail("Too few arguments", "Too few arguments in cmd: %s", cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
verb := words[0]
|
verb := words[0]
|
||||||
@@ -208,7 +187,7 @@ func runServ(c *cli.Context) error {
|
|||||||
var lfsVerb string
|
var lfsVerb string
|
||||||
if verb == lfsAuthenticateVerb {
|
if verb == lfsAuthenticateVerb {
|
||||||
if !setting.LFS.StartServer {
|
if !setting.LFS.StartServer {
|
||||||
return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
|
return fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(words) > 2 {
|
if len(words) > 2 {
|
||||||
@@ -221,37 +200,37 @@ func runServ(c *cli.Context) error {
|
|||||||
|
|
||||||
rr := strings.SplitN(repoPath, "/", 2)
|
rr := strings.SplitN(repoPath, "/", 2)
|
||||||
if len(rr) != 2 {
|
if len(rr) != 2 {
|
||||||
return fail(ctx, "Invalid repository path", "Invalid repository path: %v", repoPath)
|
return fail("Invalid repository path", "Invalid repository path: %v", repoPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
username := strings.ToLower(rr[0])
|
username := strings.ToLower(rr[0])
|
||||||
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
|
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
|
||||||
|
|
||||||
if alphaDashDotPattern.MatchString(reponame) {
|
if alphaDashDotPattern.MatchString(reponame) {
|
||||||
return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame)
|
return fail("Invalid repo name", "Invalid repo name: %s", reponame)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Bool("enable-pprof") {
|
if c.Bool("enable-pprof") {
|
||||||
if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
|
if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
|
||||||
return fail(ctx, "Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
|
return fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
|
stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fail(ctx, "Unable to start CPU profiler", "Unable to start CPU profile: %v", err)
|
return fail("Internal Server Error", "Unable to start CPU profile: %v", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
stopCPUProfiler()
|
stopCPUProfiler()
|
||||||
err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
|
err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = fail(ctx, "Unable to dump Mem profile", "Unable to dump Mem Profile: %v", err)
|
_ = fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
requestedMode, has := allowedCommands[verb]
|
requestedMode, has := allowedCommands[verb]
|
||||||
if !has {
|
if !has {
|
||||||
return fail(ctx, "Unknown git command", "Unknown git command %s", verb)
|
return fail("Unknown git command", "Unknown git command %s", verb)
|
||||||
}
|
}
|
||||||
|
|
||||||
if verb == lfsAuthenticateVerb {
|
if verb == lfsAuthenticateVerb {
|
||||||
@@ -260,13 +239,20 @@ func runServ(c *cli.Context) error {
|
|||||||
} else if lfsVerb == "download" {
|
} else if lfsVerb == "download" {
|
||||||
requestedMode = perm.AccessModeRead
|
requestedMode = perm.AccessModeRead
|
||||||
} else {
|
} else {
|
||||||
return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
|
return fail("Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
|
results, err := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
|
||||||
if extra.HasError() {
|
if err != nil {
|
||||||
return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error)
|
if private.IsErrServCommand(err) {
|
||||||
|
errServCommand := err.(private.ErrServCommand)
|
||||||
|
if errServCommand.StatusCode != http.StatusInternalServerError {
|
||||||
|
return fail("Unauthorized", "%s", errServCommand.Error())
|
||||||
|
}
|
||||||
|
return fail("Internal Server Error", "%s", errServCommand.Error())
|
||||||
|
}
|
||||||
|
return fail("Internal Server Error", "%s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// LFS token authentication
|
// LFS token authentication
|
||||||
@@ -288,7 +274,7 @@ func runServ(c *cli.Context) error {
|
|||||||
// Sign and get the complete encoded token as a string using the secret
|
// Sign and get the complete encoded token as a string using the secret
|
||||||
tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
|
tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
|
return fail("Internal error", "Failed to sign JWT token: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenAuthentication := &git_model.LFSTokenResponse{
|
tokenAuthentication := &git_model.LFSTokenResponse{
|
||||||
@@ -300,7 +286,7 @@ func runServ(c *cli.Context) error {
|
|||||||
enc := json.NewEncoder(os.Stdout)
|
enc := json.NewEncoder(os.Stdout)
|
||||||
err = enc.Encode(tokenAuthentication)
|
err = enc.Encode(tokenAuthentication)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fail(ctx, "Failed to encode LFS json response", "Failed to encode LFS json response: %v", err)
|
return fail("Internal error", "Failed to encode LFS json response: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -346,13 +332,13 @@ func runServ(c *cli.Context) error {
|
|||||||
gitcmd.Env = append(gitcmd.Env, git.CommonCmdServEnvs()...)
|
gitcmd.Env = append(gitcmd.Env, git.CommonCmdServEnvs()...)
|
||||||
|
|
||||||
if err = gitcmd.Run(); err != nil {
|
if err = gitcmd.Run(); err != nil {
|
||||||
return fail(ctx, "Failed to execute git command", "Failed to execute git command: %v", err)
|
return fail("Internal error", "Failed to execute git command: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update user key activity.
|
// Update user key activity.
|
||||||
if results.KeyID > 0 {
|
if results.KeyID > 0 {
|
||||||
if err = private.UpdatePublicKeyInRepo(ctx, results.KeyID, results.RepoID); err != nil {
|
if err = private.UpdatePublicKeyInRepo(ctx, results.KeyID, results.RepoID); err != nil {
|
||||||
return fail(ctx, "Failed to update public key", "UpdatePublicKeyInRepo: %v", err)
|
return fail("Internal error", "UpdatePublicKeyInRepo: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
219
cmd/web.go
219
cmd/web.go
@@ -9,8 +9,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
_ "net/http/pprof" // Used for debugging if enabled and a web server is running
|
_ "net/http/pprof" // Used for debugging if enabled and a web server is running
|
||||||
@@ -24,18 +22,15 @@ import (
|
|||||||
|
|
||||||
"github.com/felixge/fgprof"
|
"github.com/felixge/fgprof"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
ini "gopkg.in/ini.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PIDFile could be set from build tag
|
|
||||||
var PIDFile = "/run/gitea.pid"
|
|
||||||
|
|
||||||
// CmdWeb represents the available web sub-command.
|
// CmdWeb represents the available web sub-command.
|
||||||
var CmdWeb = cli.Command{
|
var CmdWeb = cli.Command{
|
||||||
Name: "web",
|
Name: "web",
|
||||||
Usage: "Start Gitea web server",
|
Usage: "Start Gitea web server",
|
||||||
Description: `Gitea web server is the only thing you need to run,
|
Description: `Gitea web server is the only thing you need to run,
|
||||||
and it takes care of all the other things for you`,
|
and it takes care of all the other things for you`,
|
||||||
Before: PrepareConsoleLoggerLevel(log.INFO),
|
|
||||||
Action: runWeb,
|
Action: runWeb,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
@@ -50,7 +45,7 @@ and it takes care of all the other things for you`,
|
|||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "pid, P",
|
Name: "pid, P",
|
||||||
Value: PIDFile,
|
Value: setting.PIDFile,
|
||||||
Usage: "Custom pid file path",
|
Usage: "Custom pid file path",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
@@ -86,127 +81,14 @@ func runHTTPRedirector() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPIDFile(pidPath string) {
|
|
||||||
currentPid := os.Getpid()
|
|
||||||
if err := os.MkdirAll(filepath.Dir(pidPath), os.ModePerm); err != nil {
|
|
||||||
log.Fatal("Failed to create PID folder: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Create(pidPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Failed to create PID file: %v", err)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
if _, err := file.WriteString(strconv.FormatInt(int64(currentPid), 10)); err != nil {
|
|
||||||
log.Fatal("Failed to write PID information: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveInstall(ctx *cli.Context) error {
|
|
||||||
log.Info("Gitea version: %s%s", setting.AppVer, setting.AppBuiltWith)
|
|
||||||
log.Info("App path: %s", setting.AppPath)
|
|
||||||
log.Info("Work path: %s", setting.AppWorkPath)
|
|
||||||
log.Info("Custom path: %s", setting.CustomPath)
|
|
||||||
log.Info("Config file: %s", setting.CustomConf)
|
|
||||||
log.Info("Prepare to run install page")
|
|
||||||
|
|
||||||
routers.InitWebInstallPage(graceful.GetManager().HammerContext())
|
|
||||||
|
|
||||||
// Flag for port number in case first time run conflict
|
|
||||||
if ctx.IsSet("port") {
|
|
||||||
if err := setPort(ctx.String("port")); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ctx.IsSet("install-port") {
|
|
||||||
if err := setPort(ctx.String("install-port")); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c := install.Routes()
|
|
||||||
err := listen(c, false)
|
|
||||||
if err != nil {
|
|
||||||
log.Critical("Unable to open listener for installer. Is Gitea already running?")
|
|
||||||
graceful.GetManager().DoGracefulShutdown()
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-graceful.GetManager().IsShutdown():
|
|
||||||
<-graceful.GetManager().Done()
|
|
||||||
log.Info("PID: %d Gitea Web Finished", os.Getpid())
|
|
||||||
log.GetManager().Close()
|
|
||||||
return err
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveInstalled(ctx *cli.Context) error {
|
|
||||||
setting.InitCfgProvider(setting.CustomConf)
|
|
||||||
setting.LoadCommonSettings()
|
|
||||||
setting.MustInstalled()
|
|
||||||
|
|
||||||
log.Info("Gitea version: %s%s", setting.AppVer, setting.AppBuiltWith)
|
|
||||||
log.Info("App path: %s", setting.AppPath)
|
|
||||||
log.Info("Work path: %s", setting.AppWorkPath)
|
|
||||||
log.Info("Custom path: %s", setting.CustomPath)
|
|
||||||
log.Info("Config file: %s", setting.CustomConf)
|
|
||||||
log.Info("Run mode: %s", setting.RunMode)
|
|
||||||
log.Info("Prepare to run web server")
|
|
||||||
|
|
||||||
if setting.AppWorkPathMismatch {
|
|
||||||
log.Error("WORK_PATH from config %q doesn't match other paths from environment variables or command arguments. "+
|
|
||||||
"Only WORK_PATH in config should be set and used. Please remove the other outdated work paths from environment variables and command arguments", setting.CustomConf)
|
|
||||||
}
|
|
||||||
|
|
||||||
rootCfg := setting.CfgProvider
|
|
||||||
if rootCfg.Section("").Key("WORK_PATH").String() == "" {
|
|
||||||
saveCfg, err := rootCfg.PrepareSaving()
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Unable to prepare saving WORK_PATH=%s to config %q: %v\nYou must set it manually, otherwise there might be bugs when accessing the git repositories.", setting.AppWorkPath, setting.CustomConf, err)
|
|
||||||
} else {
|
|
||||||
rootCfg.Section("").Key("WORK_PATH").SetValue(setting.AppWorkPath)
|
|
||||||
saveCfg.Section("").Key("WORK_PATH").SetValue(setting.AppWorkPath)
|
|
||||||
if err = saveCfg.Save(); err != nil {
|
|
||||||
log.Error("Unable to update WORK_PATH=%s to config %q: %v\nYou must set it manually, otherwise there might be bugs when accessing the git repositories.", setting.AppWorkPath, setting.CustomConf, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
routers.InitWebInstalled(graceful.GetManager().HammerContext())
|
|
||||||
|
|
||||||
// We check that AppDataPath exists here (it should have been created during installation)
|
|
||||||
// We can't check it in `InitWebInstalled`, because some integration tests
|
|
||||||
// use cmd -> InitWebInstalled, but the AppDataPath doesn't exist during those tests.
|
|
||||||
if _, err := os.Stat(setting.AppDataPath); err != nil {
|
|
||||||
log.Fatal("Can not find APP_DATA_PATH %q", setting.AppDataPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override the provided port number within the configuration
|
|
||||||
if ctx.IsSet("port") {
|
|
||||||
if err := setPort(ctx.String("port")); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up Chi routes
|
|
||||||
c := routers.NormalRoutes(graceful.GetManager().HammerContext())
|
|
||||||
err := listen(c, true)
|
|
||||||
<-graceful.GetManager().Done()
|
|
||||||
log.Info("PID: %d Gitea Web Finished", os.Getpid())
|
|
||||||
log.GetManager().Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func servePprof() {
|
|
||||||
http.DefaultServeMux.Handle("/debug/fgprof", fgprof.Handler())
|
|
||||||
_, _, finished := process.GetManager().AddTypedContext(context.Background(), "Web: PProf Server", process.SystemProcessType, true)
|
|
||||||
// The pprof server is for debug purpose only, it shouldn't be exposed on public network. At the moment it's not worth to introduce a configurable option for it.
|
|
||||||
log.Info("Starting pprof server on localhost:6060")
|
|
||||||
log.Info("Stopped pprof server: %v", http.ListenAndServe("localhost:6060", nil))
|
|
||||||
finished()
|
|
||||||
}
|
|
||||||
|
|
||||||
func runWeb(ctx *cli.Context) error {
|
func runWeb(ctx *cli.Context) error {
|
||||||
|
if ctx.Bool("verbose") {
|
||||||
|
_ = log.DelLogger("console")
|
||||||
|
log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "trace", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
|
||||||
|
} else if ctx.Bool("quiet") {
|
||||||
|
_ = log.DelLogger("console")
|
||||||
|
log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "fatal", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
|
||||||
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if panicked := recover(); panicked != nil {
|
if panicked := recover(); panicked != nil {
|
||||||
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
|
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
|
||||||
@@ -225,22 +107,82 @@ func runWeb(ctx *cli.Context) error {
|
|||||||
|
|
||||||
// Set pid file setting
|
// Set pid file setting
|
||||||
if ctx.IsSet("pid") {
|
if ctx.IsSet("pid") {
|
||||||
createPIDFile(ctx.String("pid"))
|
setting.PIDFile = ctx.String("pid")
|
||||||
|
setting.WritePIDFile = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !setting.InstallLock {
|
// Perform pre-initialization
|
||||||
if err := serveInstall(ctx); err != nil {
|
needsInstall := install.PreloadSettings(graceful.GetManager().HammerContext())
|
||||||
|
if needsInstall {
|
||||||
|
// Flag for port number in case first time run conflict
|
||||||
|
if ctx.IsSet("port") {
|
||||||
|
if err := setPort(ctx.String("port")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ctx.IsSet("install-port") {
|
||||||
|
if err := setPort(ctx.String("install-port")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
installCtx, cancel := context.WithCancel(graceful.GetManager().HammerContext())
|
||||||
|
c := install.Routes(installCtx)
|
||||||
|
err := listen(c, false)
|
||||||
|
cancel()
|
||||||
|
if err != nil {
|
||||||
|
log.Critical("Unable to open listener for installer. Is Gitea already running?")
|
||||||
|
graceful.GetManager().DoGracefulShutdown()
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-graceful.GetManager().IsShutdown():
|
||||||
|
<-graceful.GetManager().Done()
|
||||||
|
log.Info("PID: %d Gitea Web Finished", os.Getpid())
|
||||||
|
log.Close()
|
||||||
return err
|
return err
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NoInstallListener()
|
NoInstallListener()
|
||||||
}
|
}
|
||||||
|
|
||||||
if setting.EnablePprof {
|
if setting.EnablePprof {
|
||||||
go servePprof()
|
go func() {
|
||||||
|
http.DefaultServeMux.Handle("/debug/fgprof", fgprof.Handler())
|
||||||
|
_, _, finished := process.GetManager().AddTypedContext(context.Background(), "Web: PProf Server", process.SystemProcessType, true)
|
||||||
|
// The pprof server is for debug purpose only, it shouldn't be exposed on public network. At the moment it's not worth to introduce a configurable option for it.
|
||||||
|
log.Info("Starting pprof server on localhost:6060")
|
||||||
|
log.Info("Stopped pprof server: %v", http.ListenAndServe("localhost:6060", nil))
|
||||||
|
finished()
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
return serveInstalled(ctx)
|
log.Info("Global init")
|
||||||
|
// Perform global initialization
|
||||||
|
setting.InitProviderFromExistingFile()
|
||||||
|
setting.LoadCommonSettings()
|
||||||
|
routers.GlobalInitInstalled(graceful.GetManager().HammerContext())
|
||||||
|
|
||||||
|
// We check that AppDataPath exists here (it should have been created during installation)
|
||||||
|
// We can't check it in `GlobalInitInstalled`, because some integration tests
|
||||||
|
// use cmd -> GlobalInitInstalled, but the AppDataPath doesn't exist during those tests.
|
||||||
|
if _, err := os.Stat(setting.AppDataPath); err != nil {
|
||||||
|
log.Fatal("Can not find APP_DATA_PATH '%s'", setting.AppDataPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override the provided port number within the configuration
|
||||||
|
if ctx.IsSet("port") {
|
||||||
|
if err := setPort(ctx.String("port")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up Chi routes
|
||||||
|
c := routers.NormalRoutes(graceful.GetManager().HammerContext())
|
||||||
|
err := listen(c, true)
|
||||||
|
<-graceful.GetManager().Done()
|
||||||
|
log.Info("PID: %d Gitea Web Finished", os.Getpid())
|
||||||
|
log.Close()
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPort(port string) error {
|
func setPort(port string) error {
|
||||||
@@ -261,16 +203,9 @@ func setPort(port string) error {
|
|||||||
defaultLocalURL += ":" + setting.HTTPPort + "/"
|
defaultLocalURL += ":" + setting.HTTPPort + "/"
|
||||||
|
|
||||||
// Save LOCAL_ROOT_URL if port changed
|
// Save LOCAL_ROOT_URL if port changed
|
||||||
rootCfg := setting.CfgProvider
|
setting.CreateOrAppendToCustomConf("server.LOCAL_ROOT_URL", func(cfg *ini.File) {
|
||||||
saveCfg, err := rootCfg.PrepareSaving()
|
cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
|
||||||
if err != nil {
|
})
|
||||||
return fmt.Errorf("failed to save config file: %v", err)
|
|
||||||
}
|
|
||||||
rootCfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
|
|
||||||
saveCfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
|
|
||||||
if err = saveCfg.Save(); err != nil {
|
|
||||||
return fmt.Errorf("failed to save config file: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
2
contrib/autoboot.sh
Executable file
2
contrib/autoboot.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
su git -c "/home/git/gogs/scripts/gogs_supervisord.sh restart"
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
//nolint:forbidigo
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -17,7 +16,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/google/go-github/v52/github"
|
"github.com/google/go-github/v45/github"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,13 +5,21 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
ini "gopkg.in/ini.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EnvironmentPrefix environment variables prefixed with this represent ini values to write
|
||||||
|
const EnvironmentPrefix = "GITEA"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "environment-to-ini"
|
app.Name = "environment-to-ini"
|
||||||
@@ -24,10 +32,6 @@ func main() {
|
|||||||
will be mapped to the ini section "[section_name]" and the key
|
will be mapped to the ini section "[section_name]" and the key
|
||||||
"KEY_NAME" with the value as provided.
|
"KEY_NAME" with the value as provided.
|
||||||
|
|
||||||
Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME__FILE"
|
|
||||||
will be mapped to the ini section "[section_name]" and the key
|
|
||||||
"KEY_NAME" with the value loaded from the specified file.
|
|
||||||
|
|
||||||
Environment variables are usually restricted to a reduced character
|
Environment variables are usually restricted to a reduced character
|
||||||
set "0-9A-Z_" - in order to allow the setting of sections with
|
set "0-9A-Z_" - in order to allow the setting of sections with
|
||||||
characters outside of that set, they should be escaped as following:
|
characters outside of that set, they should be escaped as following:
|
||||||
@@ -66,8 +70,19 @@ func main() {
|
|||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Destination file to write to",
|
Usage: "Destination file to write to",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "clear",
|
||||||
|
Usage: "Clears the matched variables from the environment",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prefix, p",
|
||||||
|
Value: EnvironmentPrefix,
|
||||||
|
Usage: "Environment prefix to look for - will be suffixed by __ (2 underscores)",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
app.Action = runEnvironmentToIni
|
app.Action = runEnvironmentToIni
|
||||||
|
setting.SetCustomPathAndConf("", "", "")
|
||||||
|
|
||||||
err := app.Run(os.Args)
|
err := app.Run(os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to run app with %s: %v", os.Args, err)
|
log.Fatal("Failed to run app with %s: %v", os.Args, err)
|
||||||
@@ -75,22 +90,66 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runEnvironmentToIni(c *cli.Context) error {
|
func runEnvironmentToIni(c *cli.Context) error {
|
||||||
// the config system may change the environment variables, so get a copy first, to be used later
|
providedCustom := c.String("custom-path")
|
||||||
env := append([]string{}, os.Environ()...)
|
providedConf := c.String("config")
|
||||||
setting.InitWorkPathAndCfgProvider(os.Getenv, setting.ArgWorkPathAndCustomConf{
|
providedWorkPath := c.String("work-path")
|
||||||
WorkPath: c.String("work-path"),
|
setting.SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath)
|
||||||
CustomPath: c.String("custom-path"),
|
|
||||||
CustomConf: c.String("config"),
|
|
||||||
})
|
|
||||||
|
|
||||||
cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
|
cfg := ini.Empty()
|
||||||
|
isFile, err := util.IsFile(setting.CustomConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to load custom conf '%s': %v", setting.CustomConf, err)
|
log.Fatal("Unable to check if %s is a file. Error: %v", setting.CustomConf, err)
|
||||||
}
|
}
|
||||||
|
if isFile {
|
||||||
|
if err := cfg.Append(setting.CustomConf); err != nil {
|
||||||
|
log.Fatal("Failed to load custom conf '%s': %v", setting.CustomConf, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Warn("Custom config '%s' not found, ignore this if you're running first time", setting.CustomConf)
|
||||||
|
}
|
||||||
|
cfg.NameMapper = ini.SnackCase
|
||||||
|
|
||||||
changed := setting.EnvironmentToConfig(cfg, env)
|
changed := false
|
||||||
|
|
||||||
// try to save the config file
|
prefix := c.String("prefix") + "__"
|
||||||
|
|
||||||
|
for _, kv := range os.Environ() {
|
||||||
|
idx := strings.IndexByte(kv, '=')
|
||||||
|
if idx < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
eKey := kv[:idx]
|
||||||
|
value := kv[idx+1:]
|
||||||
|
if !strings.HasPrefix(eKey, prefix) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
eKey = eKey[len(prefix):]
|
||||||
|
sectionName, keyName := DecodeSectionKey(eKey)
|
||||||
|
if len(keyName) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
section, err := cfg.GetSection(sectionName)
|
||||||
|
if err != nil {
|
||||||
|
section, err = cfg.NewSection(sectionName)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error creating section: %s : %v", sectionName, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key := section.Key(keyName)
|
||||||
|
if key == nil {
|
||||||
|
key, err = section.NewKey(keyName, value)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error creating key: %s in section: %s with value: %s : %v", keyName, sectionName, value, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oldValue := key.Value()
|
||||||
|
if !changed && oldValue != value {
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
key.SetValue(value)
|
||||||
|
}
|
||||||
destination := c.String("out")
|
destination := c.String("out")
|
||||||
if len(destination) == 0 {
|
if len(destination) == 0 {
|
||||||
destination = setting.CustomConf
|
destination = setting.CustomConf
|
||||||
@@ -102,6 +161,76 @@ func runEnvironmentToIni(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if c.Bool("clear") {
|
||||||
|
for _, kv := range os.Environ() {
|
||||||
|
idx := strings.IndexByte(kv, '=')
|
||||||
|
if idx < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
eKey := kv[:idx]
|
||||||
|
if strings.HasPrefix(eKey, prefix) {
|
||||||
|
_ = os.Unsetenv(eKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const escapeRegexpString = "_0[xX](([0-9a-fA-F][0-9a-fA-F])+)_"
|
||||||
|
|
||||||
|
var escapeRegex = regexp.MustCompile(escapeRegexpString)
|
||||||
|
|
||||||
|
// DecodeSectionKey will decode a portable string encoded Section__Key pair
|
||||||
|
// Portable strings are considered to be of the form [A-Z0-9_]*
|
||||||
|
// We will encode a disallowed value as the UTF8 byte string preceded by _0X and
|
||||||
|
// followed by _. E.g. _0X2C_ for a '-' and _0X2E_ for '.'
|
||||||
|
// Section and Key are separated by a plain '__'.
|
||||||
|
// The entire section can be encoded as a UTF8 byte string
|
||||||
|
func DecodeSectionKey(encoded string) (string, string) {
|
||||||
|
section := ""
|
||||||
|
key := ""
|
||||||
|
|
||||||
|
inKey := false
|
||||||
|
last := 0
|
||||||
|
escapeStringIndices := escapeRegex.FindAllStringIndex(encoded, -1)
|
||||||
|
for _, unescapeIdx := range escapeStringIndices {
|
||||||
|
preceding := encoded[last:unescapeIdx[0]]
|
||||||
|
if !inKey {
|
||||||
|
if splitter := strings.Index(preceding, "__"); splitter > -1 {
|
||||||
|
section += preceding[:splitter]
|
||||||
|
inKey = true
|
||||||
|
key += preceding[splitter+2:]
|
||||||
|
} else {
|
||||||
|
section += preceding
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
key += preceding
|
||||||
|
}
|
||||||
|
toDecode := encoded[unescapeIdx[0]+3 : unescapeIdx[1]-1]
|
||||||
|
decodedBytes := make([]byte, len(toDecode)/2)
|
||||||
|
for i := 0; i < len(toDecode)/2; i++ {
|
||||||
|
// Can ignore error here as we know these should be hexadecimal from the regexp
|
||||||
|
byteInt, _ := strconv.ParseInt(toDecode[2*i:2*i+2], 16, 0)
|
||||||
|
decodedBytes[i] = byte(byteInt)
|
||||||
|
}
|
||||||
|
if inKey {
|
||||||
|
key += string(decodedBytes)
|
||||||
|
} else {
|
||||||
|
section += string(decodedBytes)
|
||||||
|
}
|
||||||
|
last = unescapeIdx[1]
|
||||||
|
}
|
||||||
|
remaining := encoded[last:]
|
||||||
|
if !inKey {
|
||||||
|
if splitter := strings.Index(remaining, "__"); splitter > -1 {
|
||||||
|
section += remaining[:splitter]
|
||||||
|
key += remaining[splitter+2:]
|
||||||
|
} else {
|
||||||
|
section += remaining
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
key += remaining
|
||||||
|
}
|
||||||
|
section = strings.ToLower(section)
|
||||||
|
return section, key
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
//nolint:forbidigo
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
dashboardTimezone: 'default',
|
dashboardTimezone: 'default',
|
||||||
dashboardRefresh: '1m',
|
dashboardRefresh: '1m',
|
||||||
|
|
||||||
// please see https://docs.gitea.com/administration/config-cheat-sheet#metrics-metrics
|
// please see https://docs.gitea.io/en-us/config-cheat-sheet/#metrics-metrics
|
||||||
// Show issue by repository metrics with format gitea_issues_by_repository{repository="org/repo"} 5.
|
// Show issue by repository metrics with format gitea_issues_by_repository{repository="org/repo"} 5.
|
||||||
// Requires Gitea 1.16.0 with ENABLED_ISSUE_BY_REPOSITORY set to true.
|
// Requires Gitea 1.16.0 with ENABLED_ISSUE_BY_REPOSITORY set to true.
|
||||||
showIssuesByRepository: true,
|
showIssuesByRepository: true,
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
### BEGIN INIT INFO
|
|
||||||
# Provides: gitea
|
|
||||||
# Required-Start: $syslog $network
|
|
||||||
# Required-Stop: $syslog
|
|
||||||
# Default-Start: 2 3 4 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Short-Description: A self-hosted Git service written in Go.
|
|
||||||
# Description: A self-hosted Git service written in Go.
|
|
||||||
### END INIT INFO
|
|
||||||
|
|
||||||
# Do NOT "set -e"
|
|
||||||
|
|
||||||
# PATH should only include /usr/* if it runs after the mountnfs.sh script
|
|
||||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
|
|
||||||
DESC="Gitea - Git with a cup of tea"
|
|
||||||
NAME=gitea
|
|
||||||
SERVICEVERBOSE=yes
|
|
||||||
PIDFILE=/run/$NAME.pid
|
|
||||||
SCRIPTNAME=/etc/init.d/$NAME
|
|
||||||
WORKINGDIR=/var/lib/$NAME
|
|
||||||
DAEMON=/usr/local/bin/$NAME
|
|
||||||
DAEMON_ARGS="web -c /etc/$NAME/app.ini"
|
|
||||||
USER=git
|
|
||||||
STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/1/KILL/5}"
|
|
||||||
|
|
||||||
# Read configuration variable file if it is present
|
|
||||||
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
|
|
||||||
|
|
||||||
# Exit if the package is not installed
|
|
||||||
[ -x "$DAEMON" ] || exit 0
|
|
||||||
|
|
||||||
do_start()
|
|
||||||
{
|
|
||||||
GITEA_ENVS="USER=$USER GITEA_WORK_DIR=$WORKINGDIR HOME=/home/$USER"
|
|
||||||
GITEA_EXEC="$DAEMON -- $DAEMON_ARGS"
|
|
||||||
sh -c "start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \\
|
|
||||||
--background --chdir $WORKINGDIR --chuid $USER \\
|
|
||||||
--exec /bin/bash -- -c '/usr/bin/env $GITEA_ENVS $GITEA_EXEC'"
|
|
||||||
}
|
|
||||||
|
|
||||||
do_stop()
|
|
||||||
{
|
|
||||||
start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PIDFILE --name $NAME --oknodo
|
|
||||||
rm -f $PIDFILE
|
|
||||||
}
|
|
||||||
|
|
||||||
do_status()
|
|
||||||
{
|
|
||||||
if [ -f $PIDFILE ]; then
|
|
||||||
if kill -0 $(cat "$PIDFILE"); then
|
|
||||||
echo "$NAME is running, PID is $(cat $PIDFILE)"
|
|
||||||
else
|
|
||||||
echo "$NAME process is dead, but pidfile exists"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "$NAME is not running"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
echo "Starting $DESC" "$NAME"
|
|
||||||
do_start
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
echo "Stopping $DESC" "$NAME"
|
|
||||||
do_stop
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
do_status
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
echo "Restarting $DESC" "$NAME"
|
|
||||||
do_stop
|
|
||||||
do_start
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
|
|
||||||
exit 2
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
<h3>With your Consent</h3>
|
<h3>With your Consent</h3>
|
||||||
|
|
||||||
<p>We share your User Personal Information, if you consent, after letting you know what information will be shared, with whom, and why. For example, if you allow third party applications to access your Account using <a href="https://docs.gitea.com/development/oauth2-provider">OAuth2 providers</a>, we share all information associated with your Account, including private repos and organizations. You may also direct us through your action on Your Gitea Instance to share your User Personal Information, such as when joining an Organization.</p>
|
<p>We share your User Personal Information, if you consent, after letting you know what information will be shared, with whom, and why. For example, if you allow third party applications to access your Account using <a href="https://docs.gitea.io/en-us/oauth2-provider/">OAuth2 providers</a>, we share all information associated with your Account, including private repos and organizations. You may also direct us through your action on Your Gitea Instance to share your User Personal Information, such as when joining an Organization.</p>
|
||||||
|
|
||||||
<h3>With Service Providers</h3>
|
<h3>With Service Providers</h3>
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
|
|
||||||
<h3>Data Portability</h3>
|
<h3>Data Portability</h3>
|
||||||
|
|
||||||
<p>As a Your Gitea Instance User, you can always take your data with you. You can clone your repositories to your computer, or you can <a href="https://docs.gitea.com/development/migrations-interfaces">perform migrations using the provided interfaces</a>, for example.</p>
|
<p>As a Your Gitea Instance User, you can always take your data with you. You can clone your repositories to your computer, or you can <a href="https://docs.gitea.io/en-us/migrations-interfaces/">perform migrations using the provided interfaces</a>, for example.</p>
|
||||||
|
|
||||||
<h3>Data Retention and Deletion of Data</h3>
|
<h3>Data Retention and Deletion of Data</h3>
|
||||||
|
|
||||||
|
|||||||
2
contrib/mysql.sql
Normal file
2
contrib/mysql.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DROP DATABASE IF EXISTS gitea;
|
||||||
|
CREATE DATABASE IF NOT EXISTS gitea CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||||
267
contrib/pr/checkout.go
Normal file
267
contrib/pr/checkout.go
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
Checkout a PR and load the tests data into sqlite database
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
gitea_git "code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
|
"code.gitea.io/gitea/modules/markup"
|
||||||
|
"code.gitea.io/gitea/modules/markup/external"
|
||||||
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
"code.gitea.io/gitea/routers"
|
||||||
|
markup_service "code.gitea.io/gitea/services/markup"
|
||||||
|
|
||||||
|
"github.com/go-git/go-git/v5"
|
||||||
|
"github.com/go-git/go-git/v5/config"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var codeFilePath = "contrib/pr/checkout.go"
|
||||||
|
|
||||||
|
func runPR() {
|
||||||
|
log.Printf("[PR] Starting gitea ...\n")
|
||||||
|
curDir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
setting.SetCustomPathAndConf("", "", "")
|
||||||
|
setting.InitProviderAllowEmpty()
|
||||||
|
setting.LoadCommonSettings()
|
||||||
|
|
||||||
|
setting.RepoRootPath, err = os.MkdirTemp(os.TempDir(), "repos")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("TempDir: %v\n", err)
|
||||||
|
}
|
||||||
|
setting.AppDataPath, err = os.MkdirTemp(os.TempDir(), "appdata")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("TempDir: %v\n", err)
|
||||||
|
}
|
||||||
|
setting.AppWorkPath = curDir
|
||||||
|
setting.StaticRootPath = curDir
|
||||||
|
setting.GravatarSource = "https://secure.gravatar.com/avatar/"
|
||||||
|
setting.AppURL = "http://localhost:8080/"
|
||||||
|
setting.HTTPPort = "8080"
|
||||||
|
setting.SSH.Domain = "localhost"
|
||||||
|
setting.SSH.Port = 3000
|
||||||
|
setting.InstallLock = true
|
||||||
|
setting.SecretKey = "9pCviYTWSb"
|
||||||
|
setting.InternalToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8"
|
||||||
|
curUser, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
setting.RunUser = curUser.Username
|
||||||
|
|
||||||
|
log.Printf("[PR] Loading fixtures data ...\n")
|
||||||
|
//models.LoadConfigs()
|
||||||
|
/*
|
||||||
|
setting.Database.Type = "sqlite3"
|
||||||
|
setting.Database.Path = ":memory:"
|
||||||
|
setting.Database.Timeout = 500
|
||||||
|
*/
|
||||||
|
dbCfg := setting.CfgProvider.Section("database")
|
||||||
|
dbCfg.NewKey("DB_TYPE", "sqlite3")
|
||||||
|
dbCfg.NewKey("PATH", ":memory:")
|
||||||
|
|
||||||
|
routers.InitGitServices()
|
||||||
|
setting.Database.LogSQL = true
|
||||||
|
// x, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared")
|
||||||
|
|
||||||
|
db.InitEngineWithMigration(context.Background(), func(_ *xorm.Engine) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
db.HasEngine = true
|
||||||
|
// x.ShowSQL(true)
|
||||||
|
err = unittest.InitFixtures(
|
||||||
|
unittest.FixturesOptions{
|
||||||
|
Dir: path.Join(curDir, "models/fixtures/"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error initializing test database: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
unittest.LoadFixtures()
|
||||||
|
util.RemoveAll(setting.RepoRootPath)
|
||||||
|
util.RemoveAll(repo_module.LocalCopyPath())
|
||||||
|
unittest.CopyDir(path.Join(curDir, "tests/gitea-repositories-meta"), setting.RepoRootPath)
|
||||||
|
|
||||||
|
log.Printf("[PR] Setting up router\n")
|
||||||
|
// routers.GlobalInit()
|
||||||
|
external.RegisterRenderers()
|
||||||
|
markup.Init(markup_service.ProcessorHelper())
|
||||||
|
c := routers.NormalRoutes(graceful.GetManager().HammerContext())
|
||||||
|
|
||||||
|
log.Printf("[PR] Ready for testing !\n")
|
||||||
|
log.Printf("[PR] Login with user1, user2, user3, ... with pass: password\n")
|
||||||
|
/*
|
||||||
|
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL)
|
||||||
|
|
||||||
|
if setting.LFS.StartServer {
|
||||||
|
log.Info("LFS server enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if setting.EnablePprof {
|
||||||
|
go func() {
|
||||||
|
log.Info("Starting pprof server on localhost:6060")
|
||||||
|
log.Info("%v", http.ListenAndServe("localhost:6060", nil))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
http.ListenAndServe(":8080", c)
|
||||||
|
|
||||||
|
log.Printf("[PR] Cleaning up ...\n")
|
||||||
|
/*
|
||||||
|
if err = util.RemoveAll(setting.Indexer.IssuePath); err != nil {
|
||||||
|
fmt.Printf("util.RemoveAll: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if err = util.RemoveAll(setting.Indexer.RepoPath); err != nil {
|
||||||
|
fmt.Printf("Unable to remove repo indexer: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if err = util.RemoveAll(setting.RepoRootPath); err != nil {
|
||||||
|
log.Fatalf("util.RemoveAll: %v\n", err)
|
||||||
|
}
|
||||||
|
if err = util.RemoveAll(setting.AppDataPath); err != nil {
|
||||||
|
log.Fatalf("util.RemoveAll: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
runPRFlag := flag.Bool("run", false, "Run the PR code")
|
||||||
|
flag.Parse()
|
||||||
|
if *runPRFlag {
|
||||||
|
runPR()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// To force checkout (e.g. Windows complains about unclean work tree) set env variable FORCE=true
|
||||||
|
force, err := strconv.ParseBool(os.Getenv("FORCE"))
|
||||||
|
if err != nil {
|
||||||
|
force = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise checkout PR
|
||||||
|
if len(os.Args) != 2 {
|
||||||
|
log.Fatal("Need only one arg: the PR number")
|
||||||
|
}
|
||||||
|
pr := os.Args[1]
|
||||||
|
|
||||||
|
codeFilePath = filepath.FromSlash(codeFilePath) // Convert to running OS
|
||||||
|
|
||||||
|
// Copy this file if it will not exist in the PR branch
|
||||||
|
dat, err := os.ReadFile(codeFilePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to cache this code file : %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repo, err := git.PlainOpen(".")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to open the repo : %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find remote upstream
|
||||||
|
remotes, err := repo.Remotes()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to list remotes of repo : %v", err)
|
||||||
|
}
|
||||||
|
remoteUpstream := "origin" // Default
|
||||||
|
for _, r := range remotes {
|
||||||
|
if r.Config().URLs[0] == "https://github.com/go-gitea/gitea.git" ||
|
||||||
|
r.Config().URLs[0] == "https://github.com/go-gitea/gitea" ||
|
||||||
|
r.Config().URLs[0] == "git@github.com:go-gitea/gitea.git" { // fetch at index 0
|
||||||
|
remoteUpstream = r.Config().Name
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
branch := fmt.Sprintf("pr-%s-%d", pr, time.Now().Unix())
|
||||||
|
branchRef := plumbing.NewBranchReferenceName(branch)
|
||||||
|
|
||||||
|
log.Printf("Fetching PR #%s in %s\n", pr, branch)
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// Use git cli command for windows
|
||||||
|
runCmd("git", "fetch", remoteUpstream, fmt.Sprintf("pull/%s/head:%s", pr, branch))
|
||||||
|
} else {
|
||||||
|
ref := fmt.Sprintf("%s%s/head:%s", gitea_git.PullPrefix, pr, branchRef)
|
||||||
|
err = repo.Fetch(&git.FetchOptions{
|
||||||
|
RemoteName: remoteUpstream,
|
||||||
|
RefSpecs: []config.RefSpec{
|
||||||
|
config.RefSpec(ref),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to fetch %s from %s : %v", ref, remoteUpstream, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tree, err := repo.Worktree()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to parse git tree : %v", err)
|
||||||
|
}
|
||||||
|
log.Printf("Checkout PR #%s in %s\n", pr, branch)
|
||||||
|
err = tree.Checkout(&git.CheckoutOptions{
|
||||||
|
Branch: branchRef,
|
||||||
|
Force: force,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to checkout %s : %v", branch, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy this file if not exist
|
||||||
|
if _, err := os.Stat(codeFilePath); os.IsNotExist(err) {
|
||||||
|
err = os.MkdirAll(filepath.Dir(codeFilePath), 0o755)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to duplicate this code file in PR : %v", err)
|
||||||
|
}
|
||||||
|
err = os.WriteFile(codeFilePath, dat, 0o644)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to duplicate this code file in PR : %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Force build of js, css, bin, ...
|
||||||
|
runCmd("make", "build")
|
||||||
|
// Start with integration test
|
||||||
|
runCmd("go", "run", "-mod", "vendor", "-tags", "sqlite sqlite_unlock_notify", codeFilePath, "-run")
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCmd(cmd ...string) {
|
||||||
|
log.Printf("Executing : %s ...\n", cmd)
|
||||||
|
c := exec.Command(cmd[0], cmd[1:]...)
|
||||||
|
c.Stdout = os.Stdout
|
||||||
|
c.Stderr = os.Stderr
|
||||||
|
if err := c.Start(); err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
if err := c.Wait(); err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,7 +52,7 @@ After=network.target
|
|||||||
# Uncomment the next line if you have repos with lots of files and get a HTTP 500 error because of that
|
# Uncomment the next line if you have repos with lots of files and get a HTTP 500 error because of that
|
||||||
# LimitNOFILE=524288:524288
|
# LimitNOFILE=524288:524288
|
||||||
RestartSec=2s
|
RestartSec=2s
|
||||||
Type=notify
|
Type=simple
|
||||||
User=git
|
User=git
|
||||||
Group=git
|
Group=git
|
||||||
WorkingDirectory=/var/lib/gitea/
|
WorkingDirectory=/var/lib/gitea/
|
||||||
@@ -62,7 +62,6 @@ WorkingDirectory=/var/lib/gitea/
|
|||||||
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
|
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
|
||||||
Restart=always
|
Restart=always
|
||||||
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
|
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
|
||||||
WatchdogSec=30s
|
|
||||||
# If you install Git to directory prefix other than default PATH (which happens
|
# If you install Git to directory prefix other than default PATH (which happens
|
||||||
# for example if you install other versions of Git side-to-side with
|
# for example if you install other versions of Git side-to-side with
|
||||||
# distribution version), uncomment below line and add that prefix to PATH
|
# distribution version), uncomment below line and add that prefix to PATH
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# This is an update script for gitea installed via the binary distribution
|
# This is an update script for gitea installed via the binary distribution
|
||||||
# from dl.gitea.com on linux as systemd service. It performs a backup and updates
|
# from dl.gitea.io on linux as systemd service. It performs a backup and updates
|
||||||
# Gitea in place.
|
# Gitea in place.
|
||||||
# NOTE: This adds the GPG Signing Key of the Gitea maintainers to the keyring.
|
# NOTE: This adds the GPG Signing Key of the Gitea maintainers to the keyring.
|
||||||
# Depends on: bash, curl, xz, sha256sum. optionally jq, gpg
|
# Depends on: bash, curl, xz, sha256sum. optionally jq, gpg
|
||||||
@@ -10,15 +10,6 @@
|
|||||||
# upgrade.sh 1.15.10
|
# upgrade.sh 1.15.10
|
||||||
# giteahome=/opt/gitea giteaconf=$giteahome/app.ini upgrade.sh
|
# giteahome=/opt/gitea giteaconf=$giteahome/app.ini upgrade.sh
|
||||||
|
|
||||||
# Check if gitea service is running
|
|
||||||
if ! pidof gitea &> /dev/null; then
|
|
||||||
echo "Error: gitea is not running."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Continue with rest of the script if gitea is running
|
|
||||||
echo "Gitea is running. Continuing with rest of script..."
|
|
||||||
|
|
||||||
# apply variables from environment
|
# apply variables from environment
|
||||||
: "${giteabin:="/usr/local/bin/gitea"}"
|
: "${giteabin:="/usr/local/bin/gitea"}"
|
||||||
: "${giteahome:="/var/lib/gitea"}"
|
: "${giteahome:="/var/lib/gitea"}"
|
||||||
@@ -78,7 +69,7 @@ require curl xz sha256sum "$sudocmd"
|
|||||||
# select version to install
|
# select version to install
|
||||||
if [[ -z "${giteaversion:-}" ]]; then
|
if [[ -z "${giteaversion:-}" ]]; then
|
||||||
require jq
|
require jq
|
||||||
giteaversion=$(curl --connect-timeout 10 -sL https://dl.gitea.com/gitea/version.json | jq -r .latest.version)
|
giteaversion=$(curl --connect-timeout 10 -sL https://dl.gitea.io/gitea/version.json | jq -r .latest.version)
|
||||||
echo "Latest available version is $giteaversion"
|
echo "Latest available version is $giteaversion"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -100,7 +91,7 @@ cd "$giteahome" # needed for gitea dump later
|
|||||||
|
|
||||||
# download new binary
|
# download new binary
|
||||||
binname="gitea-${giteaversion}-${arch}"
|
binname="gitea-${giteaversion}-${arch}"
|
||||||
binurl="https://dl.gitea.com/gitea/${giteaversion}/${binname}.xz"
|
binurl="https://dl.gitea.io/gitea/${giteaversion}/${binname}.xz"
|
||||||
echo "Downloading $binurl..."
|
echo "Downloading $binurl..."
|
||||||
curl --connect-timeout 10 --silent --show-error --fail --location -O "$binurl{,.sha256,.asc}"
|
curl --connect-timeout 10 --silent --show-error --fail --location -O "$binurl{,.sha256,.asc}"
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
;; Do not copy the whole file as-is, as it contains some invalid sections for illustrative purposes.
|
;; Do not copy the whole file as-is, as it contains some invalid sections for illustrative purposes.
|
||||||
;; If you don't know what a setting is you should not set it.
|
;; If you don't know what a setting is you should not set it.
|
||||||
;;
|
;;
|
||||||
;; see https://docs.gitea.com/administration/config-cheat-sheet for additional documentation.
|
;; see https://docs.gitea.io/en-us/config-cheat-sheet/ for additional documentation.
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -16,23 +16,26 @@
|
|||||||
;;
|
;;
|
||||||
;; - _`AppPath`_: This is the absolute path of the running gitea binary.
|
;; - _`AppPath`_: This is the absolute path of the running gitea binary.
|
||||||
;; - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy:
|
;; - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy:
|
||||||
;; - The "WORK_PATH" option in "app.ini" file
|
|
||||||
;; - The `--work-path` flag passed to the binary
|
;; - The `--work-path` flag passed to the binary
|
||||||
;; - The environment variable `$GITEA_WORK_DIR`
|
;; - The environment variable `$GITEA_WORK_DIR`
|
||||||
;; - A built-in value set at build time (see building from source)
|
;; - A built-in value set at build time (see building from source)
|
||||||
;; - Otherwise it defaults to the directory of the _`AppPath`_
|
;; - Otherwise it defaults to the directory of the _`AppPath`_
|
||||||
;; - If any of the above are relative paths then they are made absolute against the directory of the _`AppPath`_
|
;; - If any of the above are relative paths then they are made absolute against the
|
||||||
;; - _`CustomPath`_: This is the base directory for custom templates and other options. It is determined by using the first set thing in the following hierarchy:
|
;; the directory of the _`AppPath`_
|
||||||
|
;; - _`CustomPath`_: This is the base directory for custom templates and other options.
|
||||||
|
;; It is determined by using the first set thing in the following hierarchy:
|
||||||
;; - The `--custom-path` flag passed to the binary
|
;; - The `--custom-path` flag passed to the binary
|
||||||
;; - The environment variable `$GITEA_CUSTOM`
|
;; - The environment variable `$GITEA_CUSTOM`
|
||||||
;; - A built-in value set at build time (see building from source)
|
;; - A built-in value set at build time (see building from source)
|
||||||
;; - Otherwise it defaults to _`AppWorkPath`_`/custom`
|
;; - Otherwise it defaults to _`AppWorkPath`_`/custom`
|
||||||
;; - If any of the above are relative paths then they are made absolute against the directory of the _`AppWorkPath`_
|
;; - If any of the above are relative paths then they are made absolute against the
|
||||||
|
;; the directory of the _`AppWorkPath`_
|
||||||
;; - _`CustomConf`_: This is the path to the `app.ini` file.
|
;; - _`CustomConf`_: This is the path to the `app.ini` file.
|
||||||
;; - The `--config` flag passed to the binary
|
;; - The `--config` flag passed to the binary
|
||||||
;; - A built-in value set at build time (see building from source)
|
;; - A built-in value set at build time (see building from source)
|
||||||
;; - Otherwise it defaults to _`CustomPath`_`/conf/app.ini`
|
;; - Otherwise it defaults to _`CustomPath`_`/conf/app.ini`
|
||||||
;; - If any of the above are relative paths then they are made absolute against the directory of the _`CustomPath`_
|
;; - If any of the above are relative paths then they are made absolute against the
|
||||||
|
;; the directory of the _`CustomPath`_
|
||||||
;;
|
;;
|
||||||
;; In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_
|
;; In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_
|
||||||
|
|
||||||
@@ -46,12 +49,8 @@ APP_NAME = ; Gitea: Git with a cup of tea
|
|||||||
;; RUN_USER will automatically detect the current user - but you can set it here change it if you run locally
|
;; RUN_USER will automatically detect the current user - but you can set it here change it if you run locally
|
||||||
RUN_USER = ; git
|
RUN_USER = ; git
|
||||||
;;
|
;;
|
||||||
;; Application run mode, affects performance and debugging: "dev" or "prod", default is "prod"
|
;; Application run mode, affects performance and debugging. Either "dev", "prod" or "test", default is "prod"
|
||||||
;; Mode "dev" makes Gitea easier to develop and debug, values other than "dev" are treated as "prod" which is for production use.
|
RUN_MODE = ; prod
|
||||||
;RUN_MODE = prod
|
|
||||||
;;
|
|
||||||
;; The working directory, see the comment of AppWorkPath above
|
|
||||||
;WORK_PATH =
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -187,8 +186,8 @@ RUN_USER = ; git
|
|||||||
;; default is the system temporary directory.
|
;; default is the system temporary directory.
|
||||||
;SSH_KEY_TEST_PATH =
|
;SSH_KEY_TEST_PATH =
|
||||||
;;
|
;;
|
||||||
;; Use `ssh-keygen` to parse public SSH keys. The value is passed to the shell. By default, Gitea does the parsing itself.
|
;; Path to ssh-keygen, default is 'ssh-keygen' which means the shell is responsible for finding out which one to call.
|
||||||
;SSH_KEYGEN_PATH =
|
;SSH_KEYGEN_PATH = ssh-keygen
|
||||||
;;
|
;;
|
||||||
;; Enable SSH Authorized Key Backup when rewriting all keys, default is true
|
;; Enable SSH Authorized Key Backup when rewriting all keys, default is true
|
||||||
;SSH_AUTHORIZED_KEYS_BACKUP = true
|
;SSH_AUTHORIZED_KEYS_BACKUP = true
|
||||||
@@ -231,6 +230,7 @@ RUN_USER = ; git
|
|||||||
;;
|
;;
|
||||||
;; Disable CDN even in "prod" mode
|
;; Disable CDN even in "prod" mode
|
||||||
;OFFLINE_MODE = false
|
;OFFLINE_MODE = false
|
||||||
|
;DISABLE_ROUTER_LOG = false
|
||||||
;;
|
;;
|
||||||
;; TLS Settings: Either ACME or manual
|
;; TLS Settings: Either ACME or manual
|
||||||
;; (Other common TLS configuration are found before)
|
;; (Other common TLS configuration are found before)
|
||||||
@@ -303,7 +303,7 @@ RUN_USER = ; git
|
|||||||
LFS_JWT_SECRET =
|
LFS_JWT_SECRET =
|
||||||
;;
|
;;
|
||||||
;; LFS authentication validity period (in time.Duration), pushes taking longer than this may fail.
|
;; LFS authentication validity period (in time.Duration), pushes taking longer than this may fail.
|
||||||
;LFS_HTTP_AUTH_EXPIRY = 24h
|
;LFS_HTTP_AUTH_EXPIRY = 20m
|
||||||
;;
|
;;
|
||||||
;; Maximum allowed LFS file size in bytes (Set to 0 for no limit).
|
;; Maximum allowed LFS file size in bytes (Set to 0 for no limit).
|
||||||
;LFS_MAX_FILE_SIZE = 0
|
;LFS_MAX_FILE_SIZE = 0
|
||||||
@@ -387,7 +387,7 @@ USER = root
|
|||||||
;ITERATE_BUFFER_SIZE = 50
|
;ITERATE_BUFFER_SIZE = 50
|
||||||
;;
|
;;
|
||||||
;; Show the database generated SQL
|
;; Show the database generated SQL
|
||||||
;LOG_SQL = false
|
LOG_SQL = false ; if unset defaults to true
|
||||||
;;
|
;;
|
||||||
;; Maximum number of DB Connect retries
|
;; Maximum number of DB Connect retries
|
||||||
;DB_RETRIES = 10
|
;DB_RETRIES = 10
|
||||||
@@ -550,67 +550,78 @@ ENABLE = true
|
|||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Main Logger
|
;; Main Logger
|
||||||
;;
|
;;
|
||||||
;; Either "console", "file" or "conn", default is "console"
|
;; Either "console", "file", "conn", "smtp" or "database", default is "console"
|
||||||
;; Use comma to separate multiple modes, e.g. "console, file"
|
;; Use comma to separate multiple modes, e.g. "console, file"
|
||||||
MODE = console
|
MODE = console
|
||||||
;;
|
;;
|
||||||
;; Either "Trace", "Debug", "Info", "Warn", "Error" or "None", default is "Info"
|
;; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical" or "None", default is "Info"
|
||||||
LEVEL = Info
|
LEVEL = Info
|
||||||
;;
|
;;
|
||||||
;; Print Stacktrace with logs (rarely helpful, do not set) Either "Trace", "Debug", "Info", "Warn", "Error", default is "None"
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;STACKTRACE_LEVEL = None
|
;; Router Logger
|
||||||
;;
|
;;
|
||||||
;; Buffer length of the channel, keep it as it is if you don't know what it is.
|
;; Switch off the router log
|
||||||
;BUFFER_LEN = 10000
|
;DISABLE_ROUTER_LOG=false
|
||||||
;;
|
;;
|
||||||
;; Sub logger modes, a single comma means use default MODE above, empty means disable it
|
;; Set the log "modes" for the router log (if file is set the log file will default to router.log)
|
||||||
;logger.access.MODE=
|
ROUTER = console
|
||||||
;logger.router.MODE=,
|
|
||||||
;logger.xorm.MODE=,
|
|
||||||
;;
|
;;
|
||||||
;; Collect SSH logs (Creates log from ssh git request)
|
;; The router will log different things at different levels.
|
||||||
;;
|
;;
|
||||||
;ENABLE_SSH_LOG = false
|
;; * started messages will be logged at TRACE level
|
||||||
|
;; * polling/completed routers will be logged at INFO
|
||||||
|
;; * slow routers will be logged at WARN
|
||||||
|
;; * failed routers will be logged at WARN
|
||||||
;;
|
;;
|
||||||
|
;; The routing level will default to that of the system but individual router level can be set in
|
||||||
|
;; [log.<mode>.router] LEVEL
|
||||||
|
;;
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
;; Access Logger (Creates log in NCSA common log format)
|
;; Access Logger (Creates log in NCSA common log format)
|
||||||
;;
|
;;
|
||||||
;; Print request id which parsed from request headers in access log, when access log is enabled.
|
;ENABLE_ACCESS_LOG = false
|
||||||
;; * E.g:
|
|
||||||
;; * In request Header: X-Request-ID: test-id-123
|
|
||||||
;; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID
|
|
||||||
;; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "test-id-123"
|
|
||||||
;;
|
;;
|
||||||
;; If you configure more than one in the .ini file, it will match in the order of configuration,
|
;; Set the log "modes" for the access log (if file is set the log file will default to access.log)
|
||||||
;; and the first match will be finally printed in the log.
|
;ACCESS = file
|
||||||
;; * E.g:
|
|
||||||
;; * In request Header: X-Trace-ID: trace-id-1q2w3e4r
|
|
||||||
;; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID, X-Trace-ID, X-Req-ID
|
|
||||||
;; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "trace-id-1q2w3e4r"
|
|
||||||
;;
|
|
||||||
;REQUEST_ID_HEADERS =
|
|
||||||
;;
|
;;
|
||||||
;; Sets the template used to create the access log.
|
;; Sets the template used to create the access log.
|
||||||
;ACCESS_LOG_TEMPLATE = {{.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}}"
|
;ACCESS_LOG_TEMPLATE = {{.Ctx.RemoteAddr}} - {{.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}}"
|
||||||
|
;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
;; Log modes (aka log writers)
|
;; SSH log (Creates log from ssh git request)
|
||||||
;;
|
;;
|
||||||
;[log.%(WriterMode)]
|
;ENABLE_SSH_LOG = false
|
||||||
;MODE=console/file/conn/...
|
;;
|
||||||
|
;; Other Settings
|
||||||
|
;;
|
||||||
|
;; Print Stacktraces with logs. (Rarely helpful.) Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "None"
|
||||||
|
;STACKTRACE_LEVEL = None
|
||||||
|
;;
|
||||||
|
;; Buffer length of the channel, keep it as it is if you don't know what it is.
|
||||||
|
;BUFFER_LEN = 10000
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Creating specific log configuration
|
||||||
|
;;
|
||||||
|
;; You can set specific configuration for individual modes and subloggers
|
||||||
|
;;
|
||||||
|
;; Configuration available to all log modes/subloggers
|
||||||
;LEVEL=
|
;LEVEL=
|
||||||
;FLAGS = stdflags
|
;FLAGS = stdflags
|
||||||
;EXPRESSION =
|
;EXPRESSION =
|
||||||
;PREFIX =
|
;PREFIX =
|
||||||
;COLORIZE = false
|
;COLORIZE = false
|
||||||
;;
|
;;
|
||||||
;[log.console]
|
;; For "console" mode only
|
||||||
;STDERR = false
|
;STDERR = false
|
||||||
;;
|
;;
|
||||||
;[log.file]
|
;; For "file" mode only
|
||||||
;; Set the file_name for the logger. If this is a relative path this will be relative to ROOT_PATH
|
;LEVEL =
|
||||||
|
;; Set the file_name for the logger. If this is a relative path this
|
||||||
|
;; will be relative to ROOT_PATH
|
||||||
;FILE_NAME =
|
;FILE_NAME =
|
||||||
;; This enables automated log rotate(switch of following options), default is true
|
;; This enables automated log rotate(switch of following options), default is true
|
||||||
;LOG_ROTATE = true
|
;LOG_ROTATE = true
|
||||||
@@ -624,8 +635,9 @@ LEVEL = Info
|
|||||||
;COMPRESS = true
|
;COMPRESS = true
|
||||||
;; compression level see godoc for compress/gzip
|
;; compression level see godoc for compress/gzip
|
||||||
;COMPRESSION_LEVEL = -1
|
;COMPRESSION_LEVEL = -1
|
||||||
;;
|
;
|
||||||
;[log.conn]
|
;; For "conn" mode only
|
||||||
|
;LEVEL =
|
||||||
;; Reconnect host for every single message, default is false
|
;; Reconnect host for every single message, default is false
|
||||||
;RECONNECT_ON_MSG = false
|
;RECONNECT_ON_MSG = false
|
||||||
;; Try to reconnect when connection is lost, default is false
|
;; Try to reconnect when connection is lost, default is false
|
||||||
@@ -634,6 +646,19 @@ LEVEL = Info
|
|||||||
;PROTOCOL = tcp
|
;PROTOCOL = tcp
|
||||||
;; Host address
|
;; Host address
|
||||||
;ADDR =
|
;ADDR =
|
||||||
|
;
|
||||||
|
;; For "smtp" mode only
|
||||||
|
;LEVEL =
|
||||||
|
;; Name displayed in mail title, default is "Diagnostic message from server"
|
||||||
|
;SUBJECT = Diagnostic message from server
|
||||||
|
;; Mail server
|
||||||
|
;HOST =
|
||||||
|
;; Mailer user name and password
|
||||||
|
;USER =
|
||||||
|
;; Use PASSWD = `your password` for quoting if you use special characters in the password.
|
||||||
|
;PASSWD =
|
||||||
|
;; Receivers, can be one or more, e.g. 1@example.com,2@example.com
|
||||||
|
;RECEIVERS =
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -683,24 +708,6 @@ LEVEL = Info
|
|||||||
;; Disable the usage of using partial clones for git.
|
;; Disable the usage of using partial clones for git.
|
||||||
;DISABLE_PARTIAL_CLONE = false
|
;DISABLE_PARTIAL_CLONE = false
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Git Operation timeout in seconds
|
|
||||||
;[git.timeout]
|
|
||||||
;DEFAULT = 360
|
|
||||||
;MIGRATE = 600
|
|
||||||
;MIRROR = 300
|
|
||||||
;CLONE = 300
|
|
||||||
;PULL = 300
|
|
||||||
;GC = 60
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Git config options
|
|
||||||
;; This section only does "set" config, a removed config key from this section won't be removed from git config automatically. The format is `some.configKey = value`.
|
|
||||||
;[git.config]
|
|
||||||
;diff.algorithm = histogram
|
|
||||||
;core.logAllRefUpdates = true
|
|
||||||
;gc.reflogExpire = 90
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
[service]
|
[service]
|
||||||
@@ -719,11 +726,11 @@ LEVEL = Info
|
|||||||
;; Whether a new user needs to be confirmed manually after registration. (Requires `REGISTER_EMAIL_CONFIRM` to be disabled.)
|
;; Whether a new user needs to be confirmed manually after registration. (Requires `REGISTER_EMAIL_CONFIRM` to be disabled.)
|
||||||
;REGISTER_MANUAL_CONFIRM = false
|
;REGISTER_MANUAL_CONFIRM = false
|
||||||
;;
|
;;
|
||||||
;; List of domain names that are allowed to be used to register on a Gitea instance, wildcard is supported
|
;; List of domain names that are allowed to be used to register on a Gitea instance
|
||||||
;; eg: gitea.io,example.com,*.mydomain.com
|
;; gitea.io,example.com
|
||||||
;EMAIL_DOMAIN_ALLOWLIST =
|
;EMAIL_DOMAIN_WHITELIST =
|
||||||
;;
|
;;
|
||||||
;; Comma-separated list of domain names that are not allowed to be used to register on a Gitea instance, wildcard is supported
|
;; Comma-separated list of domain names that are not allowed to be used to register on a Gitea instance
|
||||||
;EMAIL_DOMAIN_BLOCKLIST =
|
;EMAIL_DOMAIN_BLOCKLIST =
|
||||||
;;
|
;;
|
||||||
;; Disallow registration, only allow admins to create accounts.
|
;; Disallow registration, only allow admins to create accounts.
|
||||||
@@ -903,6 +910,12 @@ LEVEL = Info
|
|||||||
;; Global limit of repositories per user, applied at creation time. -1 means no limit
|
;; Global limit of repositories per user, applied at creation time. -1 means no limit
|
||||||
;MAX_CREATION_LIMIT = -1
|
;MAX_CREATION_LIMIT = -1
|
||||||
;;
|
;;
|
||||||
|
;; Mirror sync queue length, increase if mirror syncing starts hanging (DEPRECATED: please use [queue.mirror] LENGTH instead)
|
||||||
|
;MIRROR_QUEUE_LENGTH = 1000
|
||||||
|
;;
|
||||||
|
;; Patch test queue length, increase if pull request patch testing starts hanging (DEPRECATED: please use [queue.pr_patch_checker] LENGTH instead)
|
||||||
|
;PULL_REQUEST_QUEUE_LENGTH = 1000
|
||||||
|
;;
|
||||||
;; Preferred Licenses to place at the top of the List
|
;; Preferred Licenses to place at the top of the List
|
||||||
;; The name here must match the filename in options/license or custom/options/license
|
;; The name here must match the filename in options/license or custom/options/license
|
||||||
;PREFERRED_LICENSES = Apache License 2.0,MIT License
|
;PREFERRED_LICENSES = Apache License 2.0,MIT License
|
||||||
@@ -917,14 +930,11 @@ LEVEL = Info
|
|||||||
;; Force ssh:// clone url instead of scp-style uri when default SSH port is used
|
;; Force ssh:// clone url instead of scp-style uri when default SSH port is used
|
||||||
;USE_COMPAT_SSH_URI = false
|
;USE_COMPAT_SSH_URI = false
|
||||||
;;
|
;;
|
||||||
;; Value for the "go get" request returns the repository url as https or ssh, default is https
|
|
||||||
;GO_GET_CLONE_URL_PROTOCOL = https
|
|
||||||
;;
|
|
||||||
;; Close issues as long as a commit on any branch marks it as fixed
|
;; Close issues as long as a commit on any branch marks it as fixed
|
||||||
;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions.
|
;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages
|
||||||
;DISABLED_REPO_UNITS =
|
;DISABLED_REPO_UNITS =
|
||||||
;;
|
;;
|
||||||
;; Comma separated list of default new repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects, repo.packages, repo.actions.
|
;; Comma separated list of default new repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects, repo.packages.
|
||||||
;; Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility.
|
;; Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility.
|
||||||
;; External wiki and issue tracker can't be enabled by default as it requires additional settings.
|
;; External wiki and issue tracker can't be enabled by default as it requires additional settings.
|
||||||
;; Disabled repo units will not be added to new repositories regardless if it is in the default list.
|
;; Disabled repo units will not be added to new repositories regardless if it is in the default list.
|
||||||
@@ -966,7 +976,11 @@ LEVEL = Info
|
|||||||
;;
|
;;
|
||||||
;; List of file extensions for which lines should be wrapped in the Monaco editor
|
;; List of file extensions for which lines should be wrapped in the Monaco editor
|
||||||
;; Separate extensions with a comma. To line wrap files without an extension, just put a comma
|
;; Separate extensions with a comma. To line wrap files without an extension, just put a comma
|
||||||
;LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,.livemd,
|
;LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,
|
||||||
|
;;
|
||||||
|
;; Valid file modes that have a preview API associated with them, such as api/v1/markdown
|
||||||
|
;; Separate the values by commas. The preview tab in edit mode won't be displayed if the file extension doesn't match
|
||||||
|
;PREVIEWABLE_FILE_MODES = markdown
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1044,9 +1058,6 @@ LEVEL = Info
|
|||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; List of reasons why a Pull Request or Issue can be locked
|
;; List of reasons why a Pull Request or Issue can be locked
|
||||||
;LOCK_REASONS = Too heated,Off-topic,Resolved,Spam
|
;LOCK_REASONS = Too heated,Off-topic,Resolved,Spam
|
||||||
;; Maximum number of pinned Issues per repo
|
|
||||||
;; Set to 0 to disable pinning Issues
|
|
||||||
;MAX_PINNED = 3
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1180,6 +1191,11 @@ LEVEL = Info
|
|||||||
;; Number of line of codes shown for a code comment
|
;; Number of line of codes shown for a code comment
|
||||||
;CODE_COMMENT_LINES = 4
|
;CODE_COMMENT_LINES = 4
|
||||||
;;
|
;;
|
||||||
|
;; Value of `theme-color` meta tag, used by Android >= 5.0
|
||||||
|
;; An invalid color like "none" or "disable" will have the default style
|
||||||
|
;; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
|
||||||
|
;THEME_COLOR_META_TAG = `#6cc644`
|
||||||
|
;;
|
||||||
;; Max size of files to be displayed (default is 8MiB)
|
;; Max size of files to be displayed (default is 8MiB)
|
||||||
;MAX_DISPLAY_FILE_SIZE = 8388608
|
;MAX_DISPLAY_FILE_SIZE = 8388608
|
||||||
;;
|
;;
|
||||||
@@ -1208,9 +1224,8 @@ LEVEL = Info
|
|||||||
;; Whether to search within description at repository search on explore page.
|
;; Whether to search within description at repository search on explore page.
|
||||||
;SEARCH_REPO_DESCRIPTION = true
|
;SEARCH_REPO_DESCRIPTION = true
|
||||||
;;
|
;;
|
||||||
;; Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
|
;; Whether to enable a Service Worker to cache frontend assets
|
||||||
;; A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
|
;USE_SERVICE_WORKER = false
|
||||||
;ONLY_SHOW_RELEVANT_REPOS = false
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1300,12 +1315,11 @@ LEVEL = Info
|
|||||||
;; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown
|
;; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown
|
||||||
;; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes)
|
;; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes)
|
||||||
;; URLs starting with http and https are always displayed, whatever is put in this entry.
|
;; URLs starting with http and https are always displayed, whatever is put in this entry.
|
||||||
;; If this entry is empty, all URL schemes are allowed.
|
|
||||||
;CUSTOM_URL_SCHEMES =
|
;CUSTOM_URL_SCHEMES =
|
||||||
;;
|
;;
|
||||||
;; List of file extensions that should be rendered/edited as Markdown
|
;; List of file extensions that should be rendered/edited as Markdown
|
||||||
;; Separate the extensions with a comma. To render files without any extension as markdown, just put a comma
|
;; Separate the extensions with a comma. To render files without any extension as markdown, just put a comma
|
||||||
;FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd,.livemd
|
;FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd
|
||||||
;;
|
;;
|
||||||
;; Enables math inline and block detection
|
;; Enables math inline and block detection
|
||||||
;ENABLE_MATH = true
|
;ENABLE_MATH = true
|
||||||
@@ -1331,13 +1345,13 @@ LEVEL = Info
|
|||||||
;; Issue Indexer settings
|
;; Issue Indexer settings
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
;; Issue indexer type, currently support: bleve, db, elasticsearch or meilisearch default is bleve
|
;; Issue indexer type, currently support: bleve, db or elasticsearch, default is bleve
|
||||||
;ISSUE_INDEXER_TYPE = bleve
|
;ISSUE_INDEXER_TYPE = bleve
|
||||||
;;
|
;;
|
||||||
;; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve
|
;; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve
|
||||||
;ISSUE_INDEXER_PATH = indexers/issues.bleve ; Relative paths will be made absolute against _`AppWorkPath`_.
|
;ISSUE_INDEXER_PATH = indexers/issues.bleve ; Relative paths will be made absolute against _`AppWorkPath`_.
|
||||||
;;
|
;;
|
||||||
;; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch or meilisearch
|
;; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch
|
||||||
;ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
|
;ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
|
||||||
;;
|
;;
|
||||||
;; Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch
|
;; Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch
|
||||||
@@ -1347,6 +1361,22 @@ LEVEL = Info
|
|||||||
;; Set to -1 to disable timeout.
|
;; Set to -1 to disable timeout.
|
||||||
;STARTUP_TIMEOUT = 30s
|
;STARTUP_TIMEOUT = 30s
|
||||||
;;
|
;;
|
||||||
|
;; Issue indexer queue, currently support: channel, levelqueue or redis, default is levelqueue (deprecated - use [queue.issue_indexer])
|
||||||
|
;ISSUE_INDEXER_QUEUE_TYPE = levelqueue; **DEPRECATED** use settings in `[queue.issue_indexer]`.
|
||||||
|
;;
|
||||||
|
;; When ISSUE_INDEXER_QUEUE_TYPE is levelqueue, this will be the path where the queue will be saved.
|
||||||
|
;; This can be overridden by `ISSUE_INDEXER_QUEUE_CONN_STR`.
|
||||||
|
;; default is queues/common
|
||||||
|
;ISSUE_INDEXER_QUEUE_DIR = queues/common; **DEPRECATED** use settings in `[queue.issue_indexer]`. Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
|
||||||
|
;;
|
||||||
|
;; When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string.
|
||||||
|
;; When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this is a directory or additional options of
|
||||||
|
;; the form `leveldb://path/to/db?option=value&....`, and overrides `ISSUE_INDEXER_QUEUE_DIR`.
|
||||||
|
;ISSUE_INDEXER_QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0"; **DEPRECATED** use settings in `[queue.issue_indexer]`.
|
||||||
|
;;
|
||||||
|
;; Batch queue number, default is 20
|
||||||
|
;ISSUE_INDEXER_QUEUE_BATCH_NUMBER = 20; **DEPRECATED** use settings in `[queue.issue_indexer]`.
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Repository Indexer settings
|
;; Repository Indexer settings
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1354,10 +1384,6 @@ LEVEL = Info
|
|||||||
;; repo indexer by default disabled, since it uses a lot of disk space
|
;; repo indexer by default disabled, since it uses a lot of disk space
|
||||||
;REPO_INDEXER_ENABLED = false
|
;REPO_INDEXER_ENABLED = false
|
||||||
;;
|
;;
|
||||||
;; repo indexer units, the items to index, could be `sources`, `forks`, `mirrors`, `templates` or any combination of them separated by a comma.
|
|
||||||
;; If empty then it defaults to `sources` only, as if you'd like to disable fully please see REPO_INDEXER_ENABLED.
|
|
||||||
;REPO_INDEXER_REPO_TYPES = sources,forks,mirrors,templates
|
|
||||||
;;
|
|
||||||
;; Code search engine type, could be `bleve` or `elasticsearch`.
|
;; Code search engine type, could be `bleve` or `elasticsearch`.
|
||||||
;REPO_INDEXER_TYPE = bleve
|
;REPO_INDEXER_TYPE = bleve
|
||||||
;;
|
;;
|
||||||
@@ -1377,6 +1403,8 @@ LEVEL = Info
|
|||||||
;; A comma separated list of glob patterns to exclude from the index; ; default is empty
|
;; A comma separated list of glob patterns to exclude from the index; ; default is empty
|
||||||
;REPO_INDEXER_EXCLUDE =
|
;REPO_INDEXER_EXCLUDE =
|
||||||
;;
|
;;
|
||||||
|
;;
|
||||||
|
;UPDATE_BUFFER_LEN = 20; **DEPRECATED** use settings in `[queue.issue_indexer]`.
|
||||||
;MAX_FILE_SIZE = 1048576
|
;MAX_FILE_SIZE = 1048576
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1398,15 +1426,15 @@ LEVEL = Info
|
|||||||
;DATADIR = queues/ ; Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
|
;DATADIR = queues/ ; Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
|
||||||
;;
|
;;
|
||||||
;; Default queue length before a channel queue will block
|
;; Default queue length before a channel queue will block
|
||||||
;LENGTH = 100
|
;LENGTH = 20
|
||||||
;;
|
;;
|
||||||
;; Batch size to send for batched queues
|
;; Batch size to send for batched queues
|
||||||
;BATCH_LENGTH = 20
|
;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 connection string.
|
||||||
;; When `TYPE` is `persistable-channel`, this provides a directory for the underlying leveldb
|
;; 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`.
|
;; 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"
|
;CONN_STR = "addrs=127.0.0.1:6379 db=0"
|
||||||
;;
|
;;
|
||||||
;; Provides the suffix of the default redis/disk queue name - specific queues can be overridden within in their [queue.name] sections.
|
;; Provides the suffix of the default redis/disk queue name - specific queues can be overridden within in their [queue.name] sections.
|
||||||
;QUEUE_NAME = "_queue"
|
;QUEUE_NAME = "_queue"
|
||||||
@@ -1414,8 +1442,29 @@ LEVEL = Info
|
|||||||
;; Provides the suffix of the default redis/disk unique queue set name - specific queues can be overridden within in their [queue.name] sections.
|
;; Provides the suffix of the default redis/disk unique queue set name - specific queues can be overridden within in their [queue.name] sections.
|
||||||
;SET_NAME = "_unique"
|
;SET_NAME = "_unique"
|
||||||
;;
|
;;
|
||||||
;; Maximum number of worker go-routines for the queue. Default value is "CpuNum/2" clipped to between 1 and 10.
|
;; If the queue cannot be created at startup - level queues may need a timeout at startup - wrap the queue:
|
||||||
;MAX_WORKERS = ; (dynamic)
|
;WRAP_IF_NECESSARY = true
|
||||||
|
;;
|
||||||
|
;; Attempt to create the wrapped queue at max
|
||||||
|
;MAX_ATTEMPTS = 10
|
||||||
|
;;
|
||||||
|
;; Timeout queue creation
|
||||||
|
;TIMEOUT = 15m30s
|
||||||
|
;;
|
||||||
|
;; Create a pool with this many workers
|
||||||
|
;WORKERS = 0
|
||||||
|
;;
|
||||||
|
;; Dynamically scale the worker pool to at this many workers
|
||||||
|
;MAX_WORKERS = 10
|
||||||
|
;;
|
||||||
|
;; Add boost workers when the queue blocks for BLOCK_TIMEOUT
|
||||||
|
;BLOCK_TIMEOUT = 1s
|
||||||
|
;;
|
||||||
|
;; Remove the boost workers after BOOST_TIMEOUT
|
||||||
|
;BOOST_TIMEOUT = 5m
|
||||||
|
;;
|
||||||
|
;; During a boost add BOOST_WORKERS
|
||||||
|
;BOOST_WORKERS = 1
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1675,9 +1724,8 @@ LEVEL = Info
|
|||||||
;; For "memory" only, GC interval in seconds, default is 60
|
;; For "memory" only, GC interval in seconds, default is 60
|
||||||
;INTERVAL = 60
|
;INTERVAL = 60
|
||||||
;;
|
;;
|
||||||
;; For "redis", "redis-cluster" and "memcache", connection host address
|
;; For "redis" and "memcache", connection host address
|
||||||
;; redis: `redis://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`
|
||||||
;; redis-cluster: `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
|
|
||||||
;; memcache: `127.0.0.1:11211`
|
;; memcache: `127.0.0.1:11211`
|
||||||
;; twoqueue: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000`
|
;; twoqueue: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000`
|
||||||
;HOST =
|
;HOST =
|
||||||
@@ -1709,7 +1757,7 @@ 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]
|
;; Default is "memory". "db" will reuse the configuration in [database]
|
||||||
;PROVIDER = memory
|
;PROVIDER = memory
|
||||||
;;
|
;;
|
||||||
@@ -1717,7 +1765,6 @@ LEVEL = Info
|
|||||||
;; memory: doesn't have any config yet
|
;; memory: doesn't have any config yet
|
||||||
;; file: session file path, e.g. `data/sessions`
|
;; file: session file path, e.g. `data/sessions`
|
||||||
;; redis: `redis://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`
|
||||||
;; redis-cluster: `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
|
|
||||||
;; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table`
|
;; 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`_.
|
;PROVIDER_CONFIG = data/sessions ; Relative paths will be made absolute against _`AppWorkPath`_.
|
||||||
;;
|
;;
|
||||||
@@ -1753,19 +1800,16 @@ LEVEL = Info
|
|||||||
;; Max Width and Height of uploaded avatars.
|
;; Max Width and Height of uploaded avatars.
|
||||||
;; This is to limit the amount of RAM used when resizing the image.
|
;; This is to limit the amount of RAM used when resizing the image.
|
||||||
;AVATAR_MAX_WIDTH = 4096
|
;AVATAR_MAX_WIDTH = 4096
|
||||||
;AVATAR_MAX_HEIGHT = 4096
|
;AVATAR_MAX_HEIGHT = 3072
|
||||||
;;
|
;;
|
||||||
;; The multiplication factor for rendered avatar images.
|
;; The multiplication factor for rendered avatar images.
|
||||||
;; Larger values result in finer rendering on HiDPI devices.
|
;; Larger values result in finer rendering on HiDPI devices.
|
||||||
;AVATAR_RENDERED_SIZE_FACTOR = 2
|
;AVATAR_RENDERED_SIZE_FACTOR = 3
|
||||||
;;
|
;;
|
||||||
;; Maximum allowed file size for uploaded avatars.
|
;; Maximum allowed file size for uploaded avatars.
|
||||||
;; This is to limit the amount of RAM used when resizing the image.
|
;; This is to limit the amount of RAM used when resizing the image.
|
||||||
;AVATAR_MAX_FILE_SIZE = 1048576
|
;AVATAR_MAX_FILE_SIZE = 1048576
|
||||||
;;
|
;;
|
||||||
;; If the uploaded file is not larger than this byte size, the image will be used as is, without resizing/converting.
|
|
||||||
;AVATAR_MAX_ORIGIN_SIZE = 262144
|
|
||||||
;;
|
|
||||||
;; Chinese users can choose "duoshuo"
|
;; Chinese users can choose "duoshuo"
|
||||||
;; or a custom avatar source, like: http://cn.gravatar.com/avatar/
|
;; or a custom avatar source, like: http://cn.gravatar.com/avatar/
|
||||||
;GRAVATAR_SOURCE = gravatar
|
;GRAVATAR_SOURCE = gravatar
|
||||||
@@ -1788,7 +1832,7 @@ LEVEL = Info
|
|||||||
;ENABLED = true
|
;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.
|
;; 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 = .csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip
|
||||||
;;
|
;;
|
||||||
;; Max size of each file. Defaults to 4MB
|
;; Max size of each file. Defaults to 4MB
|
||||||
;MAX_SIZE = 4
|
;MAX_SIZE = 4
|
||||||
@@ -1804,9 +1848,8 @@ LEVEL = Info
|
|||||||
;; Currently, only `minio` is supported.
|
;; Currently, only `minio` is supported.
|
||||||
;SERVE_DIRECT = false
|
;SERVE_DIRECT = false
|
||||||
;;
|
;;
|
||||||
;; Path for attachments. Defaults to `attachments`. Only available when STORAGE_TYPE is `local`
|
;; Path for attachments. Defaults to `data/attachments` only available when STORAGE_TYPE is `local`
|
||||||
;; Relative paths will be resolved to `${AppDataPath}/${attachment.PATH}`
|
;PATH = data/attachments
|
||||||
;PATH = attachments
|
|
||||||
;;
|
;;
|
||||||
;; Minio endpoint to connect only available when STORAGE_TYPE is `minio`
|
;; Minio endpoint to connect only available when STORAGE_TYPE is `minio`
|
||||||
;MINIO_ENDPOINT = localhost:9000
|
;MINIO_ENDPOINT = localhost:9000
|
||||||
@@ -1831,9 +1874,6 @@ LEVEL = Info
|
|||||||
;;
|
;;
|
||||||
;; Minio skip SSL verification available when STORAGE_TYPE is `minio`
|
;; Minio skip SSL verification available when STORAGE_TYPE is `minio`
|
||||||
;MINIO_INSECURE_SKIP_VERIFY = false
|
;MINIO_INSECURE_SKIP_VERIFY = false
|
||||||
;;
|
|
||||||
;; Minio checksum algorithm: default (for MinIO or AWS S3) or md5 (for Cloudflare or Backblaze)
|
|
||||||
;MINIO_CHECKSUM_ALGORITHM = default
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1841,6 +1881,11 @@ LEVEL = Info
|
|||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
|
;; Specifies the format for fully outputted dates. Defaults to RFC1123
|
||||||
|
;; Special supported values are ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro and StampNano
|
||||||
|
;; For more information about the format see http://golang.org/pkg/time/#pkg-constants
|
||||||
|
;FORMAT =
|
||||||
|
;;
|
||||||
;; Location the UI time display i.e. Asia/Shanghai
|
;; Location the UI time display i.e. Asia/Shanghai
|
||||||
;; Empty means server's location setting
|
;; Empty means server's location setting
|
||||||
;DEFAULT_UI_LOCATION =
|
;DEFAULT_UI_LOCATION =
|
||||||
@@ -2160,7 +2205,7 @@ LEVEL = Info
|
|||||||
;RUN_AT_START = false
|
;RUN_AT_START = false
|
||||||
;ENABLE_SUCCESS_NOTICE = false
|
;ENABLE_SUCCESS_NOTICE = false
|
||||||
;SCHEDULE = @every 168h
|
;SCHEDULE = @every 168h
|
||||||
;HTTP_ENDPOINT = https://dl.gitea.com/gitea/version.json
|
;HTTP_ENDPOINT = https://dl.gitea.io/gitea/version.json
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -2196,6 +2241,21 @@ LEVEL = Info
|
|||||||
;Check at least this proportion of LFSMetaObjects per repo. (This may cause all stale LFSMetaObjects to be checked.)
|
;Check at least this proportion of LFSMetaObjects per repo. (This may cause all stale LFSMetaObjects to be checked.)
|
||||||
;PROPORTION_TO_CHECK_PER_REPO = 0.6
|
;PROPORTION_TO_CHECK_PER_REPO = 0.6
|
||||||
|
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Git Operation timeout in seconds
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;[git.timeout]
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;DEFAULT = 360
|
||||||
|
;MIGRATE = 600
|
||||||
|
;MIRROR = 300
|
||||||
|
;CLONE = 300
|
||||||
|
;PULL = 300
|
||||||
|
;GC = 60
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;[mirror]
|
;[mirror]
|
||||||
@@ -2250,6 +2310,7 @@ LEVEL = Info
|
|||||||
;[other]
|
;[other]
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;SHOW_FOOTER_BRANDING = false
|
||||||
;; Show version information about Gitea and Go in the footer
|
;; Show version information about Gitea and Go in the footer
|
||||||
;SHOW_FOOTER_VERSION = true
|
;SHOW_FOOTER_VERSION = true
|
||||||
;; Show template execution time in the footer
|
;; Show template execution time in the footer
|
||||||
@@ -2326,7 +2387,7 @@ LEVEL = Info
|
|||||||
;QUEUE_LENGTH = 1000
|
;QUEUE_LENGTH = 1000
|
||||||
;;
|
;;
|
||||||
;; Task queue connection string, available only when `QUEUE_TYPE` is `redis`.
|
;; 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`.
|
;; If there is a password of redis, use `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`.
|
||||||
;QUEUE_CONN_STR = "redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s"
|
;QUEUE_CONN_STR = "redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s"
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -2393,10 +2454,6 @@ LEVEL = Info
|
|||||||
;; Enable/Disable package registry capabilities
|
;; Enable/Disable package registry capabilities
|
||||||
;ENABLED = true
|
;ENABLED = true
|
||||||
;;
|
;;
|
||||||
;STORAGE_TYPE = local
|
|
||||||
;; override the minio base path if storage type is minio
|
|
||||||
;MINIO_BASE_PATH = packages/
|
|
||||||
;;
|
|
||||||
;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload`
|
;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload`
|
||||||
;CHUNKED_UPLOAD_PATH = tmp/package-upload
|
;CHUNKED_UPLOAD_PATH = tmp/package-upload
|
||||||
;;
|
;;
|
||||||
@@ -2404,8 +2461,6 @@ LEVEL = Info
|
|||||||
;LIMIT_TOTAL_OWNER_COUNT = -1
|
;LIMIT_TOTAL_OWNER_COUNT = -1
|
||||||
;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
;LIMIT_TOTAL_OWNER_SIZE = -1
|
;LIMIT_TOTAL_OWNER_SIZE = -1
|
||||||
;; Maximum size of an Alpine upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
|
||||||
;LIMIT_SIZE_ALPINE = -1
|
|
||||||
;; Maximum size of a Cargo upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of a Cargo upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
;LIMIT_SIZE_CARGO = -1
|
;LIMIT_SIZE_CARGO = -1
|
||||||
;; Maximum size of a Chef upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of a Chef upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
@@ -2418,14 +2473,8 @@ LEVEL = Info
|
|||||||
;LIMIT_SIZE_CONDA = -1
|
;LIMIT_SIZE_CONDA = -1
|
||||||
;; Maximum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
;LIMIT_SIZE_CONTAINER = -1
|
;LIMIT_SIZE_CONTAINER = -1
|
||||||
;; Maximum size of a CRAN upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
|
||||||
;LIMIT_SIZE_CRAN = -1
|
|
||||||
;; Maximum size of a Debian upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
|
||||||
;LIMIT_SIZE_DEBIAN = -1
|
|
||||||
;; Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
;LIMIT_SIZE_GENERIC = -1
|
;LIMIT_SIZE_GENERIC = -1
|
||||||
;; Maximum size of a Go upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
|
||||||
;LIMIT_SIZE_GO = -1
|
|
||||||
;; Maximum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
;LIMIT_SIZE_HELM = -1
|
;LIMIT_SIZE_HELM = -1
|
||||||
;; Maximum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
@@ -2438,12 +2487,8 @@ LEVEL = Info
|
|||||||
;LIMIT_SIZE_PUB = -1
|
;LIMIT_SIZE_PUB = -1
|
||||||
;; Maximum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
;LIMIT_SIZE_PYPI = -1
|
;LIMIT_SIZE_PYPI = -1
|
||||||
;; Maximum size of a RPM upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
|
||||||
;LIMIT_SIZE_RPM = -1
|
|
||||||
;; Maximum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
;LIMIT_SIZE_RUBYGEMS = -1
|
;LIMIT_SIZE_RUBYGEMS = -1
|
||||||
;; Maximum size of a Swift upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
|
||||||
;LIMIT_SIZE_SWIFT = -1
|
|
||||||
;; Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
;LIMIT_SIZE_VAGRANT = -1
|
;LIMIT_SIZE_VAGRANT = -1
|
||||||
|
|
||||||
@@ -2457,19 +2502,6 @@ LEVEL = Info
|
|||||||
;; storage type
|
;; storage type
|
||||||
;STORAGE_TYPE = local
|
;STORAGE_TYPE = local
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; repo-archive storage will override storage
|
|
||||||
;;
|
|
||||||
;[repo-archive]
|
|
||||||
;STORAGE_TYPE = local
|
|
||||||
;;
|
|
||||||
;; Where your lfs files reside, default is data/lfs.
|
|
||||||
;PATH = data/repo-archive
|
|
||||||
;;
|
|
||||||
;; override the minio base path if storage type is minio
|
|
||||||
;MINIO_BASE_PATH = repo-archive/
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; settings for repository archives, will override storage setting
|
;; settings for repository archives, will override storage setting
|
||||||
@@ -2489,9 +2521,6 @@ LEVEL = Info
|
|||||||
;;
|
;;
|
||||||
;; Where your lfs files reside, default is data/lfs.
|
;; Where your lfs files reside, default is data/lfs.
|
||||||
;PATH = data/lfs
|
;PATH = data/lfs
|
||||||
;;
|
|
||||||
;; override the minio base path if storage type is minio
|
|
||||||
;MINIO_BASE_PATH = lfs/
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -2541,9 +2570,8 @@ LEVEL = Info
|
|||||||
; [actions]
|
; [actions]
|
||||||
;; Enable/Disable actions capabilities
|
;; Enable/Disable actions capabilities
|
||||||
;ENABLED = false
|
;ENABLED = false
|
||||||
;;
|
;; Default address to get action plugins, e.g. the default value means downloading from "https://gitea.com/actions/checkout" for "uses: actions/checkout@v3"
|
||||||
;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
;DEFAULT_ACTIONS_URL = https://gitea.com
|
||||||
;DEFAULT_ACTIONS_URL = github
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ Dockerfile is found in root of repository.
|
|||||||
|
|
||||||
Docker image can be found on [docker hub](https://hub.docker.com/r/gitea/gitea)
|
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.io/en-us/install-with-docker/)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-rootless
|
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-rootless
|
||||||
{{#if build.tags}}
|
{{#if build.tags}}
|
||||||
{{#unless (contains "-rc" build.tag)}}
|
{{#unless (contains "-rc" build.tag)}}
|
||||||
tags:
|
tags:
|
||||||
@@ -10,12 +10,12 @@ tags:
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
manifests:
|
manifests:
|
||||||
-
|
-
|
||||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-amd64-rootless
|
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-amd64-rootless
|
||||||
platform:
|
platform:
|
||||||
architecture: amd64
|
architecture: amd64
|
||||||
os: linux
|
os: linux
|
||||||
-
|
-
|
||||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-arm64-rootless
|
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-arm64-rootless
|
||||||
platform:
|
platform:
|
||||||
architecture: arm64
|
architecture: arm64
|
||||||
os: linux
|
os: linux
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}
|
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}
|
||||||
{{#if build.tags}}
|
{{#if build.tags}}
|
||||||
{{#unless (contains "-rc" build.tag)}}
|
{{#unless (contains "-rc" build.tag)}}
|
||||||
tags:
|
tags:
|
||||||
@@ -10,12 +10,12 @@ tags:
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
manifests:
|
manifests:
|
||||||
-
|
-
|
||||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-amd64
|
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-amd64
|
||||||
platform:
|
platform:
|
||||||
architecture: amd64
|
architecture: amd64
|
||||||
os: linux
|
os: linux
|
||||||
-
|
-
|
||||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-arm64
|
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-arm64
|
||||||
platform:
|
platform:
|
||||||
architecture: arm64
|
architecture: arm64
|
||||||
os: linux
|
os: linux
|
||||||
|
|||||||
@@ -2,15 +2,7 @@
|
|||||||
|
|
||||||
if [ ! -d /data/git/.ssh ]; then
|
if [ ! -d /data/git/.ssh ]; then
|
||||||
mkdir -p /data/git/.ssh
|
mkdir -p /data/git/.ssh
|
||||||
fi
|
chmod 700 /data/git/.ssh
|
||||||
|
|
||||||
# Set the correct permissions on the .ssh directory and authorized_keys file,
|
|
||||||
# or sshd will refuse to use them and lead to clone/push/pull failures.
|
|
||||||
# It could happen when users have copied their data to a new volume and changed the file permission by accident,
|
|
||||||
# and it would be very hard to troubleshoot unless users know how to check the logs of sshd which is started by s6.
|
|
||||||
chmod 700 /data/git/.ssh
|
|
||||||
if [ -f /data/git/.ssh/authorized_keys ]; then
|
|
||||||
chmod 600 /data/git/.ssh/authorized_keys
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f /data/git/.ssh/environment ]; then
|
if [ ! -f /data/git/.ssh/environment ]; then
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ PATH = /data/gitea/attachments
|
|||||||
[log]
|
[log]
|
||||||
MODE = console
|
MODE = console
|
||||||
LEVEL = info
|
LEVEL = info
|
||||||
|
ROUTER = console
|
||||||
ROOT_PATH = /data/gitea/log
|
ROOT_PATH = /data/gitea/log
|
||||||
|
|
||||||
[security]
|
[security]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#
|
#
|
||||||
# And place the original in /usr/lib/gitea with working files in /data/gitea
|
# And place the original in /usr/lib/gitea with working files in /data/gitea
|
||||||
GITEA="/app/gitea/gitea"
|
GITEA="/app/gitea/gitea"
|
||||||
WORK_DIR="/data/gitea"
|
WORK_DIR="/app/gitea"
|
||||||
CUSTOM_PATH="/data/gitea"
|
CUSTOM_PATH="/data/gitea"
|
||||||
|
|
||||||
# Provide docker defaults
|
# Provide docker defaults
|
||||||
|
|||||||
36
docs/Makefile
Normal file
36
docs/Makefile
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
THEME := themes/gitea
|
||||||
|
PUBLIC := public
|
||||||
|
ARCHIVE := https://dl.gitea.io/theme/master.tar.gz
|
||||||
|
|
||||||
|
HUGO_PACKAGE := github.com/gohugoio/hugo@v0.82.0
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: build
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -rf $(PUBLIC) $(THEME)
|
||||||
|
|
||||||
|
.PHONY: trans-copy
|
||||||
|
trans-copy:
|
||||||
|
bash scripts/trans-copy.sh
|
||||||
|
|
||||||
|
.PHONY: server
|
||||||
|
server: $(THEME)
|
||||||
|
go run $(HUGO_PACKAGE) server
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build: $(THEME)
|
||||||
|
go run $(HUGO_PACKAGE) --cleanDestinationDir
|
||||||
|
|
||||||
|
.PHONY: build-offline
|
||||||
|
build-offline: $(THEME)
|
||||||
|
go run $(HUGO_PACKAGE) --baseURL="/" --cleanDestinationDir
|
||||||
|
|
||||||
|
.PHONY: update
|
||||||
|
update: $(THEME)
|
||||||
|
|
||||||
|
$(THEME): $(THEME)/theme.toml
|
||||||
|
$(THEME)/theme.toml:
|
||||||
|
mkdir -p $$(dirname $@)
|
||||||
|
curl -L -s $(ARCHIVE) | tar xz -C $$(dirname $@)
|
||||||
@@ -3,7 +3,36 @@
|
|||||||
[](https://discord.gg/Gitea)
|
[](https://discord.gg/Gitea)
|
||||||
[](http://microbadger.com/images/gitea/docs "Get your own image badge on microbadger.com")
|
[](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).
|
## Hosting
|
||||||
|
|
||||||
|
These pages are hosted using [netlifycms](https://www.netlifycms.org/) and get
|
||||||
|
automatically updated on every push to the `master` branch.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
These pages use the [Hugo](https://gohugo.io/) static site generator.
|
||||||
|
If you are planning to contribute you'll want to download and install Hugo on
|
||||||
|
your local machine.
|
||||||
|
|
||||||
|
The installation of Hugo is out of the scope of this document, so please take
|
||||||
|
the [official install instructions](https://gohugo.io/overview/installing/) to
|
||||||
|
get Hugo up and running.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
To generate the website and serve it on [localhost:1313](http://localhost:1313)
|
||||||
|
just execute this command and stop it with `Ctrl+C`:
|
||||||
|
|
||||||
|
```
|
||||||
|
make server
|
||||||
|
```
|
||||||
|
|
||||||
|
When you are done with your changes just create a pull request, after merging
|
||||||
|
the pull request the website will be updated automatically.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Fork -> Patch -> Push -> Pull Request
|
||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,27 @@
|
|||||||
[](https://discord.gg/Gitea)
|
[](https://discord.gg/Gitea)
|
||||||
[](http://microbadger.com/images/gitea/docs "Get your own image badge on microbadger.com")
|
[](http://microbadger.com/images/gitea/docs "Get your own image badge on microbadger.com")
|
||||||
|
|
||||||
https://gitea.com/gitea/gitea-docusaurus
|
## 关于托管方式
|
||||||
|
|
||||||
|
本页面托管在我们 Docker 容器内的基础设施上, 它会在每次推送到 `master` 分支的时候自动更新,如果你想自己管理这个页面,你可以从我们的 Docker 镜像 [gitea/docs](https://hub.docker.com/r/gitea/docs/) 中获取它。
|
||||||
|
|
||||||
|
## 安装 Hugo
|
||||||
|
|
||||||
|
本页面使用了 [Hugo](https://github.com/spf13/hugo) 静态页面生成工具,如果您有维护它的意愿,则需要在本地计算机上下载并安装 Hugo。Hugo 的安装教程不在本文档的讲述范围之内,详情请参见 [官方文档](https://gohugo.io/overview/installing/)。
|
||||||
|
|
||||||
|
## 如何部署
|
||||||
|
|
||||||
|
在 [localhost:1313](http://localhost:1313) 处构建和运行网站的命令如下,如果需要停止可以使用组合键 `Ctrl+C`:
|
||||||
|
|
||||||
|
```
|
||||||
|
make server
|
||||||
|
```
|
||||||
|
|
||||||
|
完成更改后,只需创建一个 Pull Request (PR),该 PR 一经合并网站将自动更新。
|
||||||
|
|
||||||
|
## 如何贡献您的代码
|
||||||
|
|
||||||
|
Fork -> Patch -> Push -> Pull Request
|
||||||
|
|
||||||
## 关于我们
|
## 关于我们
|
||||||
|
|
||||||
|
|||||||
174
docs/assets/js/search.js
Normal file
174
docs/assets/js/search.js
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/* global Fuse, Mark */
|
||||||
|
|
||||||
|
function ready(fn) {
|
||||||
|
if (document.readyState !== 'loading') {
|
||||||
|
fn();
|
||||||
|
} else {
|
||||||
|
document.addEventListener('DOMContentLoaded', fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ready(doSearch);
|
||||||
|
|
||||||
|
const summaryInclude = 60;
|
||||||
|
const fuseOptions = {
|
||||||
|
shouldSort: true,
|
||||||
|
includeMatches: true,
|
||||||
|
matchAllTokens: true,
|
||||||
|
threshold: 0, // for parsing diacritics
|
||||||
|
tokenize: true,
|
||||||
|
location: 0,
|
||||||
|
distance: 100,
|
||||||
|
maxPatternLength: 32,
|
||||||
|
minMatchCharLength: 1,
|
||||||
|
keys: [{
|
||||||
|
name: 'title',
|
||||||
|
weight: 0.8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'contents',
|
||||||
|
weight: 0.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tags',
|
||||||
|
weight: 0.3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'categories',
|
||||||
|
weight: 0.3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
function param(name) {
|
||||||
|
return decodeURIComponent((window.location.search.split(`${name}=`)[1] || '').split('&')[0]).replace(/\+/g, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchQuery = param('s');
|
||||||
|
|
||||||
|
function doSearch() {
|
||||||
|
if (searchQuery) {
|
||||||
|
document.getElementById('search-query').value = searchQuery;
|
||||||
|
executeSearch(searchQuery);
|
||||||
|
} else {
|
||||||
|
const para = document.createElement('P');
|
||||||
|
para.textContent = 'Please enter a word or phrase above';
|
||||||
|
document.getElementById('search-results').appendChild(para);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getJSON(url, fn) {
|
||||||
|
const request = new XMLHttpRequest();
|
||||||
|
request.open('GET', url, true);
|
||||||
|
request.addEventListener('load', () => {
|
||||||
|
if (request.status >= 200 && request.status < 400) {
|
||||||
|
const data = JSON.parse(request.responseText);
|
||||||
|
fn(data);
|
||||||
|
} else {
|
||||||
|
console.error(`Target reached on ${url} with error ${request.status}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
request.addEventListener('error', () => {
|
||||||
|
console.error(`Connection error ${request.status}`);
|
||||||
|
});
|
||||||
|
request.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeSearch(searchQuery) {
|
||||||
|
getJSON(`/${document.LANG}/index.json`, (data) => {
|
||||||
|
const pages = data;
|
||||||
|
const fuse = new Fuse(pages, fuseOptions);
|
||||||
|
const result = fuse.search(searchQuery);
|
||||||
|
document.getElementById('search-results').innerHTML = '';
|
||||||
|
if (result.length > 0) {
|
||||||
|
populateResults(result);
|
||||||
|
} else {
|
||||||
|
const para = document.createElement('P');
|
||||||
|
para.textContent = 'No matches found';
|
||||||
|
document.getElementById('search-results').appendChild(para);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateResults(result) {
|
||||||
|
for (const [key, value] of result.entries()) {
|
||||||
|
const content = value.item.contents;
|
||||||
|
let snippet = '';
|
||||||
|
const snippetHighlights = [];
|
||||||
|
if (fuseOptions.tokenize) {
|
||||||
|
snippetHighlights.push(searchQuery);
|
||||||
|
for (const mvalue of value.matches) {
|
||||||
|
if (mvalue.key === 'tags' || mvalue.key === 'categories') {
|
||||||
|
snippetHighlights.push(mvalue.value);
|
||||||
|
} else if (mvalue.key === 'contents') {
|
||||||
|
const ind = content.toLowerCase().indexOf(searchQuery.toLowerCase());
|
||||||
|
const start = ind - summaryInclude > 0 ? ind - summaryInclude : 0;
|
||||||
|
const end = ind + searchQuery.length + summaryInclude < content.length ? ind + searchQuery.length + summaryInclude : content.length;
|
||||||
|
snippet += content.substring(start, end);
|
||||||
|
if (ind > -1) {
|
||||||
|
snippetHighlights.push(content.substring(ind, ind + searchQuery.length));
|
||||||
|
} else {
|
||||||
|
snippetHighlights.push(mvalue.value.substring(mvalue.indices[0][0], mvalue.indices[0][1] - mvalue.indices[0][0] + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snippet.length < 1) {
|
||||||
|
snippet += content.substring(0, summaryInclude * 2);
|
||||||
|
}
|
||||||
|
// pull template from hugo template definition
|
||||||
|
const templateDefinition = document.getElementById('search-result-template').innerHTML;
|
||||||
|
// replace values
|
||||||
|
const output = render(templateDefinition, {
|
||||||
|
key,
|
||||||
|
title: value.item.title,
|
||||||
|
link: value.item.permalink,
|
||||||
|
tags: value.item.tags,
|
||||||
|
categories: value.item.categories,
|
||||||
|
snippet
|
||||||
|
});
|
||||||
|
document.getElementById('search-results').appendChild(htmlToElement(output));
|
||||||
|
|
||||||
|
for (const snipvalue of snippetHighlights) {
|
||||||
|
new Mark(document.getElementById(`summary-${key}`)).mark(snipvalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function render(templateString, data) {
|
||||||
|
let conditionalMatches, copy;
|
||||||
|
const conditionalPattern = /\$\{\s*isset ([a-zA-Z]*) \s*\}(.*)\$\{\s*end\s*}/g;
|
||||||
|
// since loop below depends on re.lastInxdex, we use a copy to capture any manipulations whilst inside the loop
|
||||||
|
copy = templateString;
|
||||||
|
while ((conditionalMatches = conditionalPattern.exec(templateString)) !== null) {
|
||||||
|
if (data[conditionalMatches[1]]) {
|
||||||
|
// valid key, remove conditionals, leave content.
|
||||||
|
copy = copy.replace(conditionalMatches[0], conditionalMatches[2]);
|
||||||
|
} else {
|
||||||
|
// not valid, remove entire section
|
||||||
|
copy = copy.replace(conditionalMatches[0], '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templateString = copy;
|
||||||
|
// now any conditionals removed we can do simple substitution
|
||||||
|
let key, find, re;
|
||||||
|
for (key of Object.keys(data)) {
|
||||||
|
find = `\\$\\{\\s*${key}\\s*\\}`;
|
||||||
|
re = new RegExp(find, 'g');
|
||||||
|
templateString = templateString.replace(re, data[key]);
|
||||||
|
}
|
||||||
|
return templateString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By Mark Amery: https://stackoverflow.com/a/35385518
|
||||||
|
* @param {String} HTML representing a single element
|
||||||
|
* @return {Element}
|
||||||
|
*/
|
||||||
|
function htmlToElement(html) {
|
||||||
|
const template = document.createElement('template');
|
||||||
|
html = html.trim(); // Never return a text node of whitespace as the result
|
||||||
|
template.innerHTML = html;
|
||||||
|
return template.content.firstChild;
|
||||||
|
}
|
||||||
364
docs/config.yaml
Normal file
364
docs/config.yaml
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
baseurl: https://docs.gitea.io/
|
||||||
|
languageCode: en-us
|
||||||
|
title: Docs
|
||||||
|
theme: gitea
|
||||||
|
|
||||||
|
defaultContentLanguage: en-us
|
||||||
|
defaultContentLanguageInSubdir: true
|
||||||
|
enableMissingTranslationPlaceholders: true
|
||||||
|
enableEmoji: true
|
||||||
|
|
||||||
|
permalinks:
|
||||||
|
post: /:year/:month/:title/
|
||||||
|
doc: /:slug/
|
||||||
|
page: /:slug/
|
||||||
|
default: /:slug/
|
||||||
|
|
||||||
|
params:
|
||||||
|
description: Git with a cup of tea
|
||||||
|
author: The Gitea Authors
|
||||||
|
website: https://docs.gitea.io
|
||||||
|
version: 1.18.5
|
||||||
|
minGoVersion: 1.19
|
||||||
|
goVersion: 1.20
|
||||||
|
minNodeVersion: 16
|
||||||
|
search: nav
|
||||||
|
repo: "https://github.com/go-gitea/gitea"
|
||||||
|
docContentPath: "docs/content"
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
home:
|
||||||
|
- HTML
|
||||||
|
- RSS
|
||||||
|
- JSON
|
||||||
|
|
||||||
|
menu:
|
||||||
|
page:
|
||||||
|
- name: Website
|
||||||
|
url: https://gitea.io/en-us/
|
||||||
|
weight: 10
|
||||||
|
pre: home
|
||||||
|
- name: Docs
|
||||||
|
url: /en-us/
|
||||||
|
weight: 20
|
||||||
|
pre: question
|
||||||
|
post: active
|
||||||
|
- name: API
|
||||||
|
url: https://try.gitea.io/api/swagger
|
||||||
|
weight: 45
|
||||||
|
pre: plug
|
||||||
|
- name: Blog
|
||||||
|
url: https://blog.gitea.io/
|
||||||
|
weight: 30
|
||||||
|
pre: rss
|
||||||
|
- name: Shop
|
||||||
|
url: https://shop.gitea.io/
|
||||||
|
weight: 40
|
||||||
|
pre: shopping-cart
|
||||||
|
- name: Translation
|
||||||
|
url: https://crowdin.com/project/gitea
|
||||||
|
weight: 41
|
||||||
|
pre: language
|
||||||
|
- name: Downloads
|
||||||
|
url: https://dl.gitea.io/
|
||||||
|
weight: 50
|
||||||
|
pre: download
|
||||||
|
- name: GitHub
|
||||||
|
url: https://github.com/go-gitea/
|
||||||
|
weight: 60
|
||||||
|
pre: github
|
||||||
|
- name: Discord Chat
|
||||||
|
url: https://discord.gg/Gitea
|
||||||
|
weight: 70
|
||||||
|
pre: comment
|
||||||
|
- name: Forum
|
||||||
|
url: https://discourse.gitea.io/
|
||||||
|
weight: 80
|
||||||
|
pre: group
|
||||||
|
|
||||||
|
languages:
|
||||||
|
en-us:
|
||||||
|
weight: 0
|
||||||
|
languageName: English
|
||||||
|
|
||||||
|
zh-cn:
|
||||||
|
weight: 1
|
||||||
|
languageName: 中文(简体)
|
||||||
|
menu:
|
||||||
|
page:
|
||||||
|
- name: 网站
|
||||||
|
url: https://gitea.io/zh-cn/
|
||||||
|
weight: 10
|
||||||
|
pre: home
|
||||||
|
- name: 文档
|
||||||
|
url: /zh-cn/
|
||||||
|
weight: 20
|
||||||
|
pre: question
|
||||||
|
post: active
|
||||||
|
- name: API
|
||||||
|
url: https://try.gitea.io/api/swagger
|
||||||
|
weight: 45
|
||||||
|
pre: plug
|
||||||
|
- name: 博客
|
||||||
|
url: https://blog.gitea.io/
|
||||||
|
weight: 30
|
||||||
|
pre: rss
|
||||||
|
- name: 导入
|
||||||
|
url: https://code.gitea.io/
|
||||||
|
weight: 40
|
||||||
|
pre: code
|
||||||
|
- name: 翻译
|
||||||
|
url: https://crowdin.com/project/gitea
|
||||||
|
weight: 41
|
||||||
|
pre: language
|
||||||
|
- name: 下载
|
||||||
|
url: https://dl.gitea.io/
|
||||||
|
weight: 50
|
||||||
|
pre: download
|
||||||
|
- name: GitHub
|
||||||
|
url: https://github.com/go-gitea/
|
||||||
|
weight: 60
|
||||||
|
pre: github
|
||||||
|
- name: Discord Chat
|
||||||
|
url: https://discord.gg/Gitea
|
||||||
|
weight: 70
|
||||||
|
pre: comment
|
||||||
|
- name: Forum
|
||||||
|
url: https://discourse.gitea.io/
|
||||||
|
weight: 80
|
||||||
|
pre: group
|
||||||
|
|
||||||
|
zh-tw:
|
||||||
|
weight: 2
|
||||||
|
languageName: 中文(繁體)
|
||||||
|
menu:
|
||||||
|
page:
|
||||||
|
- name: 網站
|
||||||
|
url: https://gitea.io/zh-tw/
|
||||||
|
weight: 10
|
||||||
|
pre: home
|
||||||
|
- name: 文件
|
||||||
|
url: /zh-tw/
|
||||||
|
weight: 20
|
||||||
|
pre: question
|
||||||
|
post: active
|
||||||
|
- name: API
|
||||||
|
url: https://try.gitea.io/api/swagger
|
||||||
|
weight: 45
|
||||||
|
pre: plug
|
||||||
|
- name: 部落格
|
||||||
|
url: https://blog.gitea.io/
|
||||||
|
weight: 30
|
||||||
|
pre: rss
|
||||||
|
- name: 商店
|
||||||
|
url: https://shop.gitea.io/
|
||||||
|
weight: 40
|
||||||
|
pre: shopping-cart
|
||||||
|
- name: 翻譯
|
||||||
|
url: https://crowdin.com/project/gitea
|
||||||
|
weight: 41
|
||||||
|
pre: language
|
||||||
|
- name: 下載
|
||||||
|
url: https://dl.gitea.io/
|
||||||
|
weight: 50
|
||||||
|
pre: download
|
||||||
|
- name: GitHub
|
||||||
|
url: https://github.com/go-gitea/
|
||||||
|
weight: 60
|
||||||
|
pre: github
|
||||||
|
- name: Discord 聊天室
|
||||||
|
url: https://discord.gg/Gitea
|
||||||
|
weight: 70
|
||||||
|
pre: comment
|
||||||
|
- name: 討論區
|
||||||
|
url: https://discourse.gitea.io/
|
||||||
|
weight: 80
|
||||||
|
pre: group
|
||||||
|
|
||||||
|
pt-br:
|
||||||
|
weight: 3
|
||||||
|
languageName: Português Brasileiro
|
||||||
|
menu:
|
||||||
|
page:
|
||||||
|
- name: Página inicial
|
||||||
|
url: https://gitea.io/pt-br/
|
||||||
|
weight: 10
|
||||||
|
pre: home
|
||||||
|
- name: Documentação
|
||||||
|
url: /pt-br/
|
||||||
|
weight: 20
|
||||||
|
pre: question
|
||||||
|
post: active
|
||||||
|
- name: API
|
||||||
|
url: https://try.gitea.io/api/swagger
|
||||||
|
weight: 45
|
||||||
|
pre: plug
|
||||||
|
- name: Blog
|
||||||
|
url: https://blog.gitea.io/
|
||||||
|
weight: 30
|
||||||
|
pre: rss
|
||||||
|
- name: Código-fonte
|
||||||
|
url: https://code.gitea.io/
|
||||||
|
weight: 40
|
||||||
|
pre: code
|
||||||
|
- name: Translation
|
||||||
|
url: https://crowdin.com/project/gitea
|
||||||
|
weight: 41
|
||||||
|
pre: language
|
||||||
|
- name: Downloads
|
||||||
|
url: https://dl.gitea.io/
|
||||||
|
weight: 50
|
||||||
|
pre: download
|
||||||
|
- name: GitHub
|
||||||
|
url: https://github.com/go-gitea/
|
||||||
|
weight: 60
|
||||||
|
pre: github
|
||||||
|
- name: Chat no Discord
|
||||||
|
url: https://discord.gg/Gitea
|
||||||
|
weight: 70
|
||||||
|
pre: comment
|
||||||
|
- name: Forum
|
||||||
|
url: https://discourse.gitea.io/
|
||||||
|
weight: 80
|
||||||
|
pre: group
|
||||||
|
|
||||||
|
nl-nl:
|
||||||
|
weight: 4
|
||||||
|
languageName: Nederlands
|
||||||
|
menu:
|
||||||
|
page:
|
||||||
|
- name: Website
|
||||||
|
url: https://gitea.io/nl-nl/
|
||||||
|
weight: 10
|
||||||
|
pre: home
|
||||||
|
- name: Docs
|
||||||
|
url: /nl-nl/
|
||||||
|
weight: 20
|
||||||
|
pre: question
|
||||||
|
post: active
|
||||||
|
- name: API
|
||||||
|
url: https://try.gitea.io/api/swagger
|
||||||
|
weight: 45
|
||||||
|
pre: plug
|
||||||
|
- name: Blog
|
||||||
|
url: https://blog.gitea.io/
|
||||||
|
weight: 30
|
||||||
|
pre: rss
|
||||||
|
- name: Code
|
||||||
|
url: https://code.gitea.io/
|
||||||
|
weight: 40
|
||||||
|
pre: code
|
||||||
|
- name: Translation
|
||||||
|
url: https://crowdin.com/project/gitea
|
||||||
|
weight: 41
|
||||||
|
pre: language
|
||||||
|
- name: Downloads
|
||||||
|
url: https://dl.gitea.io/
|
||||||
|
weight: 50
|
||||||
|
pre: download
|
||||||
|
- name: GitHub
|
||||||
|
url: https://github.com/go-gitea/
|
||||||
|
weight: 60
|
||||||
|
pre: github
|
||||||
|
- name: Discord Chat
|
||||||
|
url: https://discord.gg/Gitea
|
||||||
|
weight: 70
|
||||||
|
pre: comment
|
||||||
|
- name: Forum
|
||||||
|
url: https://discourse.gitea.io/
|
||||||
|
weight: 80
|
||||||
|
pre: group
|
||||||
|
|
||||||
|
fr-fr:
|
||||||
|
weight: 5
|
||||||
|
languageName: Français
|
||||||
|
menu:
|
||||||
|
page:
|
||||||
|
- name: Site
|
||||||
|
url: https://gitea.io/en-us/
|
||||||
|
weight: 10
|
||||||
|
pre: home
|
||||||
|
post: active
|
||||||
|
- name: Documentation
|
||||||
|
url: /fr-fr/
|
||||||
|
weight: 20
|
||||||
|
pre: question
|
||||||
|
- name: API
|
||||||
|
url: https://try.gitea.io/api/swagger
|
||||||
|
weight: 45
|
||||||
|
pre: plug
|
||||||
|
- name: Blog
|
||||||
|
url: https://blog.gitea.io/
|
||||||
|
weight: 30
|
||||||
|
pre: rss
|
||||||
|
- name: Code
|
||||||
|
url: https://code.gitea.io/
|
||||||
|
weight: 40
|
||||||
|
pre: code
|
||||||
|
- name: Translation
|
||||||
|
url: https://crowdin.com/project/gitea
|
||||||
|
weight: 41
|
||||||
|
pre: language
|
||||||
|
- name: Téléchargement
|
||||||
|
url: https://dl.gitea.io/
|
||||||
|
weight: 50
|
||||||
|
pre: download
|
||||||
|
- name: GitHub
|
||||||
|
url: https://github.com/go-gitea/
|
||||||
|
weight: 60
|
||||||
|
pre: github
|
||||||
|
- name: Discord Chat
|
||||||
|
url: https://discord.gg/Gitea
|
||||||
|
weight: 70
|
||||||
|
pre: comment
|
||||||
|
- name: Forum
|
||||||
|
url: https://discourse.gitea.io/
|
||||||
|
weight: 80
|
||||||
|
pre: group
|
||||||
|
|
||||||
|
de-de:
|
||||||
|
weight: 6
|
||||||
|
languageName: Deutsch
|
||||||
|
menu:
|
||||||
|
page:
|
||||||
|
- name: Webseite
|
||||||
|
url: https://gitea.io/en-us/
|
||||||
|
weight: 10
|
||||||
|
pre: home
|
||||||
|
post: active
|
||||||
|
- name: Dokumentation
|
||||||
|
url: /de-de/
|
||||||
|
weight: 20
|
||||||
|
pre: question
|
||||||
|
- name: API
|
||||||
|
url: https://try.gitea.io/api/swagger
|
||||||
|
weight: 45
|
||||||
|
pre: plug
|
||||||
|
- name: Blog
|
||||||
|
url: https://blog.gitea.io/
|
||||||
|
weight: 30
|
||||||
|
pre: rss
|
||||||
|
- name: Code
|
||||||
|
url: https://code.gitea.io/
|
||||||
|
weight: 40
|
||||||
|
pre: code
|
||||||
|
- name: Übersetzung
|
||||||
|
url: https://crowdin.com/project/gitea
|
||||||
|
weight: 41
|
||||||
|
pre: language
|
||||||
|
- name: Downloads
|
||||||
|
url: https://dl.gitea.io/
|
||||||
|
weight: 50
|
||||||
|
pre: download
|
||||||
|
- name: GitHub
|
||||||
|
url: https://github.com/go-gitea/
|
||||||
|
weight: 60
|
||||||
|
pre: github
|
||||||
|
- name: Discord Chat
|
||||||
|
url: https://discord.gg/Gitea
|
||||||
|
weight: 70
|
||||||
|
pre: comment
|
||||||
|
- name: Forum
|
||||||
|
url: https://discourse.gitea.io/
|
||||||
|
weight: 80
|
||||||
|
pre: group
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
date: "2023-04-27T14:00:00+08:00"
|
|
||||||
title: "Actions"
|
|
||||||
slug: "actions"
|
|
||||||
sidebar_position: 36
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
name: "Usage - Actions"
|
|
||||||
sidebar_position: 31
|
|
||||||
identifier: "actions"
|
|
||||||
---
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
date: "2016-12-01T16:00:00+02:00"
|
|
||||||
title: "Administration"
|
|
||||||
slug: "administration"
|
|
||||||
sidebar_position: 30
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
name: "Administration"
|
|
||||||
sidebar_position: 20
|
|
||||||
collapse: true
|
|
||||||
identifier: "administration"
|
|
||||||
---
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
date: "2016-12-01T16:00:00+02:00"
|
|
||||||
title: "运维"
|
|
||||||
slug: "administration"
|
|
||||||
sidebar_position: 30
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
name: "运维"
|
|
||||||
sidebar_position: 20
|
|
||||||
identifier: "administration"
|
|
||||||
---
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
date: "2016-12-01T16:00:00+02:00"
|
|
||||||
title: "運維"
|
|
||||||
slug: "administration"
|
|
||||||
sidebar_position: 30
|
|
||||||
toc: false
|
|
||||||
draft: false
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
name: "運維"
|
|
||||||
sidebar_position: 20
|
|
||||||
identifier: "administration"
|
|
||||||
---
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
---
|
|
||||||
date: "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/` 目录下。例如,如果要添加隐私政策:
|
|
||||||
|
|
||||||
```
|
|
||||||
wget -O /path/to/custom/public/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 以查看更改。
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user